Pigeon Core - Variables

def

New variables are created by the def special form:

(def var)
(def var1 var2 var3)
(def (var value))
(def (var1 value1) (var2 value2))

If no value is given, the variable is initialised to undef: otherwise the value expression is used. The variable name is not yet visible during evaluation of the value, except for the special case where the value is a lambda expression, in which case the variable is available for binding as part of the resulting closure (handy when defining recursive functions).

If a def expression declares multiple variables, these are constructed from left to right. Each one is visible during initialisation of the next. Thus there is no difference between declaring several variables in a single def, or splitting this code across more than one expression.

Variable scopes are defined by the enclosing special form. Program forms (lambda, block, loop) create a regular scope. Conditional forms (if, and, or) create a null scope, in which it is illegal to declare variables (but you can always nest a block inside the conditional to reestablish a regular scope).

A def expression returns the value assigned to the last variable in the list.

set

To assign a new value to an existing variable, use the set special form:

(set var value)

A set expression returns the value that was assigned.

Move along folks, nothing more to see here!

In the full syntax, a=b translates into (set a b), while a:=b becomes (def (a b)).

But what about more interesting things, like assigning to an array subscript or message slot? set can only assign directly to a scoped variable, so any more sophisticated constructs must be implemented as a function call or message send.

The solution is a simple macro substitution. set is redefined as a macro that checks the type of its first parameter. If this is a regular symbol, the macro leaves the call unchanged, but if this is a list, it flattens out the contents of that list, and concatenates the first entry of the list onto the set token itself. For instance the expression object.table[23] = 'elf' would initially parse as:

(set (index: (table: object) 23) 'elf')

That is not a valid target for an assignment, but the macro will change it to:

(setindex: (table: object) 23 'elf')

which merely requires a suitable definition of the setindex message.

List unpacking assignments ([a b] = [b a]) are implemented in a similar way.