I've been thinking a lot about how PGE implements closures. Right
now, the closures are a bit rough -- PGE does heuristic look-ahead to
find the end of the closure, saves off the code as a string, and
compiles it at runtime like an eval. To make the heuristic look-
ahead work, PGE insists that closures must be bound by "{{...}}"
instead of "{...}" as Larry has specified. The problems are 1) you
don't find syntax errors at compile time, 2) you need a cache to keep
the compiler from being re-invoked after every match, 3) PIR is
implemented as a special case.
Patrick has mentioned several times that the proper solution to the
problem is a representation of the high-level language that PGE can
interact with. My thoughts about that HLL mapping:
1) we should invoke the other language's compiler at compile-time and
generate an anonymous PIR .sub
a) a special version of the compiler that just parses a block,
rather than a whole program (for Perl6 for example, I think the
distinction is irrelevant)
b) the returned PIR might have several subs. In this case, the
anonymous one will typically be short and will invoke the others
--> so there should be two return values: the library and the
entry point
2) the other language should be represented as an object which can:
a) parse a block
b) pre-process that block to insert boilerplate (see PIR_closure
in PGE::Perl6Regex today) for the anonymous entry point
I thought about co-opting the PGE :lang adverb, which is currently a
string representing the compreg name. If that were optionally a
PGE::HLLMapping instance, then we could conditionally invoke some of
the behavior described above.
Remaining questions:
1) what's the namespace of the generated code?
2) how do we handle languages where embedded code blocks are not
equivalent to whole programs? Do we subclass the grammar and redefine
TOP to be a statement block?
Chris