XRM 44: Add shell-like meta-for loops.

https://svn.lrde.epita.fr/svn/xrm/trunk Index: ChangeLog from SIGOURE Benoit <sigoure.benoit@lrde.epita.fr> Add shell-like meta-for loops. It is now possible to write meta-for loops a la shell: for i in x, y, z do const int i = 42; end yields => const int x = 42; const int y = 42; const int z = 42; It's a bit ugly but I'm going to need something similar for the next extension. So I thought it would be "nice" to make this "feature" not only some internal hack used to achieve transformations and let the user play with it if he/she feels so. * src/lib/xrm/pp/xrm-meta-for.str: Add boxing for meta-for-in loops. * src/str/check-meta-vars.str: Add checks for meta-for-in loops. * src/str/xrm-to-prism.str: change the way array-decl-desugar is called. * src/str/eval-meta-code.str: Eval (unroll) "meta for in" loops. * src/syn/xrm/XRM-MetaFor.sdf: Add "meta for in" loops. * tests/xrm/for-in.xpm: New. * tests/test-xrm-front.sh.in: Remove useless check. src/lib/xrm/pp/xrm-meta-for.str | 27 ++++++++++++--- src/str/check-meta-vars.str | 9 +++++ src/str/eval-meta-code.str | 70 ++++++++++++++++++++++++++++++---------- src/str/xrm-to-prism.str | 4 +- src/syn/xrm/XRM-MetaFor.sdf | 12 ++++-- tests/test-xrm-front.sh.in | 8 ---- tests/xrm/for-in.xpm | 3 + 7 files changed, 97 insertions(+), 36 deletions(-) Index: src/lib/xrm/pp/xrm-meta-for.str --- src/lib/xrm/pp/xrm-meta-for.str (revision 43) +++ src/lib/xrm/pp/xrm-meta-for.str (working copy) @@ -2,10 +2,10 @@ rules - // "for" Identifier "from" Int "to" Int "do" ModulesFileSection* "end" - // -> MetaFor - // "for" Identifier "from" Int "to" Int "do" DeclarationOrCommand* "end" - // -> MetaFor + // "for" Identifier "from" Expression "to" Expression "do" + // ModulesFileSection* "end" -> MetaFor + // "for" Identifier "from" Expression "to" Expression "do" + // DeclarationOrCommand* "end" -> MetaFor prism-to-box: MetaFor(idf, for-from, for-to, mfs-list) -> box |[ V[ V is=2 [ @@ -16,9 +16,9 @@ ] KW["end"] // in the outermost V box ] ]| - // "for" Identifier "from" Int "to" Int "step" Int "do" + // "for" Identifier "from" Expression "to" Expression "step" Expression "do" // ModulesFileSection* "end" -> MetaFor - // "for" Identifier "from" Int "to" Int "step" Int "do" + // "for" Identifier "from" Expression "to" Expression "step" Expression "do" // DeclarationOrCommand* "end" -> MetaFor prism-to-box: MetaFor(idf, for-from, for-to, for-step, mfs-list) @@ -30,3 +30,18 @@ ~*mfs-list // in the innermost V box ] KW["end"] // in the outermost V box ] ]| + + // "for" Identifier "in" {Expression ","} "do" ModulesFileSection* "end" + // -> MetaForIn + // "for" Identifier "in" {Expression ","} "do" DeclarationOrCommand* "end" + // -> MetaForIn + prism-to-box: + MetaForIn(idf, in-list, mfs-list) + -> box |[ V[ V is=2 [ + H hs=1 [ KW["for"] ~idf + KW["in"] ~*in-list' + KW["do"] ] + ~*mfs-list // in the innermost V box + ] KW["end"] // in the outermost V box + ] ]| + where <separate-by(!S(","))> in-list => in-list' Index: src/str/check-meta-vars.str --- src/str/check-meta-vars.str (revision 43) +++ src/str/check-meta-vars.str (working copy) @@ -13,6 +13,7 @@ check-meta-vars = check-meta-for + <+ check-meta-forin <+ check-meta-if <+ ArrayAccess(id, check-all-identifers-are-meta-vars) <+ ArrayAccessPrime(id, check-all-identifers-are-meta-vars) @@ -28,6 +29,14 @@ ; <check-meta-vars> body |}) + check-meta-forin = + ?MetaForIn(new-meta-var, exp-list, body) + ; where({| MetaVars: + <add-meta-var> new-meta-var + ; <check-meta-vars> exp-list + ; <check-meta-vars> body + |}) + check-meta-if = ?MetaIf(condition, then-part, else-part) ; where( Index: src/str/xrm-to-prism.str --- src/str/xrm-to-prism.str (revision 43) +++ src/str/xrm-to-prism.str (working copy) @@ -51,9 +51,9 @@ * traversal is bottomup and won't recurse into generated code. * * This must come AFTER collect-static-const-decl since we might need - * to expand an array which relies on static const variables. + * to expand an arrays which rely on static const variables. */ - ; topdown(try(array-decl-desugar)) + ; array-decl-desugar /* Check that meta vars are always defined in the current scope when used * and that they are not redefined twice in the same scope */ Index: src/str/eval-meta-code.str --- src/str/eval-meta-code.str (revision 43) +++ src/str/eval-meta-code.str (working copy) @@ -19,7 +19,8 @@ eval-meta-code = eval-meta-if - <+ unroll-meta-loops + <+ unroll-meta-for + <+ unroll-meta-forin <+ all(eval-meta-code) strategies @@ -47,7 +48,7 @@ strategies - unroll-meta-loops = + unroll-meta-for = ?MetaFor(meta-var, from, to, step, body) /* reduce the fields from to and step down to simple integers */ ; where( <prism-desugar> from => from' @@ -62,17 +63,17 @@ ; !step' => Int(istep) ) ; {| MetaCode: - ///*DEBUG*/say(!" @@@ unroll-meta-loops: starting:") + ///*DEBUG*/say(!" @@@ unroll-meta-for: starting:") ///*DEBUG*/; printf(|" meta-var = ", meta-var) ///*DEBUG*/; printf(|" from = ", ifrom) ///*DEBUG*/; printf(|" to = ", ito); - where(<check-meta-var-unicity> meta-var) - ; for-loop(gen-meta-code | ifrom, ito, istep, []) - ///*DEBUG*/; say(!" ~~~ unroll-meta-loops: before bagof-MetaModule") + where(<check-meta-var-unicity> meta-var) // FIXME: is this still needed? + ; for-loop(gen-meta-for | ifrom, ito, istep, []) + ///*DEBUG*/; say(!" ~~~ unroll-meta-for: before bagof-MetaModule") ///*DEBUG*/; debug ; bagof-MetaCode ; reverse - ///*DEBUG*/; say(!" ~~~ unroll-meta-loops: after bagof-MetaModule") + ///*DEBUG*/; say(!" ~~~ unroll-meta-for: after bagof-MetaModule") ///*DEBUG*/; debug |} @@ -94,24 +95,61 @@ strategies - gen-meta-code(|i, data) = - ///*DEBUG*/say(!" ### gen-meta-code starting"); debug; - (?MetaFor(meta-var, _, _, _, body) <+ fatal-err-msg(|"ICE!")) - ///*DEBUG*/; say(!" >>> gen-meta-code -- start -- current term >>>") + gen-meta-for(|i, data) = + ///*DEBUG*/say(!" ### gen-meta-for starting"); debug; + ?MetaFor(meta-var, _, _, _, body) + ///*DEBUG*/; say(!" >>> gen-meta-for -- start -- current term >>>") ///*DEBUG*/; debug - ///*DEBUG*/; say(!" >>> gen-meta-code -- start -- iterator >>>") + ///*DEBUG*/; say(!" >>> gen-meta-for -- start -- iterator >>>") ///*DEBUG*/; printf(|" meta-var = ", meta-var) ///*DEBUG*/; printf(|" i = ", i) - ///*DEBUG*/; say(!" <<< gen-meta-code -- propagating meta-var's value <<< ") + ///*DEBUG*/; say(!" <<< gen-meta-for -- propagating meta-var's value <<< ") ; !body ; topdown(try(?meta-var; !Int(i))) ///*DEBUG*/; debug - ///*DEBUG*/; say(!" ~~~ gen-meta-code: now recursing") + ///*DEBUG*/; say(!" ~~~ gen-meta-for: now recursing") ; eval-meta-code => generated-code ; rules(MetaCode:+ _ -> generated-code) - ///*DEBUG*/; say(!" ~~~ gen-meta-code: recursion finished, final result:") + ///*DEBUG*/; say(!" ~~~ gen-meta-for: recursion finished, final result:") ///*DEBUG*/; debug - ///*DEBUG*/; say(!" <<<<<<<<<<<<<<<<< gen-meta-code <<<<<<<<<<<<<<<<< ") + ///*DEBUG*/; say(!" <<<<<<<<<<<<<<<<< gen-meta-for <<<<<<<<<<<<<<<<< ") + +strategies + + unroll-meta-forin = + ?MetaForIn(meta-var, exp-list, body) + ; {| MetaCode: + ///*DEBUG*/say(!" @@@ unroll-meta-forin: starting:") + ///*DEBUG*/; printf(|" meta-var = ", meta-var) + ///*DEBUG*/; printf(|" exp-list = ", exp-list); + where(<check-meta-var-unicity> meta-var) // FIXME: is this still needed? + ; <map(gen-meta-forin(|meta-var, body))> exp-list + ///*DEBUG*/; say(!" ~~~ unroll-meta-forin: before bagof-MetaModule") + ///*DEBUG*/; debug + ; bagof-MetaCode + ; reverse + ///*DEBUG*/; say(!" ~~~ unroll-meta-forin: after bagof-MetaModule") + ///*DEBUG*/; debug + |} + + gen-meta-forin(|meta-var, body) = + ///*DEBUG*/say(!" ### gen-meta-forin starting"); debug; + ?exp-to-replace + ///*DEBUG*/; say(!" >>> gen-meta-forin -- start -- current term >>>") + ///*DEBUG*/; debug + ///*DEBUG*/; say(!" >>> gen-meta-forin -- start -- iterator >>>") + ///*DEBUG*/; printf(|" meta-var = ", meta-var) + ///*DEBUG*/; printf(|" exp-to-replace = ", exp-to-replace) + ///*DEBUG*/; say(!" <<< gen-meta-forin -- propagating meta-var's value <<< ") + ; !body + ; topdown(try(?meta-var; !exp-to-replace)) + ///*DEBUG*/; debug + ///*DEBUG*/; say(!" ~~~ gen-meta-forin: now recursing") + ; eval-meta-code => generated-code + ; rules(MetaCode:+ _ -> generated-code) + ///*DEBUG*/; say(!" ~~~ gen-meta-forin: recursion finished, final result:") + ///*DEBUG*/; debug + ///*DEBUG*/; say(!" <<<<<<<<<<<<<<<<< gen-meta-forin <<<<<<<<<<<<<<<<< ") strategies ///*DEBUG*/printf(|str, term) = where(<fprintnl> (stderr, [str, term])) Index: src/syn/xrm/XRM-MetaFor.sdf --- src/syn/xrm/XRM-MetaFor.sdf (revision 43) +++ src/syn/xrm/XRM-MetaFor.sdf (working copy) @@ -21,17 +21,21 @@ %% This MetaFor can be found only at top-level %% So we can see it as a ModulesFileSection "for" Identifier "from" Expression "to" Expression "do" - ModulesFileSection* "end" - -> ModulesFileSection {cons("MetaFor")} + ModulesFileSection* "end" -> ModulesFileSection {cons("MetaFor")} "for" Identifier "from" Expression "to" Expression "step" Expression "do" ModulesFileSection* "end" -> ModulesFileSection {cons("MetaFor")} + "for" Identifier "in" {Expression ","}+ "do" + ModulesFileSection* "end" -> ModulesFileSection {cons("MetaForIn")} + %% This MetaFor can be found only inside Modules %% So we can see it as a DeclarationOrCommand "for" Identifier "from" Expression "to" Expression "do" - DeclarationOrCommand* "end" - -> DeclarationOrCommand {cons("MetaFor")} + DeclarationOrCommand* "end" -> DeclarationOrCommand {cons("MetaFor")} "for" Identifier "from" Expression "to" Expression "step" Expression "do" DeclarationOrCommand* "end" -> DeclarationOrCommand {cons("MetaFor")} + + "for" Identifier "in" {Expression ","}+ "do" + ModulesFileSection* "end" -> DeclarationOrCommand {cons("MetaForIn")} Index: tests/xrm/for-in.xpm --- tests/xrm/for-in.xpm (revision 0) +++ tests/xrm/for-in.xpm (revision 0) @@ -0,0 +1,3 @@ +for i in x,y,z do + const int i = 0; +end Index: tests/test-xrm-front.sh.in --- tests/test-xrm-front.sh.in (revision 43) +++ tests/test-xrm-front.sh.in (working copy) @@ -58,14 +58,6 @@ fi echo 'OK, no ambiguities found' - diff -q "$outdir/$bfile.pm.aterm" "$outdir/$bfile.pm2.aterm" - - if [ $? -ne 0 ]; then - echo 'FAILED: the two parses did NOT produce the same AST:' - echo " * $file: both parses did NOT produce the same AST" >> failed_tests.$$ - diff -u "$outdir/$bfile.pm.aterm.pp" "$outdir/$bfile.pm2.aterm.pp" - fi - echo "<<< Test for $basefile PASSED" test_pass=$((test_pass + 1)) done
participants (1)
-
SIGOURE Benoit