https://svn.lrde.epita.fr/svn/xrm/trunk
Index: ChangeLog
from SIGOURE Benoit <sigoure.benoit(a)lrde.epita.fr>
Add messages for the --verbose notice level.
Because someone has been reporting poor performances when using
xrm-front on large files, this will help to track the execution of
the pipeline by using --verbose notice. Hopefully we'll quickly see
where is the bottleneck (in term of execution time).
desugar-array-access has been renamed to flatten-array-access because
the name wasn't really appropriate and also because this name will be
used for a new strategy in future extensions.
* src/str/desugar-array-accesses.str: Rename as...
* src/str/flatten-array-access.str: ...this.
* src/str/xrm-to-prism.str: Update accordingly.
* src/str/xrm-front.str: Add calls to notice-msg.
flatten-array-access.str | 6 +++---
xrm-front.str | 8 +++++---
xrm-to-prism.str | 15 ++++++++++++---
3 files changed, 20 insertions(+), 9 deletions(-)
Index: src/str/flatten-array-access.str
--- src/str/flatten-array-access.str (revision 44)
+++ src/str/flatten-array-access.str (working copy)
@@ -1,15 +1,15 @@
-module desugar-array-accesses
+module flatten-array-access
rules
/**
** Transform an array access into an identifier (eg: x[i] -> x_i)
*/
- remove-array-accesses:
+ flatten-array-access:
ArrayAccess(Identifier(idf), access-list) -> Identifier(idf')
where flatten-access-list(|idf, access-list) => idf'
- remove-array-accesses:
+ flatten-array-access:
ArrayAccessPrime(Identifier(idf), access-list) -> IdentifierPrime(idf')
where flatten-access-list(|idf, access-list) => idf'
Index: src/str/xrm-to-prism.str
--- src/str/xrm-to-prism.str (revision 44)
+++ src/str/xrm-to-prism.str (working copy)
@@ -25,7 +25,7 @@
imports
XRM
prism-desugar
- desugar-array-accesses
+ flatten-array-access
check-meta-vars
eval-meta-code
array-decl-desugar
@@ -40,10 +40,12 @@
<+ DesugarImplicitForStep <+ DesugarImplicitElse
<+ DesugarRand <+ EvalRand
)
+ ; notice-msg(|"xrm-to-prism: XRM sugar removed")
/* Collect static const variables
* Two goals: expand them if needed, look for variable name conflicts. */
; topdown(try(collect-static-const-decl); try(collect-formulas))
+ ; notice-msg(|"xrm-to-prism: static const and formulas collected")
/* Desugar array declarations
* eg: x[4][5] is transformed into two nested meta for loops
@@ -53,18 +55,22 @@
* This must come AFTER collect-static-const-decl since we might need
* to expand an arrays which rely on static const variables.
*/
- ; array-decl-desugar
+ ; topdown(try(array-decl-desugar))
+ ; notice-msg(|"xrm-to-prism: array declarations desugared")
/* Check that meta vars are always defined in the current scope when used
* and that they are not redefined twice in the same scope */
; check-meta-vars
+ ; notice-msg(|"xrm-to-prism: meta-vars checked")
/* unroll meta loops, eval meta if */
; eval-meta-code
+ ; notice-msg(|"xrm-to-prism: eval-meta-code done")
/* flatten nested lists */
; ModulesFile(id, flatten-list)
; ModulesFile(id, map(try(Module(id, flatten-list))))
+ ; notice-msg(|"xrm-to-prism: flatten-list done")
/* get the modules that generates random numbers (XRM rand builtin) */
; where(bagof-RandGenModules; reverse => rand-gen-modules)
@@ -73,10 +79,13 @@
; ModulesFile(id, <conc>(<id>, rand-gen-modules))
/* remove array accesses: x[i] -> x_i */
- ; bottomup(try(remove-array-accesses))
+ // FIXME: can we make this more efficient than a complete bottomup?
+ ; bottomup(try(flatten-array-access))
+ ; notice-msg(|"xrm-to-prism: flatten-array-access done")
/* re-order modules so that all declarations appear before commands */
; ModulesFile(id, map(try(reorder-module-contents)))
+ ; notice-msg(|"xrm-to-prism: reorder-module-contents done")
rules
Index: src/str/xrm-front.str
--- src/str/xrm-front.str (revision 44)
+++ src/str/xrm-front.str (working copy)
@@ -29,15 +29,17 @@
write-to // output binary ATerms
else
if must-pp-aterm then // output pp-ATerms
- write-to; xtc-transform(!"pp-aterm", pass-verbose)
+ notice-msg(|"pretty printing ATerms")
+ ; write-to; xtc-transform(!"pp-aterm", pass-verbose)
else // output PRISM source
- write-to; xtc-transform(!"pp-prism", pass-verbose)
+ notice-msg(|"pretty printing PRISM code")
+ ; write-to; xtc-transform(!"pp-prism", pass-verbose)
end
end
/** pipeline of transformations performed by xrm-front */
xrm-front-pipeline =
- dbg(|"xrm-front-pipeline starting")
+ notice-msg(|"transformation pipeline starting")
; xrm-to-prism
; dbg(|"xrm-to-prism finished")
; if must-desugar then
>>> "SIGOURE" == SIGOURE Benoit <sigoure.benoit(a)lrde.epita.fr> writes:
> Simplify XRM's grammar.
> The constructors for meta for loops and meta ifs had each two
> different names depending whether they were found at top-level or
> inside modules. This turned out to be a bad idea because it was
> completely unecessary and made transformations harder (because
> multiple different cases had to be addressed where a single one could
> be enough).
> From now on we also stop saying "static" for loops or "static" if
> because "meta" seems more appropriate to qualify them and it sounds
> better (buzzword inside! :P)
Good.
> + // -> MetaFor
> prism-to-box:
> - OuterStaticFor(idf, for-from, for-to, mfs-list)
> + MetaFor(idf, for-from, for-to, mfs-list)
Pourquoi ne pas reposer sur GPP ?
https://svn.lrde.epita.fr/svn/xrm/trunk
Index: ChangeLog
from SIGOURE Benoit <sigoure.benoit(a)lrde.epita.fr>
Fix the XRM rand builtin for negative numbers.
rand(-1) was desugared to rand(0, -1) instead of rand(-1, 0)
* src/str/xrm-to-prism.str: Move DesugarUnaryOps...
* src/str/prism-desugar.str: Here.
* src/str/builtin-rand.str (DesugarRand): Allow negative numbers.
* src/str/desugar-array-accesses.str: Fix a flowed check which
allowed negative array accesses when they came after a good array
access.
* src/syn/prism/README: New.
* src/syn/prism/PRISM-Expression.sdf: Remove a FIXME. See the README.
* tests/xrm/for-with-exps.xpm: New.
* tests/xrm/negative-rand.xpm: New.
* TODO: Bring up to date.
TODO | 18 ++++++++-
src/str/builtin-rand.str | 27 +++++++++++---
src/str/desugar-array-accesses.str | 2 -
src/str/prism-desugar.str | 19 ++++++++++
src/str/xrm-to-prism.str | 15 --------
src/syn/prism/PRISM-Expression.sdf | 6 +--
src/syn/prism/README | 68 +++++++++++++++++++++++++++++++++++++
tests/xrm/for-with-exps.xpm | 9 ++++
tests/xrm/negative-rand.xpm | 4 ++
9 files changed, 142 insertions(+), 26 deletions(-)
Index: src/str/xrm-to-prism.str
--- src/str/xrm-to-prism.str (revision 42)
+++ src/str/xrm-to-prism.str (working copy)
@@ -36,8 +36,7 @@
xrm-to-prism =
/* remove XRM sugar, normalize some nodes */
innermost(
- DesugarUnaryOps // keep this first
- <+ DesugarRightShift <+ DesugarLeftShift
+ DesugarRightShift <+ DesugarLeftShift
<+ DesugarImplicitForStep <+ DesugarImplicitElse
<+ DesugarRand <+ EvalRand
)
@@ -81,18 +80,6 @@
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) ]|
Index: src/str/prism-desugar.str
--- src/str/prism-desugar.str (revision 42)
+++ src/str/prism-desugar.str (working copy)
@@ -19,6 +19,7 @@
prism-desugar-first-pass
; innermost(
RemoveUnconditionnalUpdates
+ <+ DesugarUnaryOps // keep this before the following rules
<+ AddZero <+ MulOne <+ MulZero <+ DivOne <+ catch-div-by-zero
<+ EvalPlus <+ EvalMinus <+ EvalMul <+ EvalDiv
<+ EvalLt <+ EvalLtEq <+ EvalGt <+ EvalGtEq <+ EvalEq <+ EvalNotEq
@@ -131,6 +132,24 @@
|[ e / 1D ]| -> |[ e ]|
/*
+** Simplify the AST by removing unary operators where possible.
+*/
+
+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
+
+/*
** ## ==================== ##
** ## Constant propagation ##
** ## ==================== ##
Index: src/str/builtin-rand.str
--- src/str/builtin-rand.str (revision 42)
+++ src/str/builtin-rand.str (working copy)
@@ -15,9 +15,22 @@
rules
- /** rand(x) -> rand(0, x) */
+ /** rand(x) -> rand(0, x) if x >= 0
+ ** rand(x) -> rand(x, 0) if x < 0 */
DesugarRand:
- Rand([arg]) -> Rand([Int("0"), arg])
+ Rand([arg]) -> Rand([arg1, arg2])
+ where ?current-term
+ ; <prism-desugar> arg => arg'
+ ; if not( !arg' => Int(iarg) ) then
+ <invalid-call-to-rand-non-int> current-term
+ end
+ ; if <ltS>(iarg, "0") then
+ !Int("0") => arg2
+ ; !arg' => arg1
+ else
+ !Int("0") => arg1
+ ; !arg' => arg2
+ end
EvalRand:
Rand(args) -> Identifier(rand-var)
@@ -33,9 +46,7 @@
; <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
+ <invalid-call-to-rand-non-int> current-term
end
; if <gtS>(ifrom, ito) then
err-msg(|<concat-strings>["invalid call to XRM builtin: ",
@@ -69,6 +80,12 @@
topdown(try(\ FIXME() -> Int(i) \)) => rand-update
; rules(RandUpdateList:+ _ -> rand-update)
+ invalid-call-to-rand-non-int =
+ err-msg(|<concat-strings>["invalid call to XRM builtin: rand's",
+ " arguments must be statically evaluable"])
+ ; debug
+ ; <xtc-exit> 4
+
/* node to replace in templates */
signature constructors
FIXME : FIXME
Index: src/str/desugar-array-accesses.str
--- src/str/desugar-array-accesses.str (revision 42)
+++ src/str/desugar-array-accesses.str (working copy)
@@ -36,7 +36,7 @@
/* Now we have a list of strings such as: ["1", "2", ...]
* Check that the list only contains positive integers as strings */
- ; try(map(string-to-int; neg; invalid-array-access))
+ ; map(try(string-to-int; neg; invalid-array-access))
/* Insert underscores between each integer */
; separate-by(|"_")
Index: src/syn/prism/README
--- src/syn/prism/README (revision 0)
+++ src/syn/prism/README (revision 0)
@@ -0,0 +1,68 @@
+About the "=" and "!=" operators
+--------------------------------
+
+We would like to make "=" and "!=" non-associative. Actually it's worse than
+that since we would like to disallow expressions such as 1=2=3 at all, whether
+they are parenthesized or not.
+
+One idea could be to make "=" and "!=" non-associative in a first time and
+then reject invalid productions in a second time using SDF priorities.
+(The following stuff have been explained by Martin Bravenboer)
+
+here are the two derivations that you want to reject:
+-----------------------------------------------------------------------------
+$ echo "0 = 1 = 2" | sglri -p PRISM.tbl | pp-aterm
+amb(
+ [ Eq(
+ Eq(Int("0"), [Int("1")])
+ , [Int("2")]
+ )
+ , Eq(
+ Int("0")
+ , [Eq(Int("1"), [Int("2")])]
+ )
+ ]
+)
+-----------------------------------------------------------------------------
+
+The first one *can* be rejected with the non-assoc attribute:
+
+ Expr "=" {Range ","}+ -> Expr {cons("Eq"), non-assoc}
+
+-----------------------------------------------------------------------------
+$ echo "0 = 1 = 2" | sglri -p PRISM.tbl | pp-aterm
+Eq(
+ Int("0")
+, [Eq(Int("1"), [Int("2")])]
+)
+-----------------------------------------------------------------------------
+
+The second one is more tricky, and indeed the associativity attribute
+does not work for this derivation, since the right-hand side of the Eq
+expression only indirectly produces an Eq. What we want to reject is
+the following derivation:
+
+Expr "=" {Range ","}+ -> Expr
+
+where Range is produced by Expr -> Range
+where Expr is produced by Expr "=" {Range ","}+ -> Expr
+
+We can reject this associated Eq by defining a priority that rejects Eq
+expressions as ranges:
+
+ context-free priorities
+ Expr -> Range
+ > Expr "=" {Range ","}+ -> Expr
+
+This seems to work but due to the transitivity of priorities, this also
+rejects all expressions on the right-hand side of Eq that have lower
+priority than the Eq itself.
+
+This is a real problem because (for instance) logical operators have a lower
+priority than the "=" sign. Therefore, with the above priorities, it is
+impossible to write 1=2&3 (for instance).
+
+Hence we chose to ignore the problem completely and leave the ambiguity.
+parse-prism and parse-xrm invoke sglr with the -A option which tells sglr to
+treat ambiguities as errors. This dirty workaround enables us to reject
+invalid input such as 1=2=3.
Index: src/syn/prism/PRISM-Expression.sdf
--- src/syn/prism/PRISM-Expression.sdf (revision 42)
+++ src/syn/prism/PRISM-Expression.sdf (working copy)
@@ -136,11 +136,9 @@
Expression ">" Expression -> Expression {non-assoc,cons("Gt")}
%% Notations for describing ranges in tests
- %%Expression "=" Expression ({(Expression (".." Expression)?) ","}*)?
- %% FIXME: disallow associativy for this construction:
+ %% NOTE: The two following rules should have a `non-assoc' keyword
+ %% which is omitted on purpose. See the README in this folder.
Expression "=" {Range ","}+ -> Expression {cons("Eq")}
- %%Expression "!=" Expression ({(Expression (".." Expression)?) ","}*)?
- %% FIXME: disallow associativy for this construction:
Expression "!=" {Range ","}+ -> Expression {cons("NotEq")}
"!" Expression -> Expression {cons("Not")}
Index: tests/xrm/for-with-exps.xpm
--- tests/xrm/for-with-exps.xpm (revision 0)
+++ tests/xrm/for-with-exps.xpm (revision 0)
@@ -0,0 +1,9 @@
+for i from +42-21*+2 to +3 do // 0 to 3
+ for j from -1 to i*2 do
+ if j >= 0 then
+ const int x[i][j] = i * 42 - j;
+ else
+ const int x[i][-1*j + i*2+1] = i * 42 - j;
+ end
+ end
+end
Index: tests/xrm/negative-rand.xpm
--- tests/xrm/negative-rand.xpm (revision 0)
+++ tests/xrm/negative-rand.xpm (revision 0)
@@ -0,0 +1,4 @@
+module test
+ x : [-42..42];
+ [] true -> x'=rand(-10);
+endmodule
Index: TODO
--- TODO (revision 42)
+++ TODO (working copy)
@@ -13,8 +13,6 @@
* Add tests using "system ... endsystem" (it's properly not parsed atm)
- * Disallow associativity for the "=" and "!=" operators.
-
* Write some sort of formal descriptions of the extensions offered.
* Add more tests. Add tests which actually do check that the generated code
@@ -134,6 +132,19 @@
[] x=3 -> ... // x=3 is impossible
[] x=0 -> (x'=3) // x=3 is not in the definition range of x
+ ## ----- ##
+ ## Notes ##
+ ## ----- ##
+
+ * PRISM's parser doesn't allow negative values in ranges for variables.
+ eg: x : [-42..42];
+
+ * PRISM's parser doesn't allow ranges for variables which start and end
+ with the same values.
+ eg: x : [42..42];
+ // idea: could we fix this by transforming x in a const int?
+ // -> needs to ensure that x isn't updated anywhere.
+
## ------------- ##
## Documentation ##
## ------------- ##
@@ -207,3 +218,6 @@
* Add a "rand" builtin. Eg:
rand(50) -> random value between 0 and 50 (included)
rand(42, 50) -> random value between 42 and 50 (included)
+
+ * Disallow associativity for the "=" and "!=" operators: won't fix (see
+ src/syn/prism/README)
>>> "SIGOURE" == SIGOURE Benoit <sigoure.benoit(a)lrde.epita.fr> writes:
> + add-meta-var =
> + check-meta-var-unicity
> + ; ?meta-var
> + ; rules(MetaVars: meta-var)
J'ai peut-être mal compris, mais je ne vois pas où tu vides les
MetaVars qui sortent de la portée courante. Par ailleurs, est-ce
vraiment ce que l'on veut ? Je ne vois pas de raison d'interdire des
boucles for i dans des boucles for i.
Akim Demaille <akim(a)lrde.epita.fr> writes:
>>>> "Nicolas" == Nicolas Pouillard <nicolas.pouillard(a)gmail.com> writes:
>
> > On 5/29/06, Akim Demaille <akim(a)lrde.epita.fr> wrote:
> >> >>> "Michaël" == Michaël Cadilhac <michael.cadilhac(a)lrde.org> writes:
> >> > Please don't use such headers. SVN $Id$ is here for you.
> >>
> >> Et franchement, même ce dernier on n'en veut plus vraiment.
>
> > A bon ??
>
> > Quelles en sont les raisons ?
>
> C'est quoi l'intérêt ? Aujourd'hui on a presque toujours une
> connexion à l'Internet, ou à défaut des outils qui marchent plutôt
> bien en off-line. Sans compter que maintenant on a un Id qui est
> plutôt globale au projet que locale au fichier. Du coup, un svn info
> ou genre fait très bien le métier.
>
> Je n'ai jamais vu un cas où ça avait servi d'avoir cet Id.
Les fichiers de conf sur gentoo ont tous leur $Id$. Ça me permet,
quand je reporte un bug dans un fichier de conf, de dire que c'est
celui du 28 août 2005, modifié par Dave Wart. Tout le monde regarde
alors le même fichier, mais je n'ai pas du tout la moindre idée d'où
se trouve le repository SVN associé.
Je ne vois pas en quoi c'est différent pour l'utilisateur, mettons, de
Vaucanson, qui aura téléchargé un snapshot, ./configure && make &&
make install, supprime la tarball et le répertoire, et utilise la
bibliothèque jusqu'à (hopefully) plantage.
--
| Pour les 35-40 ans, l'humour Michaël `Micha' Cadilhac |
| c'est une plus-value. cadilh_m - Epita 2007 - CSI |
| -- Guillaume L. JID: micha(a)amessage.be |
`-- - - - - --'
>>> "SIGOURE" == SIGOURE Benoit <sigoure.benoit(a)lrde.epita.fr> writes:
> Index: src/syn/xrm/XRM-Arrays.sdf
> --- src/syn/xrm/XRM-Arrays.sdf (revision 0)
> +++ src/syn/xrm/XRM-Arrays.sdf (revision 0)
> @@ -0,0 +1,19 @@
> +module XRM-Arrays
> +imports
> + PRISM-to-XRM
> +exports
> +
> + %% EBNF Grammar: Arrays
> + %% ArrayAccess ::= Identifier ArraySubscript {ArraySubscript}
> + %%
> + %% ArraySubscript ::= "[" Identifier "]"
> +
> + sorts ArrayAccess ArraySubscript
> + context-free syntax
> + Identifier ArraySubscript+ -> ArrayAccess {cons("ArrayAccess")}
> + "[" Identifier "]" -> ArraySubscript {bracket}
Ceci n'est pas suffisant à plusieurs titres :
- tableaux multidimensionnels
- expressions plutôt qu'ID comme indices
mais je suppose que c'est seulement le temps de passer à plus grande
échelle. C'est vraiment du beau travail.
> + %% Note: why use bracket here?
Tu devrais préciser que tu parles de l'annotation, sinon c'est pas
clair.
> + %% This is a work around. In SDF, if a production contains literals,
> + %% a constructor is required. With brackets, we specify that literals
> + %% are allowed there, however this does not create a node in the AST.
Je vois pas en quoi ça fait de ça un work-around :)
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)