Most things in Opal are entities, whether they be objects or patterns. But in addition to this there are also statements. Statements are the the smallest unit of execution that can exist alone. As noted before statements may appear in objects and patterns as creation code. Statements may also be placed outside of any entity. In this case they are treated as if they were contained in a single object which encloses all top level entities and statements.
Expressions are the smallest units of execution which can't exist independently and of which statements are composed. Large expressions may also be composed of smaller expressions.
There are two fundamental forms of expressions and three ways to compose more complex expressions from others. All expressions yield a result when evaluated. Several expressions involve operators. The precedence among these operators is:
Expression Precedence | ||
---|---|---|
grouping member selection invocation |
( expr ) object . memberobject ( expr-list ) | |
assignment literal conversion |
lvalue = exprliteral : type = expr |
Where operators of higher precedence are before those of lower precedence and operators of equal precedence are grouped in boxes. Assignment is right associative while the others for which associativity makes sense are left associative.
The most basic form of expression in the name. A name is an identifier that is used to refer to an entity. A name always refers to the entity of the same name. When multiple entities have the same name in different parts of a program then the scoping rules (see 7. Scoping) are applied to determine which entity a name refers to. If a name is overloaded then determination of which entity is referenced can't be made from the name alone. Generally a name will be used in such a way that it will be clear. When a name is immediately used for member selection or invocation then it refers to the object and pattern respectively of that name (see 2.2.1 Entity Name Overloading). When an object is invoked, the invocation can be used to determine the pattern being invoked (see 4.2.5 Pattern Overloading). A name always yields an object or pattern as its result.
Member selection is achieved with the member selection operator. This operator is evaluated left to right. The syntax is:
expression.name
When the member selection operator is evaluated, the expression to the left is first evaluated then the member with the name on the right of the operator is selected from that object. If the left expression yields a pattern then it is a type error. If the left expression is an ambiguous reference then the member selection is used to resolve the entity overloading to the object (rather than the pattern). The result of member selection is an object or pattern. However, if the name refers to an overloaded pattern then further contextual resolution may be required (see 4.2.5 Pattern Overloading) to resolve the name to an individual pattern.
Literal expressions are those expressions which literally represent their value. Literal expressions take many forms and their value is determined by their form. The three forms are object literals (see 2.2.1 Object Literals), pattern literals (see 4.3.1 Pattern Literals) and primitive literals (see 1.7 Primitive Literals). Literals act similar to names and result in the entity which they are a literal for. Literals are never ambiguous and always result in some specific object or pattern.
Invocation is the fundamental action which may be performed on patterns. Invocation has the form:
expression( exp1, exp2 ...)
The left hand expression must result in a pattern, if the left expression is an ambiguous name then the invocation can be used to resolve entity overloading to the pattern or patterns. If the name refers to an overloaded pattern name then the overloading can be resolved by the number and type of arguments. The left hand expression is evaluated first, then the parameter expressions are evaluated left to right. The expression results in the value returned from the pattern invocation.
Assignment is a fundamental operation which may be performed on anonymous entities of a named type. Assignment is evaluated right to left and has the form:
lvalue = expression
The lvalue
stands for a left hand value. That is a value which may properly be the target of an assignment. Left hand values are names and expressions whose outermost operation is member selection. In either case the name must refer to an entity that may be assigned to. In the case of pattern overloading, assignment can be used to resolve the overloading to those patterns with a named type. In addition it can resolve which pattern to select when the name is overloaded (based on type compatibility). The lvalue must be type compatible with the result of the expression. In this case the lvalue will be assigned the result of the expression. The assignment expression then evaluates to the value of the expression.
Conversion expressions are of two forms, pattern conversion and object conversion. They can be used to make an implicit type conversion explicit and have the syntax:
:type = expression
The expression is evaluated and the result converted to the named type. This conversion must be legal at compile time. That is, it must be possible to assign the expression's result to an entity of that type. Conversion expressions are often used within grouping expressions because of the low precedence of the assignment operator.
In some cases the order of operation may be unclear or not what is desired. In these cases the grouping operator may be used to order the execution of expressions. The grouping operators are the parentheses and have the form:
( expression )
Expressions enclosed in parentheses are evaluated before their surrounding expression. The grouping expression evaluates to the result of the contained expression.
A statement is generally an expression which is terminated by a semicolon. Only certain types of expressions may be made into statements. The expression must contain at least one of the following:
Note that a conversion expression is not sufficient to make an expression capable of being a statement.
One other form of statement exists. The return statement indicates a change in execution flow. When a return statement is encountered in creation code, execution is terminated and control returns to the caller. If this occurs from a pattern then the optional return expression will be evaluated and the result returned from the pattern. The syntax is:
return expression;
If the return statement occurs inside a pattern which declares a none void return type then the return must include a statement. The exception is if the return type is self. In this case the return type should not include an expression. Self will automatically be returned. Return statements used in object bodies are unnecessary and should not have an expression. Any entity occurring after a return statement is not initialized and is not part of the object being described.