Expressions
Expressions
An expression is any executable construct, which is everything in the grammar except:
 a function or service definition
 a typedef or resource declaration
 the null statemment, ";"
These are termed nonexecutables. The function, service, typedef and resource constructs have the effect of creating their entity in the Inq environment where the script was parsed. The null statement has no effect at all.
An expression is evaluated to yield a value and to cause any effect it may have, such as creating new nodes or altering existing values.
Constants and Variables
An expression evaluates to a constant value if it is either:
 a value type constant;
 a node that is an alias to a value type constant;
 a node that is an alias to a variable where mutation via this alias would compromise the environment, known as field ripping and discussed in the section Transactions.
An alias to a value type constant is created by an anonymous declaration to a literal value:
any consts.nominalTemp = 25;
or to a function whose return value is such:
any constValue = call returnsConstValue();
A variable is changed by one of the mutating operators
 assignment
 pre/post increment/decrement
and the setnull() function. Mutation can only occur through a path reference, that is an expression of the form
[<prefix>]node1.node2.node3
where the optional prefix denotes one of the specific node spaces.
Parsetime Assignment Errors
Although the orthogonal nature of the Inq language suggests that it should be possible, assignment to an arbitrary expression is an error. For example, all functions have a return value. The script below is semantically equivalent to the statement $this.container.currentTemp = 27;
local function currentTemp() { $this.container.currentTemp; } . . call currentTemp() = 27; // parsetime error
Runtime Assignment Errors
The Inq runtime intervenes in the evaluation of a mutation to perform more than just its effect when the containing map
 is a managed instance in the server environment
 contains one or more variables that have been bound to a GUI view with renderinfo in the client environment.
In these cases Inq respectively enters the instance into the current transaction and raises a model event to refresh the GUI view. To correct the parse error in the above example we can rewrite the assignment as follows:
any v = call currentTemp(); v = 27; // runtime error
However, if $this.container is being managed by Inq then obtaining another reference to the value is an occurrence of field ripping and performing mutation via this reference generates a runtime error. Field ripping can occur in either of the following situations
 an anonymous declaration
 passing a byreference argument to a function
Though not, in itself, illegal, field ripping makes a constant out of the underlying variable. The value will be seen via the alias, but mutations through it would circumvent the runtime management and so are prevented. Aliases through unmanaged containers are not subject to any checks and do not generate mutation exceptions.
Operators
Individual expression terms are combined with operators to create expression groups. The following table lists the operators in order of their evaluation precedence:
Operator  Description 

<expression>
() ++  
A builtin function or construct Grouping parentheses Postincrement Postdecrement 

! ++  
Unary Minus Logical Not Preincrement Predecrement 
^^  Exponentiation 
*
/ % 
Multiplication Division Remainder 
+
 
Binary addition and subtraction 
<
<=
> >= ~~ 
Less than /
Less than or equal to Greater than / Greater than or equal to Regular Expression match 
==
!= 
Equal to Not equal to 
&&  Logical AND 
  Logical OR 
? :  Ternary 
=
+= = *= /= %= &&= = 
Assignment Addition/subtraction assignment Multiplication/division/remainder assignment Logical AND/OR assignment 
With the exception of assignment, all operators associate lefttoright, that is evaluation of an expression occurs in this direction within a precedence group. Assignment associates righttoleft.
Order of Evaluation
All terms of an expression are evaluated unless the they are operands to the operators && (logical AND),  (logical OR) or ?: (ternary).
Mathematical Binary Operators
A mathematical binary operator is processed in the following stages:
 the left hand operand is evaluated;
 the right hand operand is evaluated;
 if either operand is unresolved null an exception is thrown;
 if either operand is the null value the result of the operation is the null constant;
 if the operands are of different types, the operand of lower rank is converted to that of the higher;
 the operation is performed.
The result of the operation is a value of the same (or highest) rank, except for the relational operators, which return a boolean.
Conditional Operators
A conditional binary operator is processed in the following stages:
 the left hand operand is evaluated and converted to a boolean value if required;
 if the operator is && and the left operand evaluates to false the operation returns false;
 if the operator is  and the left operand evaluates to true the operation returns true;
 the right hand operand is evaluated and converted to a boolean value if required;
 if an operand is unresolved null it is equivalent to false;
 if either operand is the null value the result of the operation is false;
 the operation is performed.
The ternary operator evaluates its condition. If the result is true the second operand is evaluated and its result returned. If it is false the third operand is evaluated. The second and third operands do not have to return results of the same type.
Other Operators
A number of other operations are defined that, by their appearance, might have been deemed builtin functions. They are operators because, unlike functions
 multiple operands are evaluated lefttoright;
 numeric operands can be of any type.
Operator  Description  Return Type 

sqrt(x)  Returns the correctly rounded positive square root of the argument  double 
sin(x)  Returns the trigonometric sine of an angle. The argument is in radians  double 
cos(x)  Returns the trigonometric cosine of an angle. The argument is in radians  double 
tan(x)  Returns the trigonometric tangent of an angle. The argument is in radians  double 
asin(x)  Returns the arc sine of an angle, in the range of pi/2 through pi/2  double 
acos(x)  Returns the arc cosine of an angle, in the range of 0.0 through pi  double 
atan(x)  Returns the arc tangent of an angle, in the range of pi/2 through pi/2  double 
ceil(x)  Returns the smallest (closest to negative infinity) double value that is not less than the argument and is equal to a mathematical integer  double 
floor(x)  Returns the largest (closest to positive infinity) double value that is not greater than the argument and is equal to a mathematical integert  double 
todegrees(x)  Converts an angle measured in radians to an approximately equivalent angle measured in degrees  double 
toradians(x)  Converts an angle measured in degrees to an approximately equivalent angle measured in radians  double 
exp(x)  Returns Euler's number e raised to the power of the argument  double 
logn(x)  Returns the natural logarithm (base e) of the argument  double 
round(x)  Returns the closest integer to the argument  int if the argument is of float or lower rank, long otherwise 
max(x, y)  Returns the argument x or y, whichever has the greater value  One of the two arguments is returned, regardless of whether either was converted to a higher rank to make the comparison 
Function Calls
Function calls can be divided into two categories
 calls to scripted functions, defined with the function construct;
 calls to builtin functions.
In either case, Inq does not define the order of evaluation of the function arguments, so applications cannot rely on sideeffects that make one argument dependent on another.
Scripted Functions
Functions are described in Modules, Functions and Services. Each argument in a call statement is evaluated in no particular order. Argument passing then proceeds as follows:
 If the argument evaluates to unresolved null the corresponding argument is unavailable in the called function, that is references to it will result in unresolved null.
 The function definition determines whether the argument is passed by value or by reference. If passed by value the argument is copied to a value of the type of the defined argument. No ranking alignment takes place, so the argument value must be compatible with the defined type. If the argument evaluates to the null constant (or is the null value for the type), the defined argument will be the null value for its type.
 If passed by reference, the value itself is available in the called function and mutations, subject to exceptions because of field ripping, will be visible in it after the call returns.
Builtin Functions
The order of argument evaluation and even whether an argument will be evaluated is not defined. In some cases, a builtin function requires an argument to actually be (rather than just convertible to) a particular value or container type.
Arguments to builtin functions are always passed by reference. Unless explicitly stated in a function's synopsis, arguments are not mutated.
Definition of Equality
Equality Between Value Types
The equality operator performs ranking alignment of its operands, so two values can be equal regardless of whether they are the same type. The following example compares values of the double and int types:
sqrt(225) == 15; true
Fixed Precision Decimals
A fixed precision decimal value can only be compared equal to another fixed precision decimal and values with differing precision will always be not equal:
decimal:2 d2 = "1.23"; 1.23 decimal:3 d3 = "1.230"; 1.230 d2 == d3; false
Strings
Two string values are equal if they represent the same sequence of characters as each other.
Null values and The null Constant
If two values are the null value for their type then they are equal, whether or not they are of the same type.
A value that is null is equal to the null constant:
string s = null; int i; 0 setnull(i); i == s; // i and s are both null true i == null; true isnull(s); true
Equality Of Container Types
In general, containers are considered equal if they are of the same generic type (map, array or set) and contain the same number of children whose values are equal. The equality operator is applied to the container operands and recursively to any children that are, themselves, containers, to the deepest level.
For maps, whose children are keyed, there is the additional requirement that the key set in the two operands must also be equal.
Arrays are always ordered, so two arrays are only equal if their children are equal and occur in the same order. Though the hashbased containers can support ordering, this is not considered when evaluating equality.
If the children being compared at any point during the evaluation are value types then no ranking alignment takes place. Consider the following:
array a1 = (2, 3); // both values of type int [2, 3] array a2 = (2, 3l); // one int, one long [2, 3] a1 == a2; false
Here is another example that shows different map types compare equal and independently of any ordering
omap om1; // Explicitly declare an ordered map {} [] any om1.a = 4; // Put in an integer and a float as children "a" and "b" 4 any om1.b=2.0f; 2.0 any sm1.a=4; // The smap in implicitly created by these declarations 4 any sm1.b=2.0f; 2.0 // Just display the two maps. The omap shows the ordering // of the children, which is as they were inserted sm1; {a=4, b=2.0} om1; {a=4, b=2.0} [a, b] // Compare them om1 == sm1; true // Sort the ordered map. The maps are still equal sort(om1, $this); {a=4, b=2.0} [b, a] om1 == sm1; true // Of course, equality is commutative sm1 == om1; true
Parser Execution
Irrespective of its mode of operation, the parser executes statements as they are parsed. The nonexecutables of function and service definitions are placed into their respective name spaces for the package of the defining parse module.