| Search internet |
During compilation, lgc(1) invokes user defined functions in four cases: when macro expanding, when verifying, when rendering, and when unpacking. All four are Turing complete. As an example, you can define arbitrarily complex rendering and not just rendering by substitution as was done for
and
. You can also define arbitrarily complex macros and not just substitution macros like
. As an example,
macro expands to
and similarly for arbitrarily long lists, and that requires more than simple substitution.
You may skip the following without loss of continuity.
Advanced macro expansion, verification, rendering, and unpacking is treated elsewhere, but as an appetizer, consider this definition of a macro for debugging macros:
01 ""P mdebug
02 ""R base
03 ""R lgc
04 ""D 0
05 mdebug ( " , " )
06 mdebug1 ( " )
07 ""B
08 page ( ""N , ""C )
09 title "A macro debug tool"
10 bib "@MISC{dummy}"
11 main text "
12 \begin{statements}
13 \item "[[ Macro define mdebug ( u , v ) as
14 \ x . mdebug1 ( x ) end define ]]"
15 \item "[[ eager define mdebug1 ( x ) as newline
16 let << t ,, s ,, c >> = x in newline
17 let << true ,, u ,, v >> = t in newline
18 let b _ { v } = quote v end quote :: v maptag in newline
19 let b _ { c } = quote c end quote :: c maptag in newline
20 let b = << b _ { v } ,, b _ { c } >> in newline
21 println ( "Hello 1" ) .then. newline
22 eval ( u , b , c ) untag .then. newline
23 println ( "Hello 2" ) .then. newline
24 stateexpand ( v , s , c ) end define ]]"
25 \item "[[ etst mdebug ( println ( !"Now expanding " ::
26 tree2vt ( v , c ) ) , << 1 ,, 2 >> ) ; 1 :: 2 :: <<>> end test ]]"
27 \end{statements}
28 \nocite{dummy}\color{white}\bibliography{./page}
29 "
30 appendix "
31 \begin{statements}
32 \item Nothing here
33 \end{statements}
34 "
35 end page
The source text above defines a construct
which evaluates
, discards the result, and then macro expands
. Thus,
is evaluated during macro expansion.
Lines 25-26 use the construct. The second argument of mdebug reads
which macro expands to
. During macro expansion, however, mdebug has the side effect that a println statement is executed.
The argument of println is constructed from the string 'Now expanding' and the return value from
. Inside the first argument of mdebug,
is bound to the second argument of mdebug and
is bound to the 'cache' of the mdebug page. That cache contains, among other, all definitions on the mdebug page and all its transitively referenced pages. The tree2vt function converts the term
into the lgs representation of
using the name definitions in
.
The mdebug macro is defined in Lines 13-14. When the macro engine encounters an instance of mdebug, it applies the right hand side of the macro definition of mdebug to a structure
which contains everything a macro expander needs. For the mdebug macro, this leads to invocation of
.
In Line 16 the mdebug1 function destructures
into a term
, a 'macro state'
, and a cache
. The term
is the term to be macro expanded and has mdebug as principal operator. The macro state indicates, among other, how subterms should be macro expanded. The cache
is the cache of the page on which the instance of mdebug occurs.
In Line 17 mdebug1 destructures the term
into the subterms
and
which are the first and second subterm, respectively, of the term to be macro expanded. Element number zero of
is a structure which represents the principal operator. Since we know it is mdebug we ignore it by inserting the constant
at that position.
In Line 22, mdebug1 computes the value of
and then discards the value. Thus, it only makes sense to do the evaluation if it has side effects such as a call to println. The computation is done by the eval function which takes three arguments: the term
to be evaluated, a list
of bindings from variables to values, and a cache
.
The eval function is eager but is capable of evaluating arbitrary lazy functions. To do so, it returns the result in maptagged form. Maptagged values are not evaluated before they are forced. The mdebug1 function uses untag to force evaluation of the return value from eval.
The list of variable bindings is constructed in Line 18-20. First, a binding from the variable
to the value of
is constructed. Then a binding from the variable
to the value of
. And finally the bindings are assembled into a list
of bindings.
The first binding is put in an indexed variable named
. Indexed variables can be indexed by arbitrary terms. Two indexed variables are identical if the indexes are identical. As an example,
and
are distinct variables because
and
are not identical. They are just equal, but not identical as terms.
Since eval is capable of working with arbitrary values, not just eager ones, the values included in binding lists must be maptagged. The value assigned to
is the pair
where
is a value which represent the term
and
is the value of
with a maptag on top.
In Line 24, mdebug1 macro expands
as specified in the macro state
. The macro state
typically specifies default macro expansion, but there are situations where one may need to macro expand some subterm in a special way.
If you store the source above to mdebug.lgs and does
> lgc mdebug.lgs
then the output will look like this:
GRD-2009-11-14.UTC:11:55:53.597378 Reading file:mdebug.lgs Fetching base Codifying base Fetching lgc Codifying lgc Parsing Codifying 1st reading 2nd reading Hello 1 Now expanding << 1 ,, 2 >> Hello 2 Rendering Verifying The page is correct Dumping to cache User rendering Goodbye
During first reading, lgc sees the definition of mdebug for the first time. That definition has effect from the second reading. Thus, you see output from mdebug during second but not during first reading. Had there been a third reading then you would also have seen output from mdebug during the third reading.
Note that there is no output from mdebug during verification. Macro expansion only occurs during the readings. At the time of verification, the macro expansion has finished.
| Search logiweb.eu |