23.11.2014 Views

2006 Scheme and Functional Programming Papers, University of

2006 Scheme and Functional Programming Papers, University of

2006 Scheme and Functional Programming Papers, University of

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

exp<strong>and</strong>-term(term, env, phase) =<br />

emit-event("visit", term)<br />

case term <strong>of</strong><br />

(kw . _)<br />

where lookup(resolve(kw), env, phase)<br />

= ("macro", transformer)<br />

=> emit-event("enter-macro", term)<br />

let M = fresh-mark<br />

let term/M = mark(term, M)<br />

emit-event("macro-pre", term/M)<br />

let term2/M = transformer(term/M)<br />

emit-event("macro-post", term/M)<br />

let term2 = mark(term2/M, M)<br />

emit-event("exit-macro", term2)<br />

return exp<strong>and</strong>-term(term2, env, phase)<br />

(kw . _)<br />

where lookup(resolve(kw), env, phase)<br />

= ("primitive", exp<strong>and</strong>er)<br />

=> emit-event("enter-primitive", term)<br />

let term2 = exp<strong>and</strong>er(term, env, phase)<br />

emit-event("exit-primitive", term2)<br />

emit-event("return", term2)<br />

return term2<br />

id<br />

where lookup(resolve(id), env, phase)<br />

= "variable"<br />

=> emit-event("enter-primitive", id)<br />

let term2 = exp<strong>and</strong>-variable(id, env, phase)<br />

emit-event("exit-primitive", term2)<br />

emit-event("return", term2)<br />

return term2<br />

else<br />

=> raise syntax error<br />

Figure 5. Expansion function<br />

Recall the inference rules from Fig. 2 <strong>and</strong> Fig. 3. The corresponding<br />

derivation structures contain essentially the same information<br />

in a different form. The first two fields <strong>of</strong> all derivation variants<br />

are the terms before <strong>and</strong> after expansion. The remaining fields<br />

are specific to the variant. In the mrule variant, the remaining field<br />

contains the derivation <strong>of</strong> the macro’s result. In the lambda variant,<br />

the third field contains the new formal parameters <strong>and</strong> body expression<br />

after renaming, <strong>and</strong> the final field contains the derivation that<br />

represents the expansion <strong>of</strong> the renamed body expression. In the if<br />

variant, the three additional fields are the derivations for the three<br />

if subexpressions. The phase <strong>and</strong> environment parameters are not<br />

stored explicitly in the derivation structures, but they can be reconstructed<br />

for any subderivation from its context.<br />

Creating structured data from unstructured sequences is a parsing<br />

problem. By inspecting the order <strong>of</strong> calls to emit-event, recursive<br />

calls to exp<strong>and</strong>-term, <strong>and</strong> calls to other auxiliary functions,<br />

it is possible to specify a grammar that describes the language<br />

<strong>of</strong> event streams from the instrumented exp<strong>and</strong>er. Figure 9<br />

shows such a grammar. By convention, non-terminal names start<br />

with upper-case letters <strong>and</strong> terminal names start with lower-case<br />

letters.<br />

The Exp<strong>and</strong>Term non-terminal describes the events generated<br />

by the exp<strong>and</strong>-term function (Fig. 5) in exp<strong>and</strong>ing a term, whether<br />

it is the full program or a subterm. It has two variants: one for<br />

macros <strong>and</strong> one for primitive syntax. The Primitive non-terminal<br />

has a variant for each primitive syntactic form, <strong>and</strong> the productions<br />

exp<strong>and</strong>-prim-lambda(term, env, phase) =<br />

emit-event("primitive-lambda")<br />

case term <strong>of</strong><br />

(kw formals body)<br />

where formals is a list <strong>of</strong> identifiers<br />

=> let formals2 = freshnames(formals)<br />

let env2 =<br />

extend-env(env, formals, "variable", phase)<br />

let body2 = rename(body, formals, formals2)<br />

emit-event("rename", formals2, body2)<br />

let body3 = exp<strong>and</strong>-term(body2, env2)<br />

return (kw formals2 body3)<br />

else => raise syntax error<br />

exp<strong>and</strong>-prim-if(term, env, phase) =<br />

emit-event("primitive-if")<br />

case term <strong>of</strong><br />

(if test-term then-term else-term)<br />

=> emit-event("next")<br />

let test-term2 = exp<strong>and</strong>-term(test-term, env)<br />

emit-event("next")<br />

let then-term2 = exp<strong>and</strong>-term(then-term, env)<br />

emit-event("next")<br />

let else-term2 = exp<strong>and</strong>-term(else-term, env)<br />

return (kw test-term2 then-term2 else-term2)<br />

else => raise syntax error<br />

exp<strong>and</strong>-variable(id, env, phase) =<br />

let id2 = resolve(id)<br />

emit-event("variable", id2)<br />

return id2<br />

exp<strong>and</strong>-primitive-let-syntax(term, env, phase)<br />

emit-event("primitive-let-syntax", term)<br />

case term <strong>of</strong><br />

(kw ([lhs rhs] ...) body)<br />

where each lhs is a distinct identifier<br />

=> let lhss = (lhs ...)<br />

let rhss = (rhs ...)<br />

let lhss2 = freshnames(lhss)<br />

let body2 = rename(body, lhss, lhss2)<br />

emit-event("rename", lhss2 body2)<br />

let rhss2 =<br />

for each rhs in rhss:<br />

emit-event("next")<br />

exp<strong>and</strong>-term(rhs, env, phase+1)<br />

let transformers =<br />

for each rhs2 in rhss2:<br />

eval(rhs2, env)<br />

emit-event("next-part")<br />

let env2 =<br />

extend-env(env, lhss2, transformers, phase)<br />

let body3 = exp<strong>and</strong>-term(body2, env2, phase)<br />

return body3<br />

else => raise syntax error<br />

Figure 6. Expansion functions for primitives <strong>and</strong> macros<br />

22 <strong>Scheme</strong> <strong>and</strong> <strong>Functional</strong> <strong>Programming</strong>, <strong>2006</strong>

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!