Syntax - nchauhan890/leaf-language GitHub Wiki

Syntax

This section describes the syntax rules for Leaf

Numbers

The syntax for numbers only accepts integers, and numbers with a deciaml point. Possible number forms:

>>> 123
123

>>> 12.3
12.3

>>> 123.
123

>>> 123.0
123.0

Strings

Strings are enclosed in single quotes ('') and single quotes may not be escaped, however, newline characters may be used with \n. A newline character can be escaped by using a double backslash \\n. Strings implicitly continue on newlines, however the newline character is ignored Examples of strings:

>>> 'Hello world!'
Hello world!

>>> 'First line\nSecond line'
First line
Second line

>>> 'First line\\nStill on the first line'
First line\nStill on the first line

>>> 'First line
Also the first line'
First lineAlso the first line

Lists

Lists are denoted by square brackets, which may contain a number of expressions which are separated by commas:

>>> [1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]

>>> [String, 1 + 1, true]
[<type String from built-ins>, 2, true]

Assignments

Assignments use the assignment operator << and support multiple assignments:

str << 'hello world'

str, decimal, int << 'leaf', 4.53, 86

In a multiple assignment, there must be the same number of target names as objects (Note that this isn't always true - i.e. when using iterable unpacking).

Function calls

Function calls use the function name followed by an opening square bracket, function arguments, modifiers/flags and a closing square bracket.

Modifiers begin with a tilde (~), the modifier name, an assignment operator and an expression. Flags begin with a tilde also, but only have the flag name afterwards. Possible function calls:

>>> show[1, 2, 3 ~end << '' ~comma_sep]
1, 2, 3>>>

>>> show[]
>>>

>>> show[1]
1

>>> show[~no_newline]
>>>

>>> show[~end << 'END']
>>>

Booleans

Leaf support the boolean values true and false. They have a respective value of 1 and 0 and function similarly to these numbers in arithmetic since they derive Number. They must be written in lowercase only in code and display with their corresponding name.

Indentation

Indentation is denoted by the pipe character (|). It is used in conditionals, loops and function definitions Each new level of indentation must have the appropriate number of indentation characters. Indentation characters do not need to be written next to each other; they can be written spaced out to ease readability like the following:

if[a <= 10],then
|    show[a, 'is less than or equal to 10;' ~ end << ' ']
|    if [a = 5], then
|    |    show[a, 'is equal to 5;' ~ end << ' ']
|    |    if [a > 0], then
|    |    |    show[a, 'is more than 0;' ~ end << ' ']
|    |    endif
|    endif
endif

Each level of indentation usually ends with a keyword like endif to denote the end of the current indentation level.

If statements

If statements use the if, then, else and endif keywords. The expression, denoted by expr is evalutated to its boolean value and the body under each section of the if statement must be indented. Possible if statement forms:

if [expr], then
| ...
endif
if [expr], then
| ...
else, if [expr], then
| ...
endif
if [expr], then
| ...
else
| ...
endif
if [expr], then
| ...
else, if [expr], then
| ...
else
| ...
endif

If statements can contain a variable number of else, if clauses in them. Nested if statements must be indented the appropriate number of indentation characters.

While/Until loops

While and until loops use the while, until, loop and endloop. They continously loop until the condition specified at the top is either true or false: while loops repeat until false and until loops repeat until true. The syntax for while and untils loops are as follows:

while [expr_is_true], loop
| ...
endloop
until [expr_is_false], loop
| ...
endloop

For loops

For loops use the for, in, loop and endloop keywords. They iterate over any iterable and set the value of the variable(s) specified to the next value in the iterable on each iteration. This is the syntax for for loops:

for [item] in [iterable], loop
| ... (use 'item' here)
endloop

Loop Control

There are 2 ways that loops can be controlled: the break and next statements. The break statement ends the loop from inside it - this may occur when it is triggered by an if statement. The next statement starts the next repetition of the loop - in a for loop, it causes the for loop's variables to obtain their next values.

They are used as stand-alone statements and cannot appear within expressions. Note that an error will be raised if either are used outside of a loop context

Iterable unpacking

Iterable unpacking is a way to obtain each item in an iterable in a List. The syntax used is a colon (:). This can be useful in the following situations:

For loops:

In a for loop, if you need to split each item into separate variables, iterable unpacking can be used in the for loop's definition. Consider the following:

grid = ['A1', 'A2', 'B1', 'B2']
for [row, col] in [:grid], loop
| show['row:', row, 'col:', col]
endloop

This outputs:

row: A col: 2
row: B col: 1
row: B col: 2

This can only be obtained using iterable unpacking - however, a problem here is that there must be a constant number of items to unpack in each cycle returned by the iterable otherwise an error will be raised

Function calls:

When calling functions, iterables can be used as separate arguments like so:

>>> values << [1, 2, 3]
>>> show['hey', :values]
hey 1 2 3

Multiple assignments:

This can be used to get around the limitation of same-number unpacking in for loops. Unpacking can occur on either the left or right side of the assignment and each variation performs a different function:

>>> a, b, c << :[1, 2], 3
>>> show[a, b, c]
1 2 3
>>> first, :last << :[1, 2], 3, [4, 5]
>>> first
1
>>> last
[2, 3, 4, 5]