expression => operand [ternary]
operand => name | literal | special_value | paren | prefix | infix | self
literal => text | number | function
Expressions are made up of names and literals, fortified by prefix (or unary), infix (or binary), suffix, and trinary operators.
paren
=> '(' expression ')'
=> '(' parameter_list ')' '->' expression
Parentheses can be used to explicitly control the order of evaluation of expressions. Parentheses can also be used to create short-form functions.
prefix => prefix_operator operand | array | function
prefix_operator => 'abs' | 'arity'
| 'char' | 'code' | 'fix' | 'int'
| 'length' | 'name' | 'not' | 'object'
| 'parameters' | '+' | '-' | '~'
Prefix operators take an operand. These are operators, not functions, so the operand does not have to be wrapped in parentheses.
absAbsolute value. If the operand is a positive number, the result is the
number. If the operand is a negative number, the result is that number
subtracted from 0. Otherwise, the result is null.
abs -4 # 4 abs 4 # 4
arityArity. If the operand is a function, return the maximum number
of parameters permited. Otherwise, the result is null. It
can report the arity of methods in fixed objects.
charMake a character. If the operand is a number, the result is the character
having that Unicode code point. If the operand is a text, the result
is the first character of the text, or '' if the text
is empty. Otherwise, the result is null.
char 65 # 'A' char 8364 # '€' char 'abc' # 'a' char '' # ''
codeCharacter code. If the operand is a non-empty text, then the result
is the Unicode code point of the first character. Otherwise, the result
is null.
code 'A' # 65 code "Misty" # 77 code 65 # null code null # null
fixMake an object or array immutable. The result is an immutable reference.
Once a reference is made immutable, it cannot be made mutable. It is not
possible to modify an object or array with a fixed reference. It is not
possible to make a new object with the object operator with
a fixed reference. It is not possible to get a function from
an object with a fixed reference. All references obtained from a fixed
object or array will also be fixed. See Security.
The original object is not affected.
Note that numbers, texts, methods, functions, and the special values
true, false, and null are always
immutable.
functionMake a function value. See Functions.
functionname(parameter_list) {body}
intInteger. If the operand is a number, then the result is the integer part
of the number. Otherwise, the result is null. (Also see the
number.trunc method.)
int 3.1415926 # 3 int -3.1415926 # -3
lengthLength. If the operand is an array, the result is the number of elements
in the array. If the operand is a text, the result is the number of characters
in the text. Otherwise, the result is 0.
length {key : 3} # 0
length [7, 11] # 2
length [] # 0
length 'length' # 6
length '' # 0
length 1 # 0
length null # 0
length true # 0
length false # 0
nameName. If the operand is a function, it returns the name as
a text. If it doesn't have a name, it returns an empty text. Otherwise,
the result is null. It can report the name of functions in
fixed objects.
notLogical not. If the operand has a falsy value (false, null,
or '' (the empty text)) then the result
is true. Otherwise, the result is false.
not 0 # false not (3 > 4) # true
objectMake an object. If the operand is null then the result is
a new empty object. If the operand is not an object, then a 'type'
exception is raised. If the operand is fixed, then a 'fix'
exception is raised. If the operand is an object, then the result is a
new empty object that delegates to the operand. See Objects.
object null # {}
object stooge # a new empty object that inherits from the stooge object
parametersParameters. If the operand is a function, it returns the names of the
parameters as a fixed array of texts. If it doesn't have parameters,
it returns a fixed empty array. The length of the array is
the same as the arity. Otherwise, the result is null.
It can report the parameters of functions in fixed objects.
+Convert to number. If the operand is a number, the result is the number. If
the operand is a non-empty text, the result is the text converted as a real
decimal number. If the operand is false, or the empty text, the
result is 0. If the operand is null, the result is
null. If the operand is true, the result is 1.
If the operand is an object and the object has a number method,
then the result is the value returned by operand.number().
Otherwise, the result is null.
+ 2.7182817 # 2.7182817 + '12.00' # 12 + '12pt' # null + '$20' # null + '' # 0 + false # 0 + true # 1 + null # null
-Negate. If the operand is a number, the result is the number subtracted from
0. Otherwise, the result is null.
- 4 # -4 --4 # 4 - 0 # 0
| Value | ~ Value |
|---|---|
true |
"true" |
false |
"false" |
null |
"null" |
| number | number.text() |
| object | object.text() |
| array | array.text() |
| text | text |
~Convert to text. It is short for calling the text method.
Arrays and object are serialized. See JSON.
~ null # 'null'
~ true # 'true'
~ 12.00 # '12'
~ {} # '{}'
infix
=> operand (relational operand)+
=> operand (logical | arithmetic |
concatenation) operand
=> operand (subscription | invocation
| augmentation | possession)
=> operand 'array' operand
=> operand 'is' [ characteristic'not']
=> operand 'apply' operand
relational => '=' | '<>'
| '<'
| '<=' | '>' | '>=' | 'eq'
Relational operators can be strung together in useful ways, so that
a = b = c = d
has a similar result to
a = b and b = c and c = d
=Equal. If the operands are similar, as determined by the first operand's equal method, then the result is true.
a = b
is equivalent to
a.equal(b)
Also see the eq operator, which determines if the operands are the same object.
Examples:
if a = b = null then # compute result if a and b are both null
result : 10 = '10' # result is false
result : 'true' = true # result is false
fi
<>Not equal. If the operands are not similar, as determined by the first operand's equal method, then the result is false.
a <> b
is equivalent to
not (a.equal(b))Example:
result : 'false' <> false # result is true
<Less than. If the first operand is an object, and if it has an lt
method, then the result is the value return from invoking left.lt(right).
Otherwise, if the operands are not of the same type, then null
is the lowest value, followed by booleans, followed by texts, followed
by numbers, followed by the remaining types: functions, objects,
and arrays.
If the operands are the same type, then if the left operand is less than
the right operand, then the result is true. If the left operand
is greater than or equal to the right operand the result is false.
If they are both booleans, false is less than true.
If the operands are arrays, or if the operands are objects, then the system will arbitrarily decide which is smaller.
Example:
return 0 <= i < n then i else null
<=Less than or equal. This is similar to < except that
the le method is used if available, and true
is returned if the values are equal.
>Greater than. This is similar to <= except that the gt
method is used if available, and otherwise the result is complemented.
>=Greater than or equal. This is similar to < except that
the ge method is used if available, and otherwise the result
is complemented.
eqEqual. If the operands are the same value then the result is true. eq and = produce the same result for simple values and functions. They can produce different results for objects and arrays.
logical => 'and' | 'default'
| 'or'
These are short-circuiting operators. If the result can be determined by looking
only at the left operand, then the right operand is not evaluated. The values
false, null, and '' (the empty
text) are falsy. All other values are truthy.
andAnd. If the left operand is falsy, then the result is the left operand. Otherwise, the result is the right operand.
left and right is more convenient
than left then right else
left.
3 < 4 and 5 < 6 # true
defaultDefault. If the left operand is not null, then the result
is the left operand. Otherwise, the result is the right operand. It is
like or except it tests that the left operand is null
instead of falsy.
left default right is more convenient
than left is not null then left
else right.
define foo # foo is null foo default 0 # 0
orOr. If the left operand is truthy, then the result is the left operand. Otherwise, the result is the right operand.
left or right is more convenient
than left then left else
right.
3 < 4 or 6 < 5 # true
arithmetic => 'max' | 'min'
| 'mod' | '+' | '-' | '*' | '/' | '÷'
| '**'
These operators work only for numbers. If either operand is not a number,
or if the operation creates a value that is too large to be contained
in a Misty number, then the result is null.
maxMaximum. The result is the larger of the two operands. If either operand is
not a number, the result is null.
3 max 4 # 4
max can be used with min to constrain values
within an acceptable range.
2 max 3 min 7 # 3 4 max 3 min 7 # 4 9 max 3 min 7 # 7
To determine if a value lies between two other values, uses relational operators.
if 2 <= value <= 7 then ... fi
minMinimum. The result is the smaller of the two operands. If either operand is
not a number, the result is null.
3 min 4 # 3
modThe result of
a
modb
is
a
- ((a/b).floor() *b)
If b is 0, or if either operand is not a number,
then the result is null. b is not required to
be an integer. The result will have the same sign as b.
3 mod 4 # 3 13 mod 4 # 1
+Addition. If either operand is not a number, the result is null.
3 + 4 # 7
-Subtraction. If either operand is not a number, the result is null.
3 - 4 # -1
*Multiplication. If either operand is not a number, the result is null.
If it can be determined that either operand is zero, the other operand
might not be evaluated.
3 * 4 # 12 0.10 * 20 # 2
/ Division. If either operand is not a number, the result is null.
3 / 4 # 0.75 16 / 4 # 4 0 / 0 # null 3 / 0 # null
÷Integer division. a ÷ b produces a result that is similar to (a
/ b).trunc().
3 ÷ 4 # 0 17 ÷ 4 # 4 0 ÷ 0 # null 3 / 0 # null
**Exponentiation.
3 ** 4 # 81 3 ** 0 # 1 0 ** 0 # null
concatenation => '~' | '~~~'
~Concatenation. Convert the two operands to texts. Make a new text
which combines their characters. If both operands are '' or null, then the result is ''. If the first operand is ''
or null, then the result is the second operand. If the second
operand is '' or null, then the
result is the first operand.
3 ~ 4 # '34' 'beginning' ~ "and" ~ 'end' # 'beginningandend' '' ~ 'ok' # 'ok' null ~ null # '' ~ null ~ ~ null # 'nullnull'
~~~Concatenation with a space. Convert the two operands to texts. Make
a new text which combines their characters with a space inserted between
them if both are neither empty nor null. If both operands are '' or null, then the result is ''. If the first operand
is '' or null, then the result is the second
operand. If the second operand is '' or null,
then the result is the first operand.
3 ~~~ 4 # '3 4' 'beginning' ~~~ "and" ~~~ 'end' # 'beginning and end' '' ~~~ 'ok' # 'ok' null ~~~ null # '' ~ null ~~~ ~ null # 'null null'
possession
=> 'can' ['not']
=> 'has' ['not']
=> 'owns' ['not']
canMethod possession. The can infix operator is used to determine if an object contains a particular function. The expression object can name has the same result as object[name] is function.
hasInherited possession. The has infix operator is used to
determine if an object contains a particular member. The expression object
has name returns true if the object[name]
is a property of the object, including its prototype chain. If the left
operand is not an object, then it returns false.
ownsPossession. The owns infix operator is used to determine
if an object contains a particular member. The expression object
has name returns true if the object[name]
is a property of the object, excluding its prototype chain. If the left
operand is not an object, then it returns false.
is Operatorcharacteristic => 'array' | 'blob'
| 'boolean' | 'char' | 'data' |
'digit' | 'end' | 'even'
| 'false' | 'falsy' | 'fix'
| 'function' | 'int' | 'letter'
| 'lower' | 'method' | 'number'
| 'null' | 'object' | 'odd'
| 'pattern' | 'space' | 'text'
| 'true' | 'truthy' | 'upper'
The is infix operator returns either true or
false from its determination of a characteristic of the first
operand. The is keyword can optionally be followed by the
word not, which reverses the meaning of the characteristic.
So if
value is an int
is true, then
value is not an int
will be false.
is arrayIs this an array? If the operand is an array, the result is true.
Otherwise, the result is false.
0 is array # false
{} is array # false
[] is array # true
[] is not array # false
pattern [] is array # false
"array" is array # false
true is array # false
is blobIs this a blob? A blob is a pile of data. Misty does not have operators
for creating or manipulating blobs, but does allow them to transit through
the system. References to blobs can be stored in variables, objects, and arrays. Blobs
can be passed to or returned from functions. Blobs have no methods. Blogs
have no operators except for is blob. If the operand is a
blob, the result is true. Otherwise, the result
is false. Generally, a blob is blob, and a blob is truthy.
0 is blob # false "blob" is blob # false
is booleanIs this a boolean? If the operand is true or false,
the result is true. Otherwise, the result is false.
0 is boolean # false 0 is not boolean # true false is boolean # true "true" is boolean # false true is boolean # true
is charIs this a character? If the operand is a text with a length
of 1, then the result is true. Otherwise, the result is false.
1 is char # false "1" is char # true "char" is char # false '' is char # false true is char # false
is dataIs this a data value? If the operand is a not null and not
a function, then the result is true. Otherwise, the result
is false.
0 is data # true
"0" is data # true
"9" is data # true
"null" is data # true
null is data # false
function () {} is data # false
'' is data # true
false is data # true
is digitIs this a digit? If the operand is a text with a length
of 1 and is one of the 10 digit characters, then the result is true.
Otherwise, the result is false.
0 is digit # false "0" is digit # true "9" is digit # true "09" is digit # false "digit" is digit # false '' is digit # false true is digit # false ["0"] is digit # false
is endIs this a line ending character? If the operand is a text with a length
of 1, and if it contains a Unicode line ending character, then the result
is true. Otherwise, the result is false.
0 is end # false "" is end # false " " is end # false "\n" is end # true '\r' is end # true '\r\n' is end # false '[\n]' is end # false ['\n'] is end # false pattern [end] is end # false
is evenIs this an even number? If the operand is a number and its integer part
is even, then the result is true. Otherwise, the result is
false.
0 is even # true 1 is even # false (13 / 4) is even # false (13 / 0) is even # false (17 / 4) is even # true 98.6 is even # true "0" is even # false true is even # false
is falseIs this false? If the operand is false, then
the result is true. Otherwise, the result is false.
There is no advantage to using this form over the = form.
"false" is false # false false is false # true 0 is false # false '' is false # false
is falsyIs this a falsy value? If the operand is false, null,
or the empty text, then the result is true. Otherwise,
the result is false.
"false" is falsy # false
false is falsy # true
0 is falsy # false
'' is falsy # true
null is falsy # true
{} is falsy # false
[] is falsy # false
is fixIs this fixed? If the operand is immutable, then the result is true.
Otherwise, the result is false. All booleans, numbers, texts,
functions, and blobs are immutable. Objects and arrays are initially mutable,
but an immutable reference can be obtained with the fix operator.
0 is fix # true
"0" is fix # true
[] is fix # false
{} is fix # false
(fix []) is fix # true
(fix {}) is fix # true
true is fix # true
is functionIs this a function? If the operand is a function, then the result is
true. Otherwise, the result is false. If the
operand is a dot expression or a subscript expression, then is
can determine the result even if the object is fixed.
0 is function # false
function () {} is function # true
function () {return $} is function # true
"function" is function # false
true is function # false
(fix {koda: function () {}}).koda is function # true
is intIs this an integer? If the operand is a number and if its fraction part
is zero, then the result is true. Otherwise, the result is
false.
0 is int # true (13 / 4) is int # false 65.0000000 is int # true 65.0000001 is int # false null is int # false true is int # false
is letterIs this a letter? If the operand is a text with a length of 1 and is a
letter, then the result is true. Otherwise, the result is
false.
0 is letter # false "0" is letter # false "letter" is letter # false "l" is letter # true "L" is letter # true '' is letter # false true is letter # false
is lowerIs this a lower case letter? If the operand is a text with a length of 1 and is a lower case letter, then the result is true. Otherwise,
the result is false.
0 is lower # false "0" is lower # false "lower" is lower # false "l" is lower # true "L" is lower # false '' is lower # false true is lower # false
is methodIs this a method? If the operand is a function that uses $,
then the result is true. Otherwise, the result is false.
If the operand is a dot expression or a subscript expression, then is
can determine the result even if the object is fixed.
0 is method # false
function () {} is method # false
function () {return $} is method # true
"method" is method # false
true is method # false
(fix {koda: function () {return $}}).koda is method # true
is nullIs this null? If the operand is null, then
the result is true. Otherwise, the result is false.
There is no advantage to using this form over the = form or eq form.
null is null # true (13 / 0) is null # true 0 is null # false "null" is null # false "" is null # false false is null # false
is numberIs this a number? If the operand is a number, then the result is true.
Otherwise, the result is false.
0 is number # true (13 / 4) is number # true (13 / 0) is number # false 98.6 is number # true "0" is number # false true is number # false
is objectIs this an object? If the operand is an object, then the result is true.
Otherwise, the result is false.
0 is object # false
{} is object # true
[] is object # false
"object" is object # false
"{}" is object # false
function () {} is object # false
pattern [] is object # true
true is object # false
is oddIs this an even number? If the operand is a number and its integer part
is odd, then the result is true. Otherwise, the result is
false. This is not always the same as is not even.
0 is odd # false 1 is odd # true (13 / 4) is odd # true (13 / 0) is odd # false 98.6 is odd # false "0" is odd # false true is odd # false
is spaceIs this whitespace? If the operand is a text with a length of 1 and is
a whitespace character, then the result is true. Otherwise,
the result is false.
0 is space # false 32 is space # false char 32 is space # true "0" is space # false " " is space # true "\t" is space # true "\r" is space # true "space" is space # false " " is space # false "L" is space # false '' is space # false true is space # false
is textIs this a text? If the operand is a text, then the result is true.
Otherwise, the result is false.
0 is text # false "0" is text # true "number" is text # true '' is text # true true is text # false
is trueIs this true? If the operand is true, then
the result is true. Otherwise, the result is false.
There is no advantage to using this form over the = form or eq form.
"true" is true # false true is true # true 1 is true # false
is truthyIs this a truthy value? If the operand is false, null,
or the empty text, then the result is false. Otherwise,
the result is true.
"false" is truthy # true
false is truthy # false
0 is truthy # true
'' is truthy # false
null is truthy # false
{} is truthy # true
[] is truthy # true
is upperIs this an upper case letter? If the operand is a text with a length of 1 and is an upper case letter, then the result is true. Otherwise,
the result is false.
0 is upper # false "0" is upper # false "UPPER" is upper # false "u" is upper # false "U" is upper # true '' is upper # false true is upper # false
{ }augmentation => object_literal
Augmentation. If the left operand is a mutable object, then the name/value
pairs within the { } are put into the operand, and the result
is the operand. Otherwise, a 'type' exception is raised.
These expressions can be used as statements. (Also see the object.combine
method.)
define stooge : {first_name : 'Curly'}
stooge {last_name : 'Howard'}
# stooge is {first_name : 'Curly', last_name : 'Howard'}
.subscription
=> '.'name
=> '[' expression ']'
Selection. This identifies a member in a value. It is generally used only with objects, but it can be used to invoke built-in methods on other types. This is a special case of subscription.
stooge.last_name # 'Howard' stooge.first_name # 'Curly'
[ ]Subscription. The expression in the brackets is used as a key to select a member a member of an object. If the left operand is an array, then the value in the brackets is a number (not a text) used to select an element. It will be truncated to an integer if necessary. If the left operand is a text, then the number in the brackets is used to select a character.
On retrieval, if the object does not contain the key, then null
will be returned. On storage, a 'fix' exception will be raised
if the object is immutable. On storage to a mutable array, if the key
is not a number or if the key violates the bounds of the array, an 'array'
exception will be raised.
stooge['first_name'][4] # 'y' null['foo'] # null
( )invocation => '(' expression,
')'
Invocation. The ( ) suffix operator invokes a function value. The function invocation pattern can be used only
with function values that do not use the $ operator..
function_value
(parameters...)
The method invocation pattern is used with members that are function values.
object
.method_name(parameters...)
If the value is not function, a 'function' exception is
raised.
If a function is invoked with too many parameters, an 'arity'
exception is raised.
$self => '$'
Self. The $ operator allows a method to have access to the
object that was used in the invocation. See Functions.
applyApplication. The apply operator provides an alternate way
of invoking a function or method. It works like the () operator
except that it takes a single expression (which could be an array of arguments)
rather than an argument list. The left operand is an expression that yields
a function or method value. The right operand is null if
the function should be called with no parameters, or an array of parameters,
or a single parameter that is not null or an array. Also
see the object.call method. apply uses the call
process, so apply can be used to invoke anything that ()
can invoke.
Example:
my_object[methodname] apply my_array
ternary => then_else
There is one ternary operator. A ternary operator takes three operands.
A ternary expression must be wrapped in parens when it appears in the
condition part of an if statement.
then elsethen_else => 'then' expression 'else'
expression
Conditional expression. If the left operand is truthy, then the result is the middle operand. Otherwise, the result is the right operand. The unused operand is not evaluated.
message : t.reserved then "Already reserved." else "Already defined."
( ) [ ] .
apply |
{ } |
|
prefix operators
|
is ... |
** |
* / ÷ mod |
+ - |
max min |
~ ~~~ |
= <> <
> <= >= eq |
and or default
array |
then else |
Unary operators group right to left. All other operators group left to right. The member and invocation operators have the highest priority (tightest). The trinary operator has the lowest priority (loosest). Grouping can be made explicit with parens.
'$' ~ 3 + 4 // '$7'