1. Nodes
  2. Core node classes
    1. ##core#variable
    2. if
    3. quote
    4. let
    5. ##core#lambda
    6. set!
    7. ##core#undefined
    8. ##core#global-ref
    9. ##core#primitive
    10. ##core#inline
    11. ##core#inline_allocate
    12. ##core#inline_ref
    13. ##core#inline_update
    14. ##core#inline_loc_ref
    15. ##core#inline_loc_update
    16. ##core#call
    17. ##core#callunit
    18. ##core#switch
    19. ##core#cond
    20. ##core#recurse
    21. ##core#return
    22. ##core#direct_call
    23. ##core#direct_lambda
  3. Backend node classes
    1. ##core#bind
    2. ##core#closure
    3. ##core#box
    4. ##core#unbox
    5. ##core#ref
    6. ##core#update
    7. ##core#updatebox
    8. ##core#update_i
    9. ##core#updatebox_i
    10. ##core#call
    11. ##core#local
    12. ##core#setlocal
    13. ##core#global
    14. ##core#setglobal
    15. ##core#setglobal_i
    16. ##core#literal
    17. ##core#immediate
    18. ##core#proc
    19. ##core#recurse

Nodes

The node tree to represent a compiled program is described here. Each node has 3 slots: a class (a symbol that determines what type of operation is represented by this node), parameters (a list of node attributes specific to the node's class) and the subnodes (a list of child nodes) of the current node. These slots can directly be acccessed in compiler extensions with the following procedures:

 (node? X)
 (make-node CLASS PARAMETERS SUBNODES)
 (node-class NODE)
 (node-parameters NODE)
 (node-subnodes NODE)

Note that these procedures are not qualified with the ##compiler# prefix.

Core node classes

These node classes are valid in the core language, the program tree right after macro-expansion. In the following descriptions, node classes are listed in the format

 [node] <class-name> {<parameter1> ...} <sub-node> ...

where {...} represents the list stored in the parameters slot of the node. If the parameters are not used, the braces are omitted. Optional parts are enclosed in square backets ([...]):

##core#variable

 [node] ##core#variable {<variable>}

A global or lexical variable reference. The parameter is a symbol naming the variable, possibly alpha-converted (renamed).

if

 [node] if <exp> <exp> <exp>

The usual if conditional, with the test, consequent and alternative parts as subnodes.

quote

 [node] quote {<literal>}

Any literal. Unquoted literals in the program code are automatically converted to quote nodes.

let

 [node] let {<variable>} <exp-v> <exp>

A lexical binding, always for a single variable only. Multiple bindings are transformed into nested let nodes (alpha-conversion will have taken care of re-bindings). <exp-v> is the value to which the variable is bound, <exp> is the body of the binding.

##core#lambda

 [node] ##core#lambda {<id> <mode> (<variable>... [. <variable>]) <size>} <exp>

A procedure. The parameter list holds the procedure id, the mode (a flag indicating whether this is an internal lambda, i.e. a procedure introduced via CPS conversion), the argument list (or signature) and the size (a simplistically computed number giving an estimate of a procedures size). The subnode holds the body of the procedure.

set!

 [node] set! {<variable>} <exp>

An assignment. Note that letrec is transformed by the compiler into let and set! forms.

##core#undefined

 [node] ##core#undefined {}

An undefined value. Not void, but really undefined as in "has no value (yet)", but this means void in most cases (but not in all).

##core#global-ref

 [node] ##core#global-ref {<variable>}

A global variable reference. This is used internally by tinyclos.

##core#primitive

 [node] ##core#primitive {<name>}

A primitive procedure. <name> is a string (or symbol) naming a C function with CPS calling convention.

##core#inline

 [node] ##core#inline {<op>} <exp>...

Calls the C expression <op> in operator position (so it may be a C function name, or something that can be called) with the given arguments (which are unconverted and passed directly to the function). The result should also be a Scheme data object.

##core#inline_allocate

 [node] ##core#inline_allocate {<op> <words>} <exp>...

Identical to ##core#inline, but also adds <words> (an integer) to the number of words that have to be allocated in the procedure that holds this form since all data allocations in a single generated C function are coalesced into one allocation request).

##core#inline_ref

 [node] ##core#inline_ref {<name> <type>}

Reference to a C variable or rvalue of the given type (which should be a usual FFI foreign type specifier).

##core#inline_update

 [node] ##core#inline_update {<name> <type>} <exp>

Assignment to a C variable or lvalue.

##core#inline_loc_ref

 [node] ##core#inline_loc_ref {<type>} <exp>

A reference to a pointer (represented by <exp>> which is internally a byte-vector) to data of the given foreign type.

##core#inline_loc_update

 [node] ##core#inline_loc_update {<type>} <exp> <exp>

An assignment to a typed pointer value.

##core#call

 [node] ##core#call {<safe-flag> [<debug-info>]} <exp-f> <exp>...

Calls a procedure (<exp-f>) with the given arguments. The parameter list holds a flag (wether the operator should be checked for being a procedure) and some optional debugging information (which will be used in the trace buffer).

##core#callunit

 [node] ##core#callunit {<unitname>} <exp>...

Calls a library unit, which means the library has been used through a (declare (uses ...)) declaration. This is basically like a zero-argument procedure call (the arguments are not used, in fact).

##core#switch

 [node] ##core#switch {<count>} <exp> <const1> <body1> ... <defaultbody>

A different form of conditional that can be translated into C switch statement. <count> gives the number of cases, <exp> is the expression to test, and the subnodes consist of alternating pairs of constant s and "case" bodies followed by a final expression that is evaluated when no case matched.

##core#cond

 [node] ##core#cond <exp> <exp> <exp>

An alternative conditional that will generate code using the C ?: operator.

##core#recurse

 [node] ##core#recurse {<tail-flag>} <exp1> ...

A self-recursive call to the procedure containing this node, optionally a tail call (determined by the tail flag).

##core#return

 [node] ##core#return <exp>

Return from the containing procedure. This is used in procedures that can be optimized to direct leaf routines.

##core#direct_call

 [node] ##core#direct_call {<safe-flag> <debug-info> <call-id> <words>} <exp-f> <exp>...

A "direct" call to a leaf procedure, with parameters specifying whether the call is safe (needs no check), debug info, the called procedure-id and the number of words allocated (this is needed to pre-allocate storage needed in the direct procedure).

##core#direct_lambda

 [node] ##core#direct_lambda {<id> <mode> (<variable>... [. <variable>]) <size>} <exp>

A "direct" leaf procedure. Otherwise the same as ##core#lambda.

Backend node classes

The following node classes are finally converted to C by the code generator. The compiled program is first translated into the core language node tree and then iteratively re-written by optimization- and preparation passes, which will introduce occurrences of the node classes described here. Note that the transformed program, when passed to the code-generator, may only use backend node classes, not core language node classes.

The node classes if, ##core#undefined, ##core#inline, ##core#inline, ##core#inline_allocate, ##core#inline_ref, ##core#inline_update, ##core#inline_loc_ref, ##core#inline_loc_update, ##core#return, ##core#direct_call and ##core#callunit are identical in their meaning as in the core language.

Additional node classes are:

##core#bind

 [node] ##core#bind {<count>} <exp-v>... <exp>

The low-level form of lt: bind <count> temporary variables to <exp-v> ... and evaluate <exp> (at this stage local variables have no names anymore).

##core#closure

 [node] ##core#closure {<count>} <exp>...

Creates a closure with <count> slots, filled with the results of evaluating <exp>....

##core#box

 [node] ##core#box {} <exp>

Creates a box (a vector of size 1) holding an assigned lexical variable.

##core#unbox

 [node] ##core#unbox {} <exp>

Extracts the value from a box.

##core#ref

 [node] ##core#ref {<index>} <exp>

Extracts a slot from a vector-like object <exp> at the given index.

##core#update

 [node] ##core#update {<index>} <exp1> <exp2>

Mutates the slot at the given index of the vector-like object <exp1> with the value of <exp2>.

##core#updatebox

 [node] ##core#updatebox {} <exp1> <exp2>

Mutates the value stored in the box in <exp1> with the result of <exp2>.

##core#update_i

 [node] ##core#update_i {<index>} <exp1> <exp2>

Updates a slot with an immediate value. This is faster than the normal update since that doesn't require remembering the mutation to make the generational garbage collector work.

##core#updatebox_i

 [node] ##core#updatebox_i {} <exp1> <exp2>

Update a box with an immediate value.

##core#call

 [node] ##core#call {<safe-flag> [<debug-info> [<call-id> <customizable-flag>]]} <exp-f> <exp>...

Call a procedure. This is roughly equivalent to the core language ##core#call, but holds additional information obtained from optimization passes.

##core#local

 [node] ##core#local {<index>}

Access the local (temporary) variable at the given index.

##core#setlocal

 [node] ##core#setlocal {<index>} <exp>

Update a local variable.

##core#global

 [node] ##core#global {<literal> <safe-flag> <block-mode> [<name>]}

Access a global variable. Globals are implemented as slots in symbols (similar to classical Lisp dialects). Additional flags in the parameter list are used for generating faster code by omitting checks.

##core#setglobal

 [node] ##core#setglobal {<literal> <block-mode>} <exp>

Update a global variable.

##core#setglobal_i

 [node] ##core#setglobal_i {<literal> <block-mode>} <exp>

Update a global variable with an immediate value.

##core#literal

 [node] ##core#literal {<literal>}

Access a literal (similar to quote nodes).

##core#immediate

 [node] ##core#immediate {<type> [<literal>]}]     

Return an immediate literal of the given type (which can be one of the symbols bool, fix, nil and char).

##core#proc

 [node] ##core#proc {<name> [<non-internal>]}

Represents the code-pointer of a procedure (the actual closure is created by ##core#closure).

##core#recurse

 [node] ##core#recurse {<tail-flag> <call-id>} <exp1> ...

The same as in the core language, but with the id of the called procedure.