in reply to Re^4: hrm, Eval::Compile
in thread hrm, Eval::Compile

Ok... here is an example, I haven't used this technique for a while but it has been useful before.

<refas tag="foo">/path/to/bar.xml</refas>

Where bar is an xml file containing some values, and refas creates a new plugin on the fly called foo, which substitutes any foo tags it finds in the document with the values they specify, adds it to the command list and restarts the parser.

Once that command is triggered, anywhere in the document that the tag <foo>x</foo> or <foo>y</foo> exists get substituted for the values contained in foo : <y>somevalue</y>, <x>somevalue</x>.

The <SQL tag supports a refas mode which uses the columns of the database for the key.

Another example is that it is possible to build tags on the fly for example :

<<qd>gettype</qd>> somedata </<qd>gettype</qd>>

Where gettype can be either html or xml, giving either:

<html> somedata </html> or <xml> somedata </xml>

If you can't determine ahead of time what a given tag actually means because it's meaning might be changed at runtime by another tag which branches on the request data, how can you compile it?

Replies are listed 'Best First'.
Re^6: hrm, Eval::Compile
by Corion (Patriarch) on Jul 20, 2011 at 13:56 UTC

    The trick is to delay the decision and to compile code for "both" (resp. all) possibilities. See this Perl code:

    #!perl -w use strict; sub do_foo { print "Foo with $_[0]"; }; sub do_bar { print "Bar with $_[0]"; }; my %dispatch = ( foo => \&do_foo, bar => \&do_bar, ); my $method = rand > 0.5 ? 'foo' : 'bar'; $dispatch{ $method }->('Test');

    This code does not know whether $method will contain foo or bar but it can run the code for either subroutine.

    This technique of calling code through subroutine references is discussed and widely employed in Higher Order Perl.

Re^6: hrm, Eval::Compile
by Anonymous Monk on Jul 20, 2011 at 22:47 UTC
    Like Corion said, the key to implementing this design is delay :) Perl does it
    $ perl -c -e " foo(1); " -e syntax OK
    Even though foo() isn't defined yet, perl recognizes it as a function yet to be defined by the syntax(like your tags), so it holds off reporting an error as long as possible (runtime, when it tries to call it)
    $ perl -e " foo(1); " Undefined subroutine &main::foo called at -e line 1.

    H.O.P is all about this approach, build a tree, walk the tree, modify the tree, compute

    The computable things are defined by syntax < >  [ ]  ( ), whether they'll actually compute or be returned verbatim is delayed until runtime

    Like perl, TT2 takes the approach that if its not computable, its an error, not a string substitution

    Your blind spot seems to be your current implementation -- you keep thinking in terms of substitution s/// instead of function/method calls -- even s/// is not really substitutions, its a series of function/method calls -- each call to s/// is a walk of the tree (flat tree, a string)

      Oh how I wish I was a 17 year old whizz kid again... I'd have it coded up in no time. At 31 I feel 900 years old, burnt out, clapped out, one foot in the grave, someone please do me a favour and shoot me in the head.

      Ok, at the risk of really dumb, (like I haven't already), how do I build said "tree". I get what it is conceptually, but I'm thinking like a multi-level hash table solution? Is that a million miles from the answer?

      Oh how easy using n-dimensional arrays and fixed point math to do 3d graphics was back in the day... lol

        I get what it is conceptually, but I'm thinking like a multi-level hash table solution?

        Yes, you could uses Hash of Hashes. H.O.P chose Array of Arrays because arrays are already ordered and perl is very good at manipulating lists and arrays; you should chose AoA so you can leverage H.O.P. , HOP::Lexer, HOP::Parser