Squirrel provides a number of operators — symbols or keywords which represent an action to be performed on one or more variables. When Squirrel performs that action, it’s called an evaluation and it yields a value which is said to be the result of the operation. The result may be stored in one of the participant variables or a new one, or even ignored, depending on the needs of your application.
Whenever you check the value of a variable, choose which of several code paths to take in a branch structure, or iterate through the slots in a table, you make use of operators. They are fundamental to manipulating data in a Squirrel program.
But Squirrel is nothing if not flexible and it provides a mechanism for the actions of many of its operators to be overridden with your own code.
Squirrel applies operators in a specific order when it encounters multiple operators within a statement:
~
, !
, typeof, ++
, --
/
, *
, %
+
, -
<<
, >>
, >>>
<
, <=
, >
, >=
==
, !=
, <=>
&
^
|
&&
, in||
?:
+=
, =
, -=
,
Squirrel provides the following operators. A number of these are described in detail later in this section.
Operator | Name | Form | Description |
---|---|---|---|
= |
Assignment | x = y |
Make x equal to y |
+ |
Arithmetic addition | x + y |
Adds x to y |
+= |
Arithmetic compact addition | x += y |
Makes x equal to x plus y |
++ |
Arithmetic increment | x++ |
Makes x equal to x plus 1 |
- |
Arithmetic subtraction | x - y |
Subtracts y from x |
-= |
Arithmetic compact subtraction | x += y |
Makes x equal to x minus y |
-- |
Arithmetic decrement | x-- |
Makes x equal to x minus 1 |
/ |
Arithmetic division | x / y |
Divides x by y |
/= |
Arithmetic compact division | x /= y |
Makes x equal to x divided by y |
* |
Arithmetic multiplication | x * y |
Multiply x by y |
*= |
Arithmetic compact multiplication | x *= y |
Makes x equal to x times y |
% |
Arithmetic modulo | x % y |
Remainder of x divided by y |
%= |
Arithmetic compact modulo | x %= y |
Make x equal to the remainder of x divided by y |
! |
Logical NOT | !x |
Negates the boolean value |
|| |
Logical OR | x || y |
true if x is true or y is true , otherwise false |
&& |
Logical AND | x && y |
true if x and y are both true , otherwise false |
== |
Equality comparison | x == y |
true if x equals y, otherwise false |
!= |
Inequality comparison | x != y |
true if x doesn’t equal y, otherwise false |
<= |
Less than or equals comparison | x <= y |
true if x is less than or the same as y, otherwise false |
=> |
Greater than or equals comparison | x >= y |
true if x is greater than or the same as y, otherwise false |
> |
Greater than comparison | x > y |
true if x is greater than y, otherwise false |
< |
Less than comparison | x < y |
true if x is less than y, otherwise false |
<=> |
Three-way comparison | x <=> y |
See below |
<- |
New slot | x.y <- z |
Add a new key, y, to a table, x, and assign it a value, z. See also Tables |
& |
Integer bitwise AND | x & y |
Combine the two values bit by bit using AND |
| |
Integer bitwise OR | x | y |
Combine the two values bit by bit using OR |
^ |
Integer bitwise XOR | x ^ y |
Combine the two values bit by bit using Exclusive OR |
~ |
Integer bitwise NOT | x ~ y |
Combine the two values bit by bit using NOT |
>> |
Integer signed bit shift right | x >> y |
Move the bits in x to the right by y places, retaining the sign bit. See below |
<< |
Integer signed bit shift right | x >> y |
Move the bits in x to the right by y places, retaining the sign bit. See below |
>>> |
Integer unsigned bit shift right | x >>> y |
Move the bits in x to the right by y places, ignoring the sign bit. See below |
?: |
Ternary | x ? y : z |
See below |
, |
Comma | x , y |
See below |
Squirrel also provides a three-way comparison operator, <=>
, which compares the two values on either side of the operator returns a third according the result of that comparison: a positive integer if the left value is greater than the right value, 0 if the values are the same, or a negative integer if the left value is less than the right value.
In numerical comparisons, the integers returned are 1, 0 or -1, but when you are working with strings, <=>
returns the magnitude of the difference between the two strings. For example, the string expression "a" <=> "z"
evaluates to -25
(Ascii code 97 is 25 less than Ascii code 122).
Additionally, if the string contains a NUL
character (ie. integer 0), <=>
will not compare any characters after the NUL
. This is also the case with all other relative comparison operators (>
, >=
, <
and <=
) but not equality comparison operators (==
and !=
).
local result = valueOne <=> valueTwo;
// result = 1 if valueOne > valueTwo
// -1 if valueOne < valueTwo
// 0 if valueOne = valueTwo
Note To get the magnitude of the difference, you can use:
local difference = math.abs(valueOne - valueTwo);
The ternary operator, ?:
evaluates the expression to the left of the question mark and returns either of the two values (or expression results) separated by the colon depending on the result of the evaluation: the value or expression result on the left of the colon for true
, or the value or expression result on the right of the colon for false
.
For example, if the value of the imp API method server.isconnected() in the line below returns true
, the ternary operator will return the string "The imp is online"
; if server.isconnected() returns false
, messageString becomes "The imp is offline"
:
local messageString = server.isconnected() ? "The imp is online" : "The imp is offline";
The comma operator allows you to combine operations. Take a look at this code which makes use of the operator twice:
local j = 0, k = 0;
for (local i = 0 ; i < 10 ; i++ , j++) {
k = i + j;
server.log((i + 1) + ". " + k);
}
The first line is equivalent to:
local j = 0;
local k = 0;
In other words, the keyword local
is ‘shared’ by the following comma-separated assignments.
On the second line, the increment section of the for
loop configuration is i++, j++
: both i and j are incremented.
Squirrel evaluates the comma-separated expression left to right, and the result of the operator is the result of the expression on the right. For example:
local a, b;
a = (b = 1, b += 2);
server.log(a);
// Displays '3'
Again, a and b share the local
. You should note that both must be assigned a value or neither. You can’t write local a = 0, z
or an error will be thrown.
On the second line, Squirrel evaluates the bracketed statement left to right, so b is assigned the value 1, and the b is incremented by 2. The statement evaluates to 3 (which is what b equals too) and that value is assigned to a.
Squirrel integers are signed and the language’s integer bitwise operators >>
and <<
can be used to shift the value one or more bits right and left, respectively, ie. multiply or divide by two. This is useful to ‘sign extend’ 8- or 16-bit signed values retrieved from sensors or other external devices to Squirrel’s native 32-bit signed integers:
// Get sensor temperature reading, which is a signed
// 16-bit value issued as two successive bytes
local tempMSB = onewire.readByte();
local tempLSB = onewire.readByte();
// Convert to 16-bit value
local temp = (tempMSB << 8) + tempLSB;
// 'temp' is 32-bit, so we move the lower 16 bits
// up to set the sign bit (bit 31) appropriately and
// move the value itself back to the correct bits
// (the sign bit is not changed by the down-shift)
temp = ((temp << 16) >> 16);
// Convert to Celsius
local tempCelsius = temp * 0.0625;
server.log("The temperature is " + format("%.2f", tempCelsius) + "C");
The language also provides >>>
to shift the unsigned reading of the integer to the right.
The following operators make use of specific Squirrel keywords rather than symbols.
The in
operator is used to test for the existence of a slot in a table, ie. whether the table contains the specified key, or for the presence of a member property or method in an object.
Use a string literal or string variable for the name of the key you’re testing for:
if ("firstKey" in myTable) {
// 'myTable' has the key 'firstKey' so set it
myTable.firstKey = "Rowdy Yates Block";
}
local searchKey = "firstKey";
if (searchKey in myTable) {
// 'myTable' has the key 'firstKey' so set it
myTable.firstKey = "Rowdy Yates Block";
}
The if ("X" in Y)
construct works in Electric Imp Squirrel even if Y has a delegate or a _get metamethod. This is what enables if ("pinA" in hardware)
, but is not a features of standard Squirrel.
The typeof
operator returns a lower-case string indicating the type of value held (or pointed to) by the specified variable: "integer"
, "float"
, "bool"
, "string"
, "array"
, "table"
or "blob"
.
local a = {};
server.log(typeof a);
// Displays "table"
The instanceof
operator tests if the named object is an instance of the specified class, evaluating to true
if it is, otherwise false
.
if (anInstance instanceof Test) {
// Perform conditional code...
}
Metamethods are a means by which Squirrel programmers can override existing language operators. Essentially, each metamethod provides a way to substitute your functionality for Squirrel’s own. This substitution takes place whenever Squirrel subsequently encounters the overridden operator(s).
For example, Squirrel encounters any one of the relative comparison operators — <=
, >=
, <
and >
— to the right of an object, it immediately looks in the object’s specified delegate (if it has one; tables do not, by default) for the _cmp metamethod. If Squirrel finds a function named _cmp(), it will call that function, otherwise it runs the code of its own.
Metamethods only work with certain entities — tables, class instances and class objects — and a given metamethod will not necessarily work with all of those entities. For example, _nexti
only works with class instances, not tables, while _newslot
is only relevant to tables, and _newmember
to class objects.
The following table lists the metamethods available to programmers, including the entities for which they are applicable:
Metamethod | Operator(s) | Parameter(s) | Use With | Notes |
---|---|---|---|---|
_cmp | <, >, <=, >= | Operand to the right of the operator | Table, class instance | Perform a relative comparison, eg. if (a > b) { ... } Function should return an integer: 1, if a > b 0, if a == b -1, if a < b |
_mul | * | Operand to the right of the operator | Table, class instance | Perform a multiplication, eg. local a = b * c Returns the result |
_add | + | Operand to the right of the operator | Table, class instance | Perform an addition, eg. local a = b + c Returns the result |
_sub | - | Operand to the right of the operator | Table, class instance | Perform a subtraction, eg, local a = b - c Returns the result |
_div | / | Operand to the right of the operator | Table, class instance | Perform a division, eg. local a = b / c Returns the result |
_mod | % | Operand to the right of the operator | Table, class instance | Perform a modulo, eg. local a = b % c Returns the result |
_unm | - | Operand to the right of the operator | Table, class instance | Perform a unary minus, eg. local a = -b Returns the result |
_newslot | <- | Key and value | Table | Creates and adds a new slot to a table |
_delslot | delete | Key | Table | Removes a slot from a table |
_set | = | Key and value | Table, class instance | Called when code attempts to set a non-existent slot’s key, eg. table.a = b |
_get | = | Key | Table, class instance | Called when code attempts to get the value of a non-existent slot, eg. local a = table.b |
_typeof | typeof | None | Table, class instance | Returns type of object or class instance as a string, eg. local a = typeof b |
_tostring | .tostring() | None | Table, class instance | Returns the value of the object or class instance as a string, eg. local a = b.tostring() |
_nexti | foreach… in… | Previous iteration index | Class instance | Called at each iteration of a foreach loop. Parameter value will be null at the first iteration.Function must return the next index value |
_cloned | clone | The original instance or table | Table, class instance | Called when an instance or table is cloned |
_inherited | New class (as this) and its attributes | Class object | A parent class method is overridden by a child class | |
_newmember | index, value, attributes, isstatic | Class object | Called when a new class member is declared. If implemented, members will not be added to the class | |
_call | this and the function’s other (visible) parameters | Table, class instance | Called when the table or class instance is itself called as a function |
For more detailed guidance on metamethods and how (and for what) they are employed in code, please see the Developer Guide ‘Using Squirrel Metamethods’.