David Whipp wrote:
> But can I use a non-constant date?

You didn't show us the iso_date rule.

> Obviously we could put the onus on the module writer to write super-flexible
> rules/grammars. But will there be an easy way to force interpolative context
> onto this type of regex-valued subroutine arg?

With this rule you need literal numbers:

   rule iso_date { $year:=(\d{4}) -
                   $month:=(\d{2}) -
                   $day:=(\d{2}) }

This rule is more flexible:

   rule iso_date { (<Perl.term>) - { let $year := eval $1 }
                   (<Perl.term>) - { let $month := eval $2 }
                   (<Perl.term>)   { let $day := eval $3 }
                   <($year =~ /^\d{4}$/ &&
                     $month =~ /^\d{2}$/ &&
                     $day =~ /^\d{2}$/)> }

The eval is very restrictive though -- it forces the terms to
have values at compile time and breaks lexical scoping. (Unless
eval can play games with %MY and somehow evaluate in the
caller's scope. Maybe caller.{MY}.eval?)

We can tidy that up a little with another rule:

   rule value { <Perl.term>
                { let $0 := caller(2).{MY}.eval($term) } }

   rule iso_date { $year:=<value> -
                   $month:=<value> -
                   $day:=<value>
                   <($year =~ /^\d{4}$/ &&
                     $month =~ /^\d{2}$/ &&
                     $day =~ /^\d{2}$/)> }

There's still the compile-time value problem though.

What is really needed is something that converts the date syntax
to normal Perl code:

   rule iso_date { (<Perl.term>) -
                   (<Perl.term>) -
                   (<Perl.term>)
                   { use grammar Perl::AbstractSyntax;
                     $0 := (expr (invoke 'new (class 'Date) $1 $2 $3))) }

This rule just generates code -- the $0 return result is spliced
into the syntax tree at compile time. All the valid value checking
is done at run-time in the Date object constructor. (Or maybe at
compile time if the compiler can figure out there aren't any
side-effects and the object is serializable. But that's a whole
different thread.) It's very efficient because it only parses the
source code once. All the compiler optimizations (like constant
folding) get applied to your special syntax. But you're writing
Parrot macros (IMCC on steroids maybe?) and not Perl!

Another approach is to delay the final parse until run-time. In
this case, the compiler runs the rule over the input source
code and records the matched text, but without running any of the
code blocks. When the sub is called at run-time, the matched text
is parsed by the rule again, but this time with the code blocks
enabled. The second rule above (using eval) would work fine this
way (as long as the %MY games are possible). The down-side to
this approach is that you have lots of string evals happening
at run-time.

Maybe all of these techniques will be possible?

   rule x is macro { ... }
   rule y is delayed { ... }
   rule z is syntax { ... }

- Ken

Reply via email to