Author: pmichaud
Date: Fri Mar 17 16:48:00 2006
New Revision: 11921

Modified:
   trunk/compilers/pge/PGE/Exp.pir
   trunk/compilers/pge/PGE/Match.pir
   trunk/compilers/pge/PGE/P6Rule.pir
   trunk/t/compilers/pge/p6rules/closure.t

Log:
Added "return value" capability for embedded closures in p6 rules.


Modified: trunk/compilers/pge/PGE/Exp.pir
==============================================================================
--- trunk/compilers/pge/PGE/Exp.pir     (original)
+++ trunk/compilers/pge/PGE/Exp.pir     Fri Mar 17 16:48:00 2006
@@ -1192,8 +1192,13 @@
     emit(code, "  %s_1:", label)
     emit(code, "    $P1 = $P0[$S0]")
     emit(code, "    mpos = pos")
-    emit(code, "    $P1(mob)")
-    emit(code, "    goto %s", next)
+    emit(code, "    ($P0 :optional, $I0 :opt_flag) = $P1(mob)")
+    emit(code, "    if $I0 == 0 goto %s", next)
+    emit(code, "    setattribute mob, \"PGE::Match\\x0$!return\", $P0")
+    self.emitsub(code, "succeed", "pos")
+    emit(code, "    null $P0")
+    emit(code, "    setattribute mob, \"PGE::Match\\x0$!return\", $P0")
+    emit(code, "    goto fail")
     .return ()
 .end
 

Modified: trunk/compilers/pge/PGE/Match.pir
==============================================================================
--- trunk/compilers/pge/PGE/Match.pir   (original)
+++ trunk/compilers/pge/PGE/Match.pir   Fri Mar 17 16:48:00 2006
@@ -19,6 +19,7 @@
     addattribute base, "$.pos"                     # current match position
     addattribute base, "&!corou"                   # match's corou
     addattribute base, "@!capt"                    # subpattern captures
+    addattribute base, "$!return"                  # return value
     .return ()
 .end
 
@@ -132,6 +133,44 @@
     .return (to)
 .end
 
+=item C<substring()>
+
+Returns the portion of the target string matched by this object.
+
+=cut
+
+.sub "substr" :method
+    $P0 = getattribute self, "PGE::Match\x0$.target"
+    $P1 = getattribute self, "PGE::Match\x0$.from"
+    $P2 = getattribute self, "PGE::Match\x0$.pos"
+    if $P2 < 0 goto false
+    if $P2 <= $P1 goto false
+    $I1 = $P1
+    $I2 = $P2
+    $I2 -= $I1
+    $S1 = substr $P0, $I1, $I2
+    .return ($S1)
+  false:
+    .return ("")
+.end
+
+=item C<value()>
+
+Returns the "return value" for the match object.  If no return value has
+been explicitly set (by an embedded closure), return the substring
+that was matched by this match object.
+
+=cut
+
+.sub "value" :method
+    $P0 = getattribute self, "PGE::Match\x0$!return"
+    if_null $P0, value_1
+    .return ($P0)
+  value_1:
+    $S0 = self."substr"()
+    .return ($S0)
+.end
+
 =item C<__get_bool()>
 
 Returns 1 if this object successfully matched the target string,
@@ -153,8 +192,7 @@
 =cut
 
 .sub "__get_integer" :method
-    $S0 = self
-    $I0 = $S0
+    $I0 = self."value"()
     .return ($I0)
 .end
 
@@ -165,8 +203,7 @@
 =cut
 
 .sub "__get_number" :method
-    $S0 = self
-    $N0 = $S0
+    $N0 = self."value"()
     .return ($N0)
 .end
 
@@ -177,18 +214,8 @@
 =cut
 
 .sub "__get_string" :method
-    $P0 = getattribute self, "PGE::Match\x0$.target"
-    $P1 = getattribute self, "PGE::Match\x0$.from"
-    $P2 = getattribute self, "PGE::Match\x0$.pos"
-    if $P2 < 0 goto false
-    if $P2 <= $P1 goto false
-    $I1 = $P1
-    $I2 = $P2
-    $I2 -= $I1
-    $S1 = substr $P0, $I1, $I2
-    .return ($S1)
-  false:
-    .return ("")
+    $S0 = self."value"()
+    .return ($S0)
 .end
 
 =item C<__get_string_keyed_int(int key)>

Modified: trunk/compilers/pge/PGE/P6Rule.pir
==============================================================================
--- trunk/compilers/pge/PGE/P6Rule.pir  (original)
+++ trunk/compilers/pge/PGE/P6Rule.pir  Fri Mar 17 16:48:00 2006
@@ -83,6 +83,12 @@
     $P0["n"] = unicode:"\x0a\x0d\x0c\x85\u2028\u2029"
     # See http://www.unicode.org/Public/UNIDATA/PropList.txt for above
 
+    # Create and store closure preprocessors in %closure_pp
+    $P0 = new Hash
+    store_global "PGE::P6Rule", "%closure_pp", $P0
+    $P1 = find_global "PGE::P6Rule", "PIR_closure"
+    $P0["PIR"] = $P1
+
     $P0 = find_global "PGE", "p6rule"
     compreg "PGE::P6Rule", $P0
 .end
@@ -951,15 +957,39 @@
 
 .sub "p6analyze" :method
     .param pmc pad
-    $S0 = pad[":lang"]
-    self["lang"] = $S0
-    if $S0 != "PIR" goto end
+    .local string lang
+    .local pmc closure_pp
+    .local pmc closure_fn
+    lang = pad[":lang"]
+    self["lang"] = lang
+    # see if we need to do any pre-processing of the closure
+    closure_pp = find_global "PGE::P6Rule", "%closure_pp"
+    $I0 = defined closure_pp[lang]
+    if $I0 == 0 goto end
+    closure_fn = closure_pp[lang]
     $S1 = self["value"]
-    $I0 = index $S1, ".sub"
-    if $I0 >= 0 goto end
-    $S1 = concat ".sub anon :anon\n.param pmc match\n", $S1
-    $S1 .= "\n.end\n"
+    $S1 = closure_fn($S1)
     self["value"] = $S1
   end:
     .return (self)
 .end
+
+=item C<PIR_closure(string code)>
+
+This helper function helps with :lang(PIR) closures in rules
+by adding a ".sub" wrapper around the code if one isn't 
+already present.
+
+=cut
+
+.namespace [ "PGE::P6Rule" ]
+
+.sub "PIR_closure"
+    .param string code
+    $I0 = index code, ".sub"
+    if $I0 >= 0 goto end
+    code = concat ".sub anon :anon\n.param pmc match\n", code
+    code .= "\n.end\n"
+  end:
+    .return (code)
+.end

Modified: trunk/t/compilers/pge/p6rules/closure.t
==============================================================================
--- trunk/t/compilers/pge/p6rules/closure.t     (original)
+++ trunk/t/compilers/pge/p6rules/closure.t     Fri Mar 17 16:48:00 2006
@@ -42,6 +42,25 @@
      }}}}",
      qr/foo/, "multi-line PASM closure");
 
+p6rule_like("abcdef",
+    ":lang(PIR) abc {{{{
+        .return (\"xyz\")
+     }}}}",
+    qr/xyz/, "PIR closure with return");
+
+p6rule_like("abcdef",
+    ":lang(PIR) abc {{{{
+        .return (\"xyz\")
+     }}}} ghi",
+    qr/xyz/, "PIR closure with return always succeeds");
 
+p6rule_like("1234xyz5678",
+    ":lang(PIR) 2\\d\\d {{{{
+        \$I0 = match
+        \$I0 += 123
+        .return (\$I0)
+     }}}} ghi",
+    qr/357/, "PIR closure modifying match");
+ 
 # remember to change the number of tests :-)
-BEGIN { plan tests => 3; }
+BEGIN { plan tests => 6; }

Reply via email to