Page 84 of 800 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.

### An example of a non-trivial macro

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
Fetching  base
Codifying base
Fetching  lgc
Codifying lgc
Parsing
Codifying
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.

 Page 84 of 800 Search logiweb.eu