https://svn.lrde.epita.fr/svn/xrm/trunk
Index: ChangeLog from SIGOURE Benoit sigoure.benoit@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)