Limitations of lexical variables
Factor handbook » The language » Lexical variables

Prev:Lexical variables and fry


There are two main limitations of the current implementation, and both concern macros.

Macro expansions with free variables
The expansion of a macro cannot reference lexical variables bound in the outer scope. For example, the following macro is invalid:
MACRO:: twice ( quot -- ) [ quot call quot call ] ;

The following is fine, though:
MACRO:: twice ( quot -- ) quot quot '[ @ @ ] ;


Static stack effect inference and macros
A macro will only expand at compile-time if all of its inputs are literal. Likewise, the word containing the macro will only have a static stack effect and compile successfully if the macro's inputs are literal. When lexical variables are used in a macro's literal arguments, there is an additional restriction: The literals must immediately precede the macro call lexically.

For example, all of the following three code snippets are superficially equivalent, but only the first will compile:
:: good-cond-usage ( a -- ... ) { { [ a 0 < ] [ ... ] } { [ a 0 > ] [ ... ] } { [ a 0 = ] [ ... ] } } cond ;

The next two snippets will not compile because the argument to cond does not immediately precede the call:
: my-cond ( alist -- ) cond ; inline :: bad-cond-usage ( a -- ... ) { { [ a 0 < ] [ ... ] } { [ a 0 > ] [ ... ] } { [ a 0 = ] [ ... ] } } my-cond ;

:: bad-cond-usage ( a -- ... ) { { [ a 0 < ] [ ... ] } { [ a 0 > ] [ ... ] } { [ a 0 = ] [ ... ] } } swap swap cond ;

The reason is that lexical variable references are rewritten into stack code at parse time, whereas macro expansion is performed later during compile time. To circumvent this problem, the macros.expander vocabulary is used to rewrite simple macro usages prior to lexical variable transformation. However, macros.expander cannot deal with more complicated cases where the literal inputs to the macro do not immediately precede the macro call in the source.