| Block | |||
| ::= | { (Statement ;)* Expression } | ||
| | | { } | ||
| Statement | |||
| ::= | Expression | ||
| | | Binding | ||
| Binding | |||
| ::= | let Patterns = Expression | ||
| | | fun ValueId FunDef (and ValueId FunDef)* | ||
| Expression | |||
| ::= | if Expression then Expression else Expression | ||
| TryExpression | |||
| ::= | try Expression except MatchCase | ||
| | | try Expression finally Expression | ||
|
{ val s = TextIO.openIn "somefile";
try someFunction (s)
finally TextIO.closeIn s
}
To illustract how try-finally and try-except expressions are
unwound, consider the following example:
try {
try {
try {
try {
try raise BAR finally ConsoleIO.print "1";
ConsoleIO.print "a"
} finally ConsoleIO.print "2";
ConsoleIO.print "b"
} except { BAR => ConsoleIO.print "3" };
ConsoleIO.print "c"
} finally ConsoleIO.print "4";
ConsoleIO.print "d"
} except { _ => ConsoleIO.print "5" }
This will print ``123c4d.''
But if we change the second finally clause to raise the exception BAZ
as follows:
try {
try {
try {
try {
try raise BAR finally ConsoleIO.print "1";
ConsoleIO.print "a"
} finally {ConsoleIO.print "2"; raise BAZ};
ConsoleIO.print "b"
} except { BAR => ConsoleIO.print "3" };
ConsoleIO.print "c"
} finally ConsoleIO.print "4";
ConsoleIO.print "d"
} except { _ => ConsoleIO.print "5" }
then the expression will print ``1245.''
Note that in both examples, the finally clauses always execute.
If we have some form of thread finalization, then the finally clauses should be executed when a thread is finalized. Also when a thread is alerted.
| Expression | |||
| ::= | raise Expression | ||
|
| Expression | |||
| ::= | spawn Expression | ||
| Expression | |||
| ::= | sync Expression | ||
Table 11.1: Moby infix and prefix operators
Infix operators
:= assignment operator (lowest precedence) || conditional or operator && conditional and operator == != equality operators <= < >= > relational operators @ : list operators (right associativity) << >> >>> bitwise shift operators | bitwise or operator & bitwise and operator + - additive operators * / % multiplicative operators ** exponentiation ^ function composition (highest precedence)
| AssignmentExpr | |||
| ::= | ConditionalOrExpr := ConditionalOrExpr | ||
| | | ConditionalOrExpr | ||
| ConditionalOrExpr | |||
| ::= | ConditionalOrExpr || ConditionalAndExpr | ||
| | | ConditionalAndExpr | ||
| ConditionalAndExpr | |||
| ::= | ConditionalAndExpr && EqualityExpr | ||
| | | EqualityExpr | ||
| e1 || e2 | º | if e1 then True else e2 |
| e1 && e2 | º | if e1 then e2 else False |
| EqualityExpr | |||
| ::= | EqualityExpr EqualityOp RelationalExpr | ||
| | | RelationalExpr | ||
| EqualityOp | |||
| ::= | == | != | ||
| Bool | Char | String | Int |
| Long | Integer | Float | Double |
| Extended |
We probably should allow equality of tuples of equality types.
We may want to support equality on monomorphic structured values in the future.
| RelationalExpr | |||
| ::= | RelationalExpr RelationalOp ListExpr | ||
| | | ListExpr | ||
| RelationalOp | |||
| ::= | < | <= | >= | > | ||
| ListExpr | |||
| ::= | ShiftExpr ListOp ListExpr | ||
| | | ShiftExpr | ||
| ListOp | |||
| ::= | @ | :: | ||
| ShiftExpr | |||
| ::= | ShiftExpr ShiftOp BitwiseOrExpr | ||
| | | BitwiseOrExpr | ||
| ShiftOp | |||
| ::= | << | >> | >>> | ||
| BitwiseOrExpr | |||
| ::= | BitwiseOrExpr | BitwiseAndExpr | ||
| | | BitwiseOrExpr \/ BitwiseAndExpr | ||
| | | BitwiseAndExpr | ||
| BitwiseAndExpr | |||
| ::= | BitwiseAndExpr & AdditiveExpr | ||
| | | BitwiseAndExpr /\ AdditiveExpr | ||
| | | AdditiveExpr | ||
| AdditiveExpr | |||
| ::= | AdditiveExpr AdditiveOp MultiplicativeExpr | ||
| | | MultiplicativeExpr | ||
| AdditiveOp | |||
| ::= | + | - | ||
| MultiplicativeExpr | |||
| ::= | MultiplicativeExpr MultiplicativeOp Expr | ||
| | | ExponentialExpr | ||
| MultiplicativeOp | |||
| ::= | * | / | % | ||
| ExponentialExpr | |||
| ::= | ExponentialExpr ** CompositionExpr | ||
| | | CompositionExpr | ||
| CompositionExpr | |||
| ::= | PrefixExpr ^ CompositionExpr | ||
| | | PrefixExpr | ||
|
Another way to think about this is that ^ is overloaded on all combinations of polymorphic functions, where the arities match up correctly.
| PrefixExpr | |||
| ::= | PrefixOp PrefixExpr | ||
| | | ApplicationExpr | ||
| PrefixOp | |||
| ::= | * | & | ! | ~ | - | ||
| ApplicationExpr | |||
| ::= | ApplicationExpr PostfixExpr | ||
| | | PostfixExpr | ||
| PostfixExpr | |||
| ::= | PostfixExpr . Label | ||
| | | PostfixExpr [ Expression ] | ||
| | | AtomicExpr | ||
| AtomicExpr | |||
| ::= | fn FunDef | ||
| | | case Expression of MatchCase | ||
| | | ( (Expression (, Expression)*)opt ) | ||
| | | ( Expression : Type ) | ||
| | | ( Expression is Pattern ) | ||
| | | ( Expression isnot Pattern ) | ||
| | | ChoiceEvent | ||
| | | Block | ||
| | | new Pathopt MakerId | ||
| | | self | ||
| | | super . Label | ||
| | | nack_event | ||
| | | rdy_event | ||
| | | ( Operator ) | ||
| | | Pathopt ValueId | ||
| | | DataConstructor | ||
| | | # DataConstructor | ||
| | | ? DataConstructor | ||
| | | Literal | ||
| (e is p) | º | case e of { p => True, _ => False } |
| (e isnot p) | º | case e of { p => False, _ => True } |
| ChoiceEvent | |||
| ::= | {| WrappedEvent (, WrappedEvent)* |} | ||
| WrappedEvent | |||
| ::= | Expression | ||
| | | Expression \ Pattern => Expression | ||
| | | Expression \ MatchCase | ||