Expression
Gate
Documentation 1.06
The
Gate
The expression gate itself works like any other gate, except that you need to
enter a valid program to be able to spawn it, this is done using the "New
Expression..."-button in the interface which allows you to enter
expressions. Once you have spawned a gate, you can upload a new program to it
by simply clicking it again with the left mouse button. You can also fetch the
program from the gate using the right mouse button and it will then show up in
the expression gate interface. Using the reload button you can reset all
session variables to zero in the expression gate (described in "Inputs and
Outputs").
As long as you keep the same inputs and outputs when you upload a new program
the wires will not disconnect, removing an input or an output will disconnect
that wire from the expression gate.
If there is an error in your program you will be presented with a notification
of what the error is, the errors are however not predictive or especially
smart, they only refer to what parser expected to find, or not find. Meaning
that if you get "Expected (() near (,)", it means that it was
expecting a "(" before the "," in "A = fun, B =
0", in this case it is because "fun" is a function call and as
such requires that you put parenthesis behind it as "A = fun(), B =
0".
Variables
Variables are ways of storing and passing values, just like the memory (M1, M2,
etc) in calculators.
Caution: All variable names must begin with an Uppercase
character to be correctly interpreted. Of further notice is that all variables
that are not bound to input variables will be saved between each execution,
which means that if you set a non-input variable to one, it will stay one until
you change it, this allows you to create very complex setups as you know have
limited internal memory to use.
Code:
A
Code:
Out
Code:
TotalDistance
Inputs and Outputs
Inputs and outputs are variables just like any other, however, there is one
important thing about them and that is that they are bound to the inputs and
outputs of the expression gate.
Meaning that for inputs, whatever is connected to input "A" on the
expression gate trigger an execution of the expression every time it changes
values, and the value is also assigned to variable "A" for so that it
can be used during that execution. Likewise for outputs, whatever is connected
to output "B" of the expression gate receives whatever value
"B" was been assigned during when the last execution ended.
Both inputs and outputs are specified as a sequence of variables delimited by a
single space.
Code:
A
B C
If you ever look in
the files of saved expressions or expresisons posted
on boards, you will find a number of lines at the start with an
"@", these are definitions for label (N@), inputs (I@), outputs (O@).
However, you can also assign variables that are neither inputs nor outputs,
these are called session variables and are kept between each execution meaning
that if you assign "C" a value, next time the expression is executed
"C" will still have that value. This allows you to do some even more
complex things, but it is also dangerous, because it means that you have to
reset all variables at the start of each execution!
Code:
#
BAD! Once Speed has reached 50 then Break will always be 1
Speed
>= 50 -> Break = 1;
Code:
#
GOOD! Break will revert to 0 once Speed is less than 50
Break
= 0, Speed >= 50 -> Break = 1;
Code:
#
BETTER! Same but without zeroing first
Break
= (Speed >= 50 ? 1 : 0)
There are also
constants, variables which never change their value (except by the reprogramming
the gate), these are used to get rid of "magic numbers" in the code,
basically, numbers that you will soon forget what they do or that are specific
to your contraption, such as height or some value for tweaking. So instead of
writing the actual height of the contraption where needed, you assign
"HEIGHT" the value "500" (all uppercase is just a
recommendation) at the start of your expression, and then use
"HEIGHT" instead in your expressions.
Functions
Certain functions are provided to give you access to additional functionality,
that is needed when creating certain setups, all function names start with a
lowercase character followed by a left parenthesis, a comma separated argument
list and a final right parenthesis "atan2(4, 5.2)".
The entire list of functions and their description is available at the end
of this documentation.
Caution: Calling an undefined function will not yield an error in the
current implementation, it will instead return the value "-1".
Code:
#
Absolute value of -2, equals 2
abs(-2)
Code:
#
Round the value 3.42 down, equals 3
floor(3.42)
Code:
#
Convert 67 from degrees to radians, equals 1.169...
rad(67)
Arithmetic Operators
Arithmetic operators are the heart and soul of each expression and should not be
any difficult to comprehend, they are binary operators, which mean that they
take two values as input and output one, but in an understandable sentence, it
just means that you can add and multiply values.
Code:
N
+ N : addition
N
- N : subtraction
N
* N : multiplication
N
/ N : division
N
% N : modulo, also referred to as the remainder of
division "4 / 5 = 2.5 => 0.5", note "-1 % 3 = 2"
N
^ N : exponentiation, "X to the power of 2"
which is also referred to as X squared
-N : negation, change the sign of the value
Comparison Operators
Comparison operators are used for outputting zeroes and ones when put simply,
"is X less than 42", "is Y equal to 20", these are also
used to create conditions which refers to creating a set of requirements for
something to become active (one) which are combined using logical operators
explained in the next section.
Code:
N
== N : equal
N != N : not equal
N
> N :
greater than
N
< N : less
than
N
>= N : greater or equal
N
<= N : less or equal
Caution: The comparison
operators in the expression gate are different from those of the other gates,
namely that zero is false (0) and non-zero is true (1), which is different from
that used in gates where negative and zero is false (0) and positive is (1).
The cause for this is choice for programming semantics, although this might
change in the future. Of further notice is that this gate as all others
determine equality using a delta of 0.001, namely that "0 is equal to
0.00099" and so on.
Code:
#
Is 2 equal to 2, equals 1
2
== 2
Code:
#
Is 2 less than 1, equals 0
2
< 1
Code:
#
Is 3 not equal to 3, equals 0
3 != 3
Logical Operators
Logical operators are of little use by themselves, but when used in conjunction
with comparison operators they become a powerful tool for creating conditions.
These are used for creating more complex setups such checking whether a value
is in range. The same applies here as for the comparison operators, either they
return true (1) or false (0), also they input false
(0) or true (non-zero).
Code:
B
& B : and, if all are true then true otherwise
false
B
| B : or, if any is true then true otherwise false
!B : not,
equal to "B == 0", negates the logical value "2 => 0",
"1 => 0", "0 => 1"
Code:
#
1 and 0, equals 0
1
& 0
Code:
#
2 or 0, equals 2
2
| 0
Code:
#
3 greater than 5 or 4 less than 2, equals 0
3
> 5 | 4 < 2
Conditional
Statements
Although the conditional expression is very handy, it is often useful to being
able to include control over code-flow on another level, so that only certain
parts of the code will be run at certain times. Or to halt execution if a
precondition is not satisfied.
Code:
B
-> E; : if B is true then execute E
B
-> E1, E2, ...; : if B is true then execute E1 then
E2
B
-> E1 E2 ...; :
alternative syntax for the above
While in a
conditional statement you can also write "end", which will
effectively stop the execution from going any further.
Code:
B
-> end;
: if B is true then stop execution
B
-> E, ..., end; : if B is true then execute E and
stop execution
B
-> E ... end; :
alternative syntax for the above
Caution: Be aware of the
semicolon that must end each conditional statement.
Internal Clock
Caution: This is experimental functionality and might be altered in the
future if necessary.
Up until now, being able to setup complex circuits that can delay events and
continually change has only been possible via the use of an external clock of
some sort. Not only is it now possible to remove those external dependencies,
but also to create even more complex setups as a result of the selected
implementation.
Instead of specifying a frequency, you schedule when the next clock pulse
should occur using "schedule(50)", which
will cause the next clock pulse to occur in 50 milliseconds. To continually
keep it executing as it would with an external pulser
use "interval(50)" instead and put it at the
top of the expression, this function has basically the same functionality as schedule,
however it does not override previously scheduled clock pulses, instead it just
ignores the call.
It is also possible to schedule a clock pulse to be executed in response to
e.g. a key press "~Boom & Boom -> schedule(1000);"
which will cause it to execute once in one second. The smallest delay is 20ms,
values lower than 20 will be set to 20 and a value of 0 will abort any
scheduled clock pulse. To know whether or not the current execution is the
result of an internal clock pulse the function "clk()" has been made
available and will return true (1) if the current execution is the result of an
internal clock pulse or false (0) if not.
Code:
#
Counting seconds since spawned
interval(1000)
clk() -> Seconds += 1;
Code:
#
Delayed dynamite trigger
~Boom
& Boom -> schedule(5000);
clk() -> Explode = 1;
Caution: You cannot schedule
multiple clock pulses, the latter will overwrite the
previous scheduled clock pulse.
Additional
Notes
Caution: If you are writing the expression outside of the game, make
sure that your lines does not exceed 92 characters or the entire expressions
might not be transferred to the server, causing strange errors... if the
expression gate cannot be spawned but the validation works, this is most likely
the cause.
By placing a # (hash) at the start of a line that line
will be excluded from parsing, in other words, it will become a comment.
Code:
#
This is a comment!
A
newline in an expression is identical to a space, meaning that you can split an
expression into many lines, in any way you wish.
Code:
A
= 4 +
3
/ 2
#
Is identical to
A
= 4 + 3 / 2
Remember
that sometimes it is smart to use more expression gates instead of one for
reusability and simplicity of the code, if an expression gate has two separate functions
then it might be better to split it into two different.