https://svn.lrde.epita.fr/svn/xrm/trunk
Index: ChangeLog
from SIGOURE Benoit <sigoure.benoit(a)lrde.epita.fr>
Extend meta for loops + fix the XRM rand builtin.
Revision 42 \o/
The fields `from', `to' and `step' of meta for loops can now contain
any expression as long as it's statically evaluable down to a simple
Int.
The first pass of xrm-to-prism now desugar Plus(Int(i)) to Int(i) and
Minus(Int(i)) to Int(-i). This plus the previous change allows for
loops to use negative numbers (eg: for i from -4 to -1 do ... end)
* src/lib/xrm/pp/xrm-to-abox.str: Update a comment.
* src/lib/prism/pp/prism-to-abox.str: Ditto.
* src/str/xrm-to-prism.str: Move the rand builtin in another file.
Handle unary operators to ease transformations.
* src/str/builtin-rand.str: New.
* src/str/builtin-rand.meta: New.
* src/str/eval-meta-code.str: Extend for loops (as said above).
* src/syn/xrm/XRM-MetaFor.sdf: Ditto.
* src/str/xrm-front.str: Update the help message.
* src/syn/prism/PRISM-Expression.sdf: Update a comment.
* TODO: More things to do...
TODO | 19 +++++++--
src/lib/prism/pp/prism-to-abox.str | 2 -
src/lib/xrm/pp/xrm-to-abox.str | 2 -
src/str/builtin-rand.meta | 1
src/str/builtin-rand.str | 74 +++++++++++++++++++++++++++++++++++++
src/str/eval-meta-code.str | 34 +++++++++++++----
src/str/xrm-front.str | 4 +-
src/str/xrm-to-prism.str | 68 ++++++++++------------------------
src/syn/prism/PRISM-Expression.sdf | 9 ++--
src/syn/xrm/XRM-MetaFor.sdf | 16 +++++---
10 files changed, 155 insertions(+), 74 deletions(-)
Index: src/lib/xrm/pp/xrm-to-abox.str
--- src/lib/xrm/pp/xrm-to-abox.str (revision 41)
+++ src/lib/xrm/pp/xrm-to-abox.str (working copy)
@@ -54,7 +54,7 @@
// because we simply extend it
pp-xrm-to-abox(pprules) =
- // strategy generated in prism-parenthesize.str by sdf2parenthesize
+ // strategy from xrm-parenthesize.str generated by sdf2parenthesize
parenthesize-XRM
; topdown(try(very-special-conflict))
; topdown(try(repeat(pprules)))
Index: src/lib/prism/pp/prism-to-abox.str
--- src/lib/prism/pp/prism-to-abox.str (revision 41)
+++ src/lib/prism/pp/prism-to-abox.str (working copy)
@@ -47,7 +47,7 @@
pp-prism-to-abox(prism-to-box)
pp-prism-to-abox(pprules) =
- // strategy generated in prism-parenthesize.str by sdf2parenthesize
+ // strategy from prism-parenthesize.str generated by sdf2parenthesize
parenthesize-PRISM
; topdown(try(very-special-conflict))
; topdown(try(repeat(pprules)))
Index: src/str/xrm-to-prism.str
--- src/str/xrm-to-prism.str (revision 41)
+++ src/str/xrm-to-prism.str (working copy)
@@ -17,6 +17,9 @@
** - ExpandFormulas: created by the strategy collect-formulas and used by
** prism-desugar for constant propagation. Maps an identifier with an
** expression.
+** - RandGenModules: each call to the XRM builtin rand generates a module
+** which is stored in this DR. Just before xrm-to-prism finishes, we
+** paste these modules at the end of the source code.
*/
module xrm-to-prism
imports
@@ -26,13 +29,15 @@
check-meta-vars
eval-meta-code
array-decl-desugar
+ builtin-rand
strategies
xrm-to-prism =
/* remove XRM sugar, normalize some nodes */
innermost(
- DesugarRightShift <+ DesugarLeftShift
+ DesugarUnaryOps // keep this first
+ <+ DesugarRightShift <+ DesugarLeftShift
<+ DesugarImplicitForStep <+ DesugarImplicitElse
<+ DesugarRand <+ EvalRand
)
@@ -62,20 +67,32 @@
; ModulesFile(id, flatten-list)
; ModulesFile(id, map(try(Module(id, flatten-list))))
- /* get the list of generated modules that generates random numbers */
+ /* get the modules that generates random numbers (XRM rand builtin) */
; where(bagof-RandGenModules; reverse => rand-gen-modules)
- /* add the modules that generates random numbers in the ModulesFile */
+ /* paste them at the end of the file */
; ModulesFile(id, <conc>(<id>, rand-gen-modules))
/* remove array accesses: x[i] -> x_i */
- ; topdown(try(remove-array-accesses))
+ ; bottomup(try(remove-array-accesses))
/* re-order modules so that all declarations appear before commands */
; ModulesFile(id, map(try(reorder-module-contents)))
rules
+ DesugarUnaryOps:
+ Plus(Int(i)) -> Int(i)
+
+ DesugarUnaryOps:
+ Plus(Double(i)) -> Double(i)
+
+ DesugarUnaryOps:
+ Minus(Int(i)) -> Int(j) where <mulS>(i, "-1") => j
+
+ DesugarUnaryOps:
+ Minus(Double(i)) -> Double(j) where <mulS>(i, "-1") => j
+
DesugarRightShift:
|[ e1 >> e2 ]| -> |[ e1 / func(pow, 2, e2) ]|
@@ -92,51 +109,8 @@
//|[ if e then s* end ]| -> |[ if e then s* else end ]|
MetaIf(e, m*) -> MetaIf(e, m*, [])
- /** rand(x) -> rand(0, x) */
- DesugarRand:
- Rand([arg]) -> Rand([Int("0"), arg])
-
- EvalRand:
- Rand(args) -> Identifier(rand-var)
- where ?current-term
- ; if not( !args => [from, to] ) then
- err-msg(|<concat-strings>["invalid call to XRM builtin:
rand",
- " takes either one or two arguments"])
- ; !current-term; debug; <xtc-exit> 4
- end
- ; <prism-desugar> from => from'
- ; <prism-desugar> to => to'
- ; if not( !from' => Int(ifrom); !to' => Int(ito) ) then
- err-msg(|<concat-strings>["invalid call to XRM builtin:
rand's",
- " arguments must be statically evaluable"])
- ; !current-term; debug; <xtc-exit> 4
- end
- ; <debug> ifrom
- ; <debug> ito
- ; <newname> "__rand" => rand-var
- ; !ProbUpdate( Div(Int("1"), Int( <subtS>(ito, ifrom) ))
- , UpdateList([UpdateElement(IdentifierPrime(rand-var), FIXME())]))
- ; {| RandUpdateList:
- for-loop(gen-rand-update-list | ifrom, ito, "1", [])
- ; bagof-RandUpdateList
- |}
- ; reverse
- ; !ProbUpdateList(<id>) => u
- ; !|[ module ~id:rand-var
- ~id:rand-var : [~int:ifrom..~int:ito];
- [] true -> u;
- endmodule ]| => rand-gen-module
- ; rules(RandGenModules:+ _ -> rand-gen-module)
-
-strategies
-
- gen-rand-update-list(|i, data) =
- topdown(try(\ FIXME() -> Int(i) \)) => rand-update
- ; rules(RandUpdateList:+ _ -> rand-update)
-
signature constructors
Type : String -> Type
- FIXME : FIXME
strategies
Index: src/str/eval-meta-code.str
--- src/str/eval-meta-code.str (revision 41)
+++ src/str/eval-meta-code.str (working copy)
@@ -9,7 +9,7 @@
** Sorry if it makes the source a bit overloaded with comments.
**
** If you want to enable debugging simply use:
-** sed 's@///\*@/*@g' < eval-meta-code.str > .tmp
+** sed 's@/\*@/*@g' < eval-meta-code.str > .tmp
** mv .tmp eval-meta-code.str
*/
module eval-meta-code
@@ -48,15 +48,26 @@
strategies
unroll-meta-loops =
- ?MetaFor(meta-var, Int(from), Int(to), Int(step), body)
- ; where(check-loop-validity(|meta-var, from, to))
+ ?MetaFor(meta-var, from, to, step, body)
+ /* reduce the fields from to and step down to simple integers */
+ ; where( <prism-desugar> from => from'
+ ; <prism-desugar> to => to'
+ ; <prism-desugar> step => step'
+ )
+ /* check whether the loop is valid */
+ ; where(check-loop-validity(|meta-var, from', to', step'))
+ /* bind the integers of the fields from to and step */
+ ; where(!from' => Int(ifrom)
+ ; !to' => Int(ito)
+ ; !step' => Int(istep)
+ )
; {| MetaCode:
///*DEBUG*/say(!" @@@ unroll-meta-loops: starting:")
///*DEBUG*/; printf(|" meta-var = ", meta-var)
- ///*DEBUG*/; printf(|" from = ", from)
- ///*DEBUG*/; printf(|" to = ", to);
+ ///*DEBUG*/; printf(|" from = ", ifrom)
+ ///*DEBUG*/; printf(|" to = ", ito);
where(<check-meta-var-unicity> meta-var)
- ; for-loop(gen-meta-code | from, to, step, [])
+ ; for-loop(gen-meta-code | ifrom, ito, istep, [])
///*DEBUG*/; say(!" ~~~ unroll-meta-loops: before bagof-MetaModule")
///*DEBUG*/; debug
; bagof-MetaCode
@@ -65,8 +76,15 @@
///*DEBUG*/; debug
|}
- check-loop-validity(|meta-var, from, to) =
- if <gtS>(from, to) then
+ check-loop-validity(|meta-var, from, to, step) =
+ if not(!from => Int(_); !to => Int(_); !step => Int(_)) then
+ err-msg(|<concat-strings>["invalid meta for loop: the value of the
",
+ "fields `from', `to' and `step' must be
",
+ "statically evaluable down to a ",
+ "simple integer"])
+ ; <xtc-exit> 2
+ end
+ ; if <gtS>(from, to) then
!meta-var => Identifier(idf)
; err-msg(|<concat-strings>["bad `for' loop on the meta-var ",
idf, " starts at ", from,
Index: src/str/builtin-rand.str
--- src/str/builtin-rand.str (revision 0)
+++ src/str/builtin-rand.str (revision 0)
@@ -0,0 +1,74 @@
+/**
+** This sub-module handles the XRM builtin rand.
+** rand(x) generates a random value (at runtime) between 0 and x (inclusive)
+** rand(x) is first desugared to rand(0, x).
+** rand(x, y) generates a random value between x and y (inclusive).
+**
+** Here is how it works with rand(y, x)
+** 1. Check that rand is called with the correct number of arguments.
+** 2. Apply prism-desugar to those arguments in order to reduce them down
+** to simple integers [Int(..)]
+** 3. Generate a module with a single command which have a list of updates
+** which the same probability [1/(x-y+1)]
+*/
+module builtin-rand
+
+rules
+
+ /** rand(x) -> rand(0, x) */
+ DesugarRand:
+ Rand([arg]) -> Rand([Int("0"), arg])
+
+ EvalRand:
+ Rand(args) -> Identifier(rand-var)
+ where ?current-term // save the current term for error messages
+ /* check that rand is called with exactly two arguments */
+ ; if not( !args => [from, to] ) then
+ err-msg(|<concat-strings>["invalid call to XRM builtin:
rand",
+ " takes either one or two arguments"])
+ ; !current-term; debug; <xtc-exit> 4
+ end
+ /* desugar (constant propagation) to make both arguments simple Int */
+ ; <prism-desugar> from => from'
+ ; <prism-desugar> to => to'
+ /* check that both arguments are simple Int */
+ ; if not( !from' => Int(ifrom); !to' => Int(ito) ) then
+ err-msg(|<concat-strings>["invalid call to XRM builtin:
rand's",
+ " arguments must be statically evaluable"])
+ ; !current-term; debug; <xtc-exit> 4
+ end
+ ; if <gtS>(ifrom, ito) then
+ err-msg(|<concat-strings>["invalid call to XRM builtin: ",
+ "rand(x,y) where x > y"])
+ ; !current-term; debug; <xtc-exit> 4
+ end
+ /* generate a name for the random variable */
+ ; <newname> "__rand" => rand-var
+ /* template: 1/(ito-ifrom+1):(rand-var'=FIXME) */
+ ; !ProbUpdate( Div(Int("1"), Int( <addS>(<subtS>(ito,
ifrom), "1") ))
+ , UpdateList([UpdateElement(IdentifierPrime(rand-var), FIXME())]))
+ /* generate the updates by replacing the FIXME */
+ ; {| RandUpdateList:
+ for-loop(gen-rand-update-list | ifrom, ito, "1", [])
+ ; bagof-RandUpdateList
+ |}
+ ; reverse // bagof gives us the list in reverse order
+ /* put our update list in the correct AST node */
+ ; !ProbUpdateList(<id>) => u
+ /* inject that node in a module */
+ ; !|[ module ~id:rand-var
+ ~id:rand-var : [~int:ifrom..~int:ito];
+ [] true -> u;
+ endmodule ]| => rand-gen-module
+ /* save this module in a DR for later retrieval */
+ ; rules(RandGenModules:+ _ -> rand-gen-module)
+
+strategies
+
+ gen-rand-update-list(|i, data) =
+ topdown(try(\ FIXME() -> Int(i) \)) => rand-update
+ ; rules(RandUpdateList:+ _ -> rand-update)
+
+/* node to replace in templates */
+signature constructors
+ FIXME : FIXME
Index: src/str/xrm-front.str
--- src/str/xrm-front.str (revision 41)
+++ src/str/xrm-front.str (working copy)
@@ -133,8 +133,8 @@
<tool-doc>
[ Usage("xrm-front [OPTIONS]")
, Summary("Transforms an eXtended Reactive Module source file in a
- PRISM-equivalent abstract syntax tree (default) or source
- code. (see option -P)")
+ PRISM-equivalent source code (default) or abstract syntax
+ tree. (see option -A)")
, OptionUsage()
, AutoReportBugs()
]
Index: src/str/builtin-rand.meta
--- src/str/builtin-rand.meta (revision 0)
+++ src/str/builtin-rand.meta (revision 0)
@@ -0,0 +1 @@
+Meta([Syntax("StrategoXRM")])
Index: src/syn/xrm/XRM-MetaFor.sdf
--- src/syn/xrm/XRM-MetaFor.sdf (revision 41)
+++ src/syn/xrm/XRM-MetaFor.sdf (working copy)
@@ -7,27 +7,31 @@
%% EBNF Grammar: Meta For Loops
%% (* Meta For loops at the top level *)
%% ModulesFileSection ::=
- %% "for" Identifier "from" Int "to" Int
["step" Int] "do"
+ %% "for" Identifier "from" Expression "to" Expression
+ %% ["step" Expression] "do"
%% {ModulesFileSection} "end"
%%
%% (* Meta For loops inside modules *)
%% DeclarationOrCommand ::=
- %% "for" Identifier "from" Int "to" Int
["step" Int] "do"
+ %% "for" Identifier "from" Expression "to" Expression
+ %% ["step" Expression] "do"
%% {DeclarationOrCommand} "end"
context-free syntax
%% This MetaFor can be found only at top-level
%% So we can see it as a ModulesFileSection
- "for" Identifier "from" Int "to" Int "do"
ModulesFileSection* "end"
+ "for" Identifier "from" Expression "to" Expression
"do"
+ ModulesFileSection* "end"
-> ModulesFileSection {cons("MetaFor")}
- "for" Identifier "from" Int "to" Int "step"
Int "do"
+ "for" Identifier "from" Expression "to" Expression
"step" Expression "do"
ModulesFileSection* "end" -> ModulesFileSection
{cons("MetaFor")}
%% This MetaFor can be found only inside Modules
%% So we can see it as a DeclarationOrCommand
- "for" Identifier "from" Int "to" Int "do"
DeclarationOrCommand* "end"
+ "for" Identifier "from" Expression "to" Expression
"do"
+ DeclarationOrCommand* "end"
-> DeclarationOrCommand {cons("MetaFor")}
- "for" Identifier "from" Int "to" Int "step"
Int "do"
+ "for" Identifier "from" Expression "to" Expression
"step" Expression "do"
DeclarationOrCommand* "end" -> DeclarationOrCommand
{cons("MetaFor")}
Index: src/syn/prism/PRISM-Expression.sdf
--- src/syn/prism/PRISM-Expression.sdf (revision 41)
+++ src/syn/prism/PRISM-Expression.sdf (working copy)
@@ -27,8 +27,8 @@
%% | Expression ">=" Expression
%% | Expression ">" Expression
%% (* Notations for describing ranges in tests *)
- %% | Expression "=" (Single | Range) {Single | Range}
- %% | Expression "!=" (Single | Range) {Single | Range}
+ %% | Expression "=" Range {"," Range}
+ %% | Expression "!=" Range {"," Range}
%% | "!" Expression
%% | Expression "&" Expression
%% | Expression "|" Expression
@@ -46,9 +46,8 @@
%% | "func" "(" "floor" ","
Expression {"," Expression} ")"
%% | "func" "(" "ceil" ","
Expression {"," Expression} ")"
%%
- %% Single ::= Expression
- %%
- %% Range ::= Expression ".." Expression
+ %% Range ::= Expression
+ %% | Expression ".." Expression
%% EBNF Grammar: Expressions as in PRISM's parser
%% Expression ::= ExpressionITE
Index: TODO
--- TODO (revision 41)
+++ TODO (working copy)
@@ -31,6 +31,8 @@
static const int N = -1; will issue an error such as "undeclared meta
variable N" whereas the real problem is that array[N] couldn't be expanded.
+ * Labels seems to be b0rken in parse-prism.
+
## ---------- ##
## Extensions ##
## ---------- ##
@@ -48,10 +50,6 @@
declared variables (globals, formulas, local declarations etc.) and ensure
(in check-meta-vars) that their identifiers are unique.
- * Add a "rand" builtin. Eg:
- rand(50) -> random value between 0 and 50 (included)
- rand(42, 50) -> random value between 42 and 50 (included)
-
* Add a sanity check after xrm-front has finished to generate everything in
order to ensure that each module/var decl has a unique name.
@@ -103,6 +101,14 @@
* Add parameterized formulas. (Pretty much like macro-functions in C)
+ * Check why for i from -1 to -4 is not caught as an error.
+
+ * Add scopes for meta variables
+ eg: for i ... do
+ for i ... // `i' shadows its previous definition
+ end
+ end
+
## -------------- ##
## Desugarisation ##
## -------------- ##
@@ -137,6 +143,7 @@
- 2: error with meta-vars (eg: undefined meta-var, redefined meta-var)
- 3: arithmetic error when evaluating code (eg: division/modulo by 0)
- 4: invalid call to a builtin (eg rand(1,2,3))
+ - 5: invalid array access (eg: subscript is not a positive integer)
- 42: internal compiler error
- 51: not yet implemented
@@ -196,3 +203,7 @@
* Desugarise ranges (?)
x = 1..5,7,10..13
==> (x>=1 & x<=5) | (x=7) | (x>=10 & x<=13)
+
+ * Add a "rand" builtin. Eg:
+ rand(50) -> random value between 0 and 50 (included)
+ rand(42, 50) -> random value between 42 and 50 (included)