Expressions
ll.ul4c
supports many of the operators supported by Python. The following
subchapters describe all expressions/operators that UL4 supports and are ordered
from highest precedence to lowest.
Generator expressions
UL4 supports generator expressions with look like list comprehensions without the square brackets. Generator expression do not create lists in memory but instead return an iterable that can be iterated once. Function and methods that require an iterable argument can directly consume such iterables:
<?print ", ".join("(" + c + ")" for c in "gurk")?>
will output
(g), (u), (r), (k)
Outside of function/method arguments (or when more that one argument is passed) parentheses are required around generator expressions:
<?code ge = ("(" + c + ")" for c in "gurk")?>
<?print ", ".join(ge)?>
Hint
Generator expressions are implemented by
ll.ul4c.GeneratorExpressionAST
.
Index/slice access
Index and slice access is available for all container types, i.e. in the
expression a[b]
the following type combinations are supported:
string, integer: Returns the
b
th character from the stringa
. Note that negativeb
values are supported and are relative to the end, soa[-1]
is the last character.list, integer: Returns the
b
th list entry of the lista
. Negativeb
values are supported too.dict, string: Return the value from the dictionary
a
corresponding to the keyb
. Note that some implementations might support keys other than strings too. (The Python and Java implementations do for example. The Javascript implementation does too, ifMap
is supported.)
If the specified key doesn’t exist or the index is out of range for the string or list, a special “undefined” object is returned.
Slices are also supported (for list and string objects). As in Python one or both of the indexes may be missing to start at the first or end after the last character/item. Negative indexes are relative to the end. Indexes that are out of bounds are simply clipped, so
<?print "Hello, World!"[7:-1]?>
prints World
and
<?print "Hello, World!"[:-8]?>
prints Hello
.
Hint
Index/slice access is implemented by ll.ul4c.ItemAST
.
Attribute access
For string keys it’s also possible to access dictionary entries via the
attribute access operator .
, i.e. foo.key
is the same as foo["key"]
if foo
is a dictionary.
Hint
Attribute access is implemented by ll.ul4c.AttrAST
.
Function calls
A function call in UL4 looks like this: date(2014, 10, 9, 17, 29)
.
(this returns the date object @(2014-10-09T17:29)
). Some of the trailing
arguments in a function call might be optional and have default values.
For example the first three arguments for the date
function (year
,
month
and day
) are required, the remaining four arguments (hour
,
minute
, second
and microsecond
) are optional and default to 0
.
Parameter values can also be passed via keyword arguments, i.e.
date(2014, 10, 9)
could also be written as
date(day=9, month=10, year=2014)
.
Furthermore Python’s *
and **
syntax is supported for passing additional
positional or keyword arguments. For example:
<?code args = [2014, 10, 9, 17, 29]?>
<?code d = date(*args)?>
is the same as:
<?code d = date(2014, 10, 9, 17, 29)?>
The same can also be done with a keyword dictionary and the **
syntax:
<?code kwargs = {"day": 9, "month": 10, "year": 2014, "hour": 17: "minute": 29}?>
<?code d = date(**kwargs)?>
Of course it’s also possible to mix argument passing mechanics:
<?code d = date(2014, *[10, 9], **{"hour": 17, "minute": 29})?>
or
<?code d = date(2014, month=10, day=9, **{'hour': 17, 'minute': 29})?>
However the *
and **
arguments can only be use at the end of the
argument list and positional arguments must always be before keyword arguments.
A list of builtin functions can be found in Functions.
Hint
This documentation uses Python’s /
and *
notation to specify
positional-only and keyword-only arguments. So
<?ul4 f(x, /, y, *, z)?>
means that the function f
accepts the parameter x
only when passed by
position, y
can be passed either by position or by keyword and z
will
only be accepted when passed by keyword.
Hint
Function calls are implemented by ll.ul4c.CallAST
.
Unary operators
Arithmetic negation
The unary operator -
inverts the sign of its operand, which must be an
integer, float of boolean value:
<?code x = 42?><?print -x?>
prints -42
. For -
boolean values are treated as the numbers 0
and
1
, i.e.:
<?code x = True?><?print -x?>
prints -1
.
Hint
Arithmetic negation is implemented by ll.ul4c.NegAST
.
Binary negation
The unary operator ~
inverts the bits of an integer or boolean value.
Non-negative numbers are interpreted as having an unlimited number of leading
0
bits and negative numbers are interpreted as having an unlimited number
of leading 1
bits. The means that ~x
will be negative if x
is
non-negative and vice versa.
Hint
Arithmetic negation is implemented by ll.ul4c.BitNotAST
.
Multiplicative binary operators
Multiplication
The multiplication operator *
returns the arithmetic product of its
operands (which must be integer, float or boolean values). Furthermore it’s
possible to multiply a sequence (i.e. a string or list) with a non-negative
integer to get a new sequences that repeats the items of the original sequence a
number of times, e.g. "foo" * 2
returns "foofoo"
and [1, 2, 3] * 3
return [1, 2, 3, 1, 2, 3, 1, 2, 3]
. Multiplying with 0
returns an empty
string or list.
Hint
Multiplication is implemented by ll.ul4c.MulAST
.
True division
The true division operator /
returns the quotient of its operands (which
must be integer, float or boolean values). The result is always a float value.
1/2
returns 0.5
.
Hint
True division is implemented by ll.ul4c.TrueDivAST
.
Floor division
The float division operator //
returns the quotient of its operands (which
must be integer, float or boolean values) rounded down to an integer (rounding
is always done towards -infinity, i.e. (-25)/10
returns -3
). If any of
the operands is a float the result is a float too, otherwise it’s an integer.
Hint
Floor division is implemented by ll.ul4c.FloorDivAST
.
Modulo
The modulo operator %
returns the remainder from the division of the first
operand by the second, e.g. 15 % 7
returns 1
.
Hint
The modulo operator is implemented by ll.ul4c.ModAST
.
Additive binary operators
Addition
The addition operator +
returns the sum of its operands (which must be
integer, float or boolean values). Furthermore sequences of the same type can be
added, so "foo" + "bar"
returns "foobar"
and [1, 2] + [3, 4]
returns
[1, 2, 3, 4]
.
Hint
Addition is implemented by ll.ul4c.AddAST
.
Subtraction
The subtraction operator -
returns the difference of its operands (which
must be integer, float or boolean values).
Hint
Subtraction is implemented by ll.ul4c.SubAST
.
Bit shift operators
Binary left shift operator
The binary left shift operator <<
shifts the bits of its first operand (an
integer or boolean) to the left by the number of positions given by the second
operand (which must also be an integer or boolean).
Hint
The binary left shift operator is implemented by ll.ul4c.ShiftLeftAST
.
Binary right shift operator
The binary right shift operator >>
shifts the bits of its first operand (an
integer or boolean) to the right by the number of positions given by the second
operand (which must also be an integer or boolean).
Hint
The binary right shift operator is implemented by ll.ul4c.ShiftRightAST
.
Binary bitwise “and” operator
The bitwise and operator &
returns the bitwise “and” combination of its
operands (which must be integer or boolean values). E.g. 6 & 3
returns 2
.
As with the unary operator ~
, negative numbers are interpreted as having an
unlimited number of leading 1
bits.
Hint
The binary bitwise “and” operator is implemented by ll.ul4c.BitAndAST
.
Binary bitwise “exclusive or” operator
The bitwise exclusive or operator ^
returns the bitwise exclusive “or”
combination of its operands (which must be integer or boolean values).
E.g. 6 ^ 3
returns 5
.
Negative numbers are again interpreted as having an unlimited number of leading
1
bits.
Hint
The binary bitwise “exclusive or” operator is implemented by
ll.ul4c.BitXOrAST
.
Binary bitwise “inclusive or” operator
The bitwise inclusive or operator |
returns the bitwise inclusive “or”
combination of its operands (which must be integer or boolean values).
E.g. 6 | 3
returns 7
.
Negative numbers are again interpreted as having an unlimited number of leading
1
bits.
Hint
The binary bitwise “inclusive or” operator is implemented by
ll.ul4c.BitOrAST
.
Binary comparison operators
The comparison operators ==
, !=
, <
, <=
, >
and >=
compare
the value of the two operands. ==
and !=
support comparison of all
types of object. All others support comparison of “compatible” objects, which
means all “number” objects (integer, float and boolean) can be compared with
each other, all other objects can only be compared to objects of the same type.
Hint
These operators are implemented by ll.ul4c.EQAST
,
ll.ul4c.NEAST
, ll.ul4c.LTAST
, ll.ul4c.LEAST
,
ll.ul4c.GTAST
and ll.ul4c.GEAST
.
Identity comparison operators
The comparison operators is
and is not
test whether both operands refer
to the same object or not.
Note that the behaviour of these operators for “atomic” immutable objects (like integers, floats and strings) is implementation defined.
Hint
These operators are implemented by ll.ul4c.IsAST
and
ll.ul4c.IsNotAST
.
Containment tests
The in
operator
The in
operator tests whether the first operand is contained in the second
operand. In the expression a in b
the following type combinations are
supported:
string, string: Checks whether
a
is a substring ofb
.any object, list: Checks whether the object
a
is in the listb
(comparison is done by value not by identity)string, dict: Checks whether the key
a
is in the dictionaryb
. (Note that some implementations might support keys other than strings too. E.g. Python and Java do, Javascript does only forMap
objects.)
Hint
The in
operator is implemented by ll.ul4c.ContainsAST
.
The not in
operator
The not in
operator returns the inverted result of the in
operator, i.e.
it tests whether the first operand is not contained in the second operand.
Hint
The not in
operator is implemented by ll.ul4c.NotContainsAST
.
Boolean negation
The unary operator not
inverts the truth value of its operand. I.e.
not x
is True
for None
, False
, the undefined value, 0
,
0.0
, empty lists, strings, dictionaries and other empty containers and
False
for everything else.
Hint
The boolean negation operator is implemented by ll.ul4c.NotAST
.
Boolean “and” operator
The binary operator and
returns whether both of its operands are true.
It works like Python and
operator by short-circuiting operand evaluation,
i.e. if the result is clear from the first operand the seconds won’t be
evaluated.
Furthermore and
always return one of the operands.
So a and b
first evaluates a
; if a
is false, its value is returned;
otherwise, b
is evaluated and the resulting value is returned.
Hint
The boolean “and” operator is implemented by ll.ul4c.AndAST
.
Boolean “or” operator
The binary operator or
returns whether any of its operands is true. Like
and
evaluation is short-circuited and one of the operands is returned.
For example, the following code will output the data.title
object if it’s
true, else data.id
will be output:
<?printx data.title or data.id?>
Hint
The boolean “or” operator is implemented by ll.ul4c.OrAST
.
Conditional expression
The conditional expression (also called an “inline if”) a if c else b
first
evaluates the condition c
. If it is true a
is evaluated and returned
else b
is evaluated and returned.
Hint
The “inline if” operator is implemented by ll.ul4c.IfAST
.