## Expressions

Expressions can be categorized in many different ways: type of action, appearance, whether it also assigns the value somewhere or if its purpose has a special meaning.

There are 5 types of action for expressions in SGScript: arithmetic, bitwise, logical, comparison and special.

expressionappearancetype of actionassign# in.
add` A + B `arithmeticno2
subtract` A - B `arithmeticno2
multiply` A * B `arithmeticno2
divide` A / B `arithmeticno2
modulo` A % B `arithmeticno2
pre-increment` ++ A `arithmeticself1
pre-decrement` -- A `arithmeticself1
post-increment` A ++ `arithmeticself1
post-decrement` A -- `arithmeticself1
add-assign` A += B `arithmeticyes2
subtract-assign` A -= B `arithmeticyes2
multiply-assign` A *= B `arithmeticyes2
divide-assign` A /= B `arithmeticyes2
modulo-assign` A %= B `arithmeticyes2
bitwise AND` A & B `bitwiseno2
bitwise OR` A | B `bitwiseno2
bitwise XOR` A ^ B `bitwiseno2
left shift` A << B `bitwiseno2
right shift` A >> B `bitwiseno2
bitwise AND-assign` A &= B `bitwiseyes2
bitwise OR-assign` A |= B `bitwiseyes2
bitwise XOR-assign` A ^= B `bitwiseyes2
left shift-assign` A <<= B `bitwiseyes2
right shift-assign` A >>= B `bitwiseyes2
bitwise invert` ~ A `bitwiseno1
logical AND` A && B `logicalno2
logical OR` A || B `logicalno2
first-not-null` A ?? B `logicalno2
logical AND-assign` A &&= B `logicalyes2
logical OR-assign` A ||= B `logicalyes2
first-not-null-assign` A ??= B `logicalyes2
logical invert` ! A `logicalno1
less than` A < B `comparisonno2
less than or equal` A <= B `comparisonno2
greater than` A > B `comparisonno2
greater than or equal` A >= B `comparisonno2
equal` A == B `comparisonno2
not equal` A != B `comparisonno2
strict equality` A === B `comparisonno2
strict inequality` A !== B `comparisonno2
raw comparison` A <=> B `comparisonno2
error suppression` @ A `specialno1
declare-local` var A `specialmaybeany
declare-global` global A `specialmaybeany
array literal` [ A, B, .. ] `specialnoany
dict. literal` {A=1,B=2,..} `specialnoany
map literal` map{[A]=B} `specialnoany
assign` A = B `specialyes1
concatenate` A \$ B `specialno2
concatenate-assign` A \$= B `specialyes2
concatenate` A .. B `specialno2
concatenate-assign` A ..= B `specialyes2
property` A . B `specialmaybe2
index` A [ B ] `specialmaybe2
multi-index-assign` A[]<dict.lit>`specialyesany
multi-property-assign` A.<dict.lit> `specialyesany
function call` A ([B,..]) `specialno<=256
comp. function call` O!A ([B,..]) `specialno<=256
function definition` function A.. `specialmaybe0
inline if` if(A,B,C) `specialno3(2)
subexpression` ( A[, ..] ) `specialmaybeany
thread-call` thread f() `specialmaybe<=256
subthread-call` subthread f()`specialmaybe<=256
new-call` new f() `specialmaybe<=256

Some notes on the special cases:

• [increment,decrement] pre-increment and pre-decrement operators return the modified value, post- operators - the original one
• [logical] all logical operators except 'logical invert' (which returns bool) set/return one of the two operands passed
• [equality] strict (in)equality operators are the same as their non-strict counterparts with one difference: they do type checking, for example `5 == 5.0` would return 'true' and `5 === 5.0` would return 'false'
• [declare] declarations only actually set the data if they include the assignment expression, otherwise only the type is internally noted for other references
• [declare] variables can be redeclared as long as they maintain their access level
• [property,index] whether property or index expressions set data depends if they're on the receiving (left) end of an assignment expression
• [inline if] 3 inputs are required, 2 are actually used (as if `if(A){return B;}else{return C;}` was used)
• [subexpression] subexpressions can set data if they are set up like this: <subexpression> = <function-call> - this is the way to read more than one return value from a function
• [error suppression] the `@` operator disables warnings, errors and any other messages for as long as the subexpression is executed, this is mostly useful for things like reading a property or calling a function that may not exist, in cases where that isn't an error
• [dict./map literal] 3 types of keys are supported: string, identifier (interpreted as string), variable ("[ <expression> ] = <value>")
• [function] the full function definition expression syntax: `function <name> ( <args> ) [ use ( <use-list> ) ]`, followed by either `{ ... }` or `= ... ;`. <name>, <args> and the 'use' block are all optional.
• [multi-set] operator returns `A`, that is, the object itself
• [thread] `thread`/`subthread` commands support all kinds of calls (`f()`, `o.f()`, `o!f()`)
• [new] `new` supports only the basic calls (`f()`, `o.f()`), and `this` is not passed (as it would refer to the newly created instance)
##### compatible function call / inheritance call / global method call (` O!A ([B,..]) `)

CFC is created to encourage users to reduce memory usage without sacrificing clarity of code. Object and its processing function can reside in different locations (like class instance / inherited class) and still be easily accessible.

Properties:

• uses the same symbol as logical inversion operator
• usage: simplified & optimized calling of non-integrated compatible functions
• instead of `comp_func.call( object, arg1 )` (removed since 1.4) write `object!comp_func( arg1 )`
• instead of putting functions with data / class interfaces, requiring additional memory usage, allows to easily keep them separate
• simplify inheritance-like code models to the extent permitted by a dynamic language

Example WITHOUT:

```function create_object()
{
object = { x = 0, y = 0 };
function object.move( x, y ){ this.x = x; this.y = y; @this.move_callback(); }
function object.tick( delta ){ this.move( this.x + delta, this.y ); }
return object;
}```

Example WITH:

```function Object_Move( x, y ){ this.x = x; this.y = y; @this.move_callback(); }
function create_object()
{
object = { x = 0, y = 0 };
function object.tick( delta ){ this!Object_Move( this.x + delta, this.y ); }
return object;
}```

Now, by itself it may not mean much, however let's see what happens if the following code is used:

```for( i = 0; i < 100; ++i )
objects.push( create_object() );```

Without the usage of a global method, there's a key 'move' in each object that points to the function. In real software there may be no less than 10 such keys in many instances of many objects. And if there are no overrides planned for it, there's no need for it to be there but we can't really move it. Classes are an option that involves a few more allocations and it requires more memory to use them. Using `.call/sys_call` or replacing `this` with an argument would sacrifice readability and the option to relocate functions, as well as performance, this being a double call. This is where CFC comes in - syntax allows to clearly state the object and function used, and the required interface for the object to be compatible with said function.