Skip to content

Basic Constructs

Giancarlo Niccolai edited this page Jul 10, 2018 · 4 revisions

Declaring a Variable

a = 1
name = "Hello world"
vector = [1 2 3 "a" "b", "c"] // separators are optional
dictionary = [ 
    1 => "a"
    "b" => 2 ,  // separators are optional
    3 => "c"
]

Simple Expressions

1 + 1     // evaluates to 2
a = 1 + b // assignment from expression
{1+1}     // evaluates to 2
a = {1+b} // same as "a = 1+b"
a = {
    printl("hello")   // evaluates everything, and the final value...
    1+b               // ... is the result of the last evaluation.
}

Scoping

a = 1
b = 2
{   // creates a scope
    a = 100         // accesses outer a
    my b = 101      // local view of b
    c = 4           // creates c
    my d = 5        // creates d locally
    print(a, b, c, d)  All variables are defined
}

// Outside the scope, a was overwritten and c is created anew.
print(a, b, c)  // a=100, b=2, c=4, d is undefined.

Standard functions and reflection

All Falcon2 expressions are grammar sugar for an underlying function. They appear as a reflection form of the relative grammar construct, but actually the translation from the construct syntax into the functional form happens before the actual compilation step takes place.

Standard functions are in the standard namespace; this means they are directly accessible, as symbols visible from the outer program scope. For example, print and printl are standard functions to send textual output to the program standard output, and they can be accessed directly throughout the program. However, most functions have the same name as their grammar construct counterpart, (for example while or if); to identify them, the namespace accessor : (colon) can be used.

For example, print and :print are equivalent, the second specifying that the print symbol is to be accessed from the standard namespace.

While syntactic-equivalent functions, s let and run have no syntactic grammar construct masking their name, using the : namespace indicator to identify them is considered good practice.

For example:

a = 1+1     // --> :let(a, :+(1,1))

{
    print("hello")
    print("world")
}                    // --> :run(print("hello"), print("world"))

inc = {(a) 1+a}      // --> :let(inc, :expr(:params(a), :+(1,a))

function NAME {(p0, p1)[c0=0, c1=0] 
    c1 = c0+c1
    c0 = p0+p1
} 
// --> :let(NAME, :function(NAME, :params(p0,p1), :close(c0, c1), 
//          :run(:let(c1, :+(c0,c1) ), :let(c0, :+(p0,p1)))
//          ))

Flow control -- if

The if construct, and the relative :if function conditionally evaluate an expression when a control expression (called check) evaluates as true. Optionally, an expression to be evaluated when the check is false can be provided.

if exprCheck 
   exprIfTrue 
else 
   exprIfFalse

Which expands in the functional form: :if( &exprCheck, &exprIfTrue, &exprIfFalse={})

Multiple expressions can be evaluated using {} / :run():

if check {
    printl("is true")
    a = 0
}
else :run(
    printl("is false")
    a = 1
)

Notice that newline is considered a simple separator, so the if construct can be expressed as if exprCheck exprIfTrue else exprIfFalse, or if exprCheckk, exprIfTrue, else exprIfFalse; to avoid ambiguity.

The result of the if expression/function is the result of the evaluation of the selected branch (or false, if the check evaluates to false and the exprIfFalse branch is not given).

For example:

a = 10; b = 20
printl(if a < b "A is greater" else "B is greater")  // prints "B is greater"

Flow control -- While

The while construct repeats the evaluation of an expression as long as a check evaluates to true. It is defined as while check expression, or :while(&check, &expression).

For example:

a = 10
while a > 0 {
    printl(a)
    a -= 1
}

The break expr statement (or :break(expr) function) exits the loop, while the continue statement (or :continue() function) repeats the check.

The while expression/function evaluates to false, or to the value of the break expression if the loop exits through a :break(). For example:

ck = [5 3 2 6 9]
a = 5
printl( while a > 0 {
   printl( ck[a] )
   if ck[a] < 3 break "Limit reached"
   a -= 1
   })

To have a definite value out of the while expression, set the check as true and exit the loop using break only.

Flow control -- for/in

The for/in loop repeats a set of expressions while a seqExpr expression produces a sequence. It's grammar form is:

for seqExpr
    bodyExpr
    forfirst ffExpr
    formiddle fmExpr
    forlast flExpr

and function form is :for(&seqExpr, &bodyExpr, &first={}, &last={}, &middle={}).

The seqExpr is an expression that should set local variables referenced by the other expressions in the for evaluation. The seqExpr will be repeatedly evaluated until yielding a final result. For example:

for a = nextItem()
   printl(a)

The in expression (or :in() function) iterates over a sequence:

for a in [1 2 3] 
   printl(a)     // prints 1, 2 and 3

and the range(begin, end, step=0) function provides a way to generate a sequence of integer numbers between begin and end with an optional step:

for a in :range(0, 10, 3) 
   printl(a)     // prints 0, 3, 6 and 9

The ffExpr (or first parameter) if present, it's evaluated before the first body is processed. The fmExpr (or middle parameter) is evaluated after each bodyExpr evaluation except for the last one, and flExpr (or last parameter) is evaluated after the last body evaluation. For example:

:for( a in :range(0,10,3),
    print(a) 
    first: print("Numbers: ")
    middle: print(", ")
    last: printl(".")
)  
// prints "Numbers: 0, 3, 6, 9."

The continue expression/function will re-evaluate the seqExpr, skipping the rest of the expressions to be evaluated (i.e. middle or last), while break or :break(value) will exit the loop immediately.

The value of the for expression/:for function is the value of the last evaluation of seqExpr, or the value set in :break(value) if the loop is so terminated.