
https://svn.lrde.epita.fr/svn/xrm/trunk Index: ChangeLog from SIGOURE Benoit <sigoure.benoit@lrde.epita.fr> Add the static_rand builtin. NOTE: Some C was needed to implement rand(from, to) because for some reason I didn't succeed in writing something equivalent in Stratego. For some reason, the numbers I generated were all too small. * src/tools/pp-xrm.str: Remove a FIXME. * src/tools/pp-prism.str: Ditto. * src/lib/xrm/pp/xrm-expression.str: Add boxing for static_rand. * src/lib/native/rand.c: New. * src/lib/native/Makefile.am: Add rand.c. * src/str/prism-desugar.str (prism-desugar-first-pass): Re-order calls and correct a minor bug. * src/str/builtin-rand.str: Handle static_rand. * src/str/xrm-front.str: Set a random seed before the main transformation pipeline starts. * src/syn/xrm/XRM-Expression.sdf: Add static_rand. lib/native/Makefile.am | 5 +- lib/native/rand.c | 27 +++++++++++ lib/xrm/pp/xrm-expression.str | 5 ++ str/builtin-rand.str | 101 ++++++++++++++++++++++++++++++------------ str/prism-desugar.str | 8 +-- str/xrm-front.str | 1 syn/xrm/XRM-Expression.sdf | 9 +++ tools/pp-prism.str | 2 tools/pp-xrm.str | 2 9 files changed, 124 insertions(+), 36 deletions(-) Index: src/tools/pp-xrm.str --- src/tools/pp-xrm.str (revision 48) +++ src/tools/pp-xrm.str (working copy) @@ -22,7 +22,7 @@ ?(<read-from-stream>, out-file) ; pp-xrm-to-abox ; box2text-stream(|80, out-file) - // FIXME: a final \n is missing + ; <fputs> ("\n", out-file) /** * Documentation Index: src/tools/pp-prism.str --- src/tools/pp-prism.str (revision 48) +++ src/tools/pp-prism.str (working copy) @@ -22,7 +22,7 @@ ?(<read-from-stream>, out-file) ; pp-prism-to-abox ; box2text-stream(|80, out-file) - // FIXME: a final \n is missing + ; <fputs> ("\n", out-file) /** * Documentation Index: src/lib/xrm/pp/xrm-expression.str --- src/lib/xrm/pp/xrm-expression.str (revision 48) +++ src/lib/xrm/pp/xrm-expression.str (working copy) @@ -21,3 +21,8 @@ Rand(args) // because func(rand, ...) is just uggly. -> box |[ H hs=0 [ KW["rand"] "(" H hs=1 [ ~args-imploded ] ")" ] ]| where <implode-list(|",")> args => args-imploded + + prism-to-box: + StaticRand(args) + -> box |[ H hs=0 [ KW["static_rand"] "(" H hs=1 [~args-imploded] ")" ] ]| + where <implode-list(|",")> args => args-imploded Index: src/lib/native/rand.c --- src/lib/native/rand.c (revision 0) +++ src/lib/native/rand.c (revision 0) @@ -0,0 +1,27 @@ +/* +** rand.c for str-reals in /home/tsuna/work/xrm/trunk/src/lib/native +** +** Made by SIGOURE Benoit +** Mail <sigoure.benoit@lrde.epita.fr> +** +** Started on Tue Jun 6 15:13:53 2006 SIGOURE Benoit +** Last update Tue Jun 6 15:23:57 2006 SIGOURE Benoit +*/ + +#include <stdlib.h> +#include "libstr-reals.h" + +ATerm STR_REALS_rand(ATerm from, ATerm to) +{ + int ifrom; + int ito; + int r; + + if((ATgetType(from) != AT_REAL && ATgetType(from) != AT_INT) || + (ATgetType(to) != AT_REAL && ATgetType(to) != AT_INT)) + return NULL; + NUMERIC_ATERM_TO_REAL(ifrom, from); + NUMERIC_ATERM_TO_REAL(ito, to); + r = ifrom + (unsigned)((float)(ito - ifrom + 1) * rand() / (RAND_MAX + 1.)); + return (ATerm) ATmakeInt(r); +} Index: src/lib/native/Makefile.am --- src/lib/native/Makefile.am (revision 48) +++ src/lib/native/Makefile.am (working copy) @@ -5,7 +5,7 @@ ## Mail <sigoure.benoit@lrde.epita.fr> ## ## Started on Wed May 10 19:27:12 2006 SIGOURE Benoit -## Last update Thu May 25 20:19:00 2006 SIGOURE Benoit +## Last update Tue Jun 6 15:13:38 2006 SIGOURE Benoit ## include $(top_srcdir)/config/toplevel.mk @@ -16,7 +16,8 @@ libstr_reals_la_SOURCES = $(include_HEADERS) \ ceil.c \ floor.c \ - power.c + power.c \ + rand.c # FIXME: Detect in configure whether -lm needs to be used. libstr_reals_la_LIBADD = $(SSL_LIBS) -lm Index: src/str/prism-desugar.str --- src/str/prism-desugar.str (revision 48) +++ src/str/prism-desugar.str (working copy) @@ -41,13 +41,13 @@ ** formulas and ExpandFormulas. */ prism-desugar-first-pass = - ConstInt(id, prism-desugar) + ?Int(_); IntToDouble + <+ ExpandStaticConsts; prism-desugar-first-pass // we must desugar the + <+ ExpandFormulas; prism-desugar-first-pass // expansed code. + <+ ConstInt(id, prism-desugar) <+ ConstDouble(id, prism-desugar) <+ ConstBool(id, prism-desugar) <+ FormulaDef(id, prism-desugar) - <+ ?Int(_); IntToDouble - <+ ExpandStaticConsts - <+ ExpandFormulas <+ all(prism-desugar-first-pass) rules Index: src/str/builtin-rand.str --- src/str/builtin-rand.str (revision 48) +++ src/str/builtin-rand.str (working copy) @@ -20,48 +20,39 @@ ** rand(x) -> rand(x, 0) if x < 0 */ DesugarRand: Rand([arg]) -> Rand([arg1, arg2]) - where ?current-term + where desugar-rand(|arg) => (arg1, arg2) + + DesugarRand: + StaticRand([arg]) -> StaticRand([arg1, arg2]) + where desugar-rand(|arg) => (arg1, arg2) + +strategies + + desugar-rand(|arg) = + ?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 + !(arg', Int("0")) else - !Int("0") => arg1 - ; !arg' => arg2 + !(Int("0"), arg') end +rules + 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 - <invalid-call-to-rand-non-int> current-term - 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 + where check-rand-args(|"rand", args) => (from, to) /* 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") )) + /* template: 1/(to-from+1):(rand-var'=FIXME) */ + ; !ProbUpdate( Div(Int("1"), Int( <addS>(<subtS>(to, from), "1") )) , UpdateList([UpdateElement(IdentifierPrime(rand-var), FIXME())])) /* generate the updates by replacing the FIXME */ ; {| RandUpdateList: - for-loop(gen-rand-update-list | ifrom, ito, "1", []) + for-loop(gen-rand-update-list | from, to, "1", []) ; bagof-RandUpdateList |} ; reverse // bagof gives us the list in reverse order @@ -69,12 +60,52 @@ ; !ProbUpdateList(<id>) => u /* inject that node in a module */ ; !|[ module ~id:rand-var - ~id:rand-var : [~int:ifrom..~int:ito]; + ~id:rand-var : [~int:from..~int:to]; [] true -> u; endmodule ]| => rand-gen-module /* save this module in a DR for later retrieval */ ; rules(RandGenModules:+ _ -> rand-gen-module) + EvalRand: + StaticRand(args) -> Int(rand-val) + where check-rand-args(|"static_rand", args) => (from, to) + ; rand(|<string-to-int> from, <string-to-int> to) + ; int-to-string => rand-val + +strategies + + /** + ** Ensure that the arguments passed to rand or static_rand builtin are + ** correct: + ** - It must have exactly two arguments. + ** - Both arguments must be statically evaluable as Int(_). + ** - The first argument must be lesser than or equal to the second. + ** @param builtin-name: String used in error messages + ** @param args: arguments of the builtin call + ** @return (to, from) where to and from are integers. + */ + check-rand-args(|builtin-name, args) = + ?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: ", + builtin-name, " 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 + <invalid-call-to-rand-non-int> current-term + end + ; if <gtS>(ifrom, ito) then + err-msg(|<concat-strings>["invalid call to XRM builtin: ", + builtin-name, "(x,y) where x > y"]) + ; !current-term; debug; <xtc-exit> 4 + end + ; !(ifrom, ito) + strategies gen-rand-update-list(|i, data) = @@ -86,3 +117,17 @@ " arguments must be statically evaluable"]) ; debug ; <xtc-exit> 4 + +strategies + + /** + ** Returns a random integer between `from' and `to' (included). + ** @param from Integer + ** @param to Integer + ** @return Integer + ** @warning You must call <set-random-seed> seed before calling this + ** strategy, otherwise every run will generate the same sequence of + ** random numbers. + */ + rand(|from, to) = + prim("STR_REALS_rand", from, to) Index: src/str/xrm-front.str --- src/str/xrm-front.str (revision 48) +++ src/str/xrm-front.str (working copy) @@ -40,6 +40,7 @@ /** pipeline of transformations performed by xrm-front */ xrm-front-pipeline = notice-msg(|"transformation pipeline starting") + ; where(<set-random-seed> (<time>)) ; xrm-to-prism ; dbg(|"xrm-to-prism finished") ; if must-desugar then Index: src/syn/xrm/XRM-Expression.sdf --- src/syn/xrm/XRM-Expression.sdf (revision 48) +++ src/syn/xrm/XRM-Expression.sdf (working copy) @@ -14,8 +14,10 @@ %% ExpressionFunc ::= %% (* older builtin functions for backwards compat. *) %% "rand" "(" Expression {"," Expression} ")" + %% | "static_rand" "(" Expression {"," Expression} ")" %% (* builtin functions calls using the "func" notation *) %% | "func" "(" "rand" "," Expression {"," Expression} ")" + %% | "func" "(" "static_rand" "," Expression {"," Expression} ")" context-free syntax ArrayAccess -> Expression @@ -27,9 +29,16 @@ ArrayAccess "?=" {Range ","}+ -> Expression {cons("ExistsEq")} ArrayAccess "?!=" {Range ","}+ -> Expression {cons("ExistsNotEq")} + %% rand builtin "rand" "(" {Expression ","}+ ")" -> Expression {cons("Rand")} "func" "(" "rand" "," {Expression ","}+ ")" -> Expression {cons("Rand")} + %% static rand builtin + "static_rand" "(" {Expression ","}+ ")" + -> Expression {cons("StaticRand")} + "func" "(" "static_rand" "," {Expression ","}+ ")" + -> Expression {cons("StaticRand")} + %% NOTE: remember: priorities are transitive in SDF. %% The following priorities are marked either with "inherited" or "new". %% The former means that these priorities are inherited from the base