From 28a3370d03d716fd8880189880fe93783da02cb7 Mon Sep 17 00:00:00 2001 From: Glen Whitney Date: Sat, 16 Jan 2021 15:11:47 -0800 Subject: [PATCH] feat: Add SPT as an alternate means of running Stratego strategies Also completed and documented Sec 4.2 of the Stratego Tutorial/Reference manual --- test/manual-suite.spt | 12 ++++++ trans/analysis.str | 5 ++- trans/prop-dnf-rules.str | 88 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 100 insertions(+), 5 deletions(-) create mode 100644 test/manual-suite.spt diff --git a/test/manual-suite.spt b/test/manual-suite.spt new file mode 100644 index 0000000..f8e41d0 --- /dev/null +++ b/test/manual-suite.spt @@ -0,0 +1,12 @@ +module manual-suite +language Spoofax-Propositional-Language + +test sec4_2_test3 [[ + (r -> p & q) & p +]] run dnf to Atom("x") + +test sec4_2_test3_ex [[ + (r -> p & q) & p +]] run dnf to Or(And(Not(Atom("r")),Atom("p")),And(And(Atom("p"),Atom("q")),Atom("p"))) + + diff --git a/trans/analysis.str b/trans/analysis.str index a1f424c..5228868 100644 --- a/trans/analysis.str +++ b/trans/analysis.str @@ -4,6 +4,7 @@ imports nabl2/api nabl2/runtime + nabl2/shared/- statics @@ -11,7 +12,9 @@ imports rules // Analysis - editor-analyze = nabl2-analyze(id) +// editor-analyze = nabl2-analyze(id) + strip-indices : AnalysisResult([(r,Full(y,a,l,m,n))]) -> AnalysisResult([(r,Full(y,a,l,m,n))]) + editor-analyze = nabl2-analyze(id); strip-indices rules // Debugging diff --git a/trans/prop-dnf-rules.str b/trans/prop-dnf-rules.str index dad4386..bbce794 100644 --- a/trans/prop-dnf-rules.str +++ b/trans/prop-dnf-rules.str @@ -48,12 +48,92 @@ to produce ``` {! ../syntax/examples/sec4.2_test3.dnf.aterm !} ``` -as verified in the manual (again, modulo the"ATom" typo in the manual). +as verified in the manual (again, modulo the "ATom" typo in the manual). However, we also want to use this second example to show another method of running Stratego strategies from the Eclipse IDE. -## Spoofax Testing Language +### Spoofax Testing Language -CONTINUE FROM HERE -**/ \ No newline at end of file +The +[Spoofax Testing Language](http://www.metaborg.org/en/latest/source/langdev/meta/lang/spt/index.html) +(SPT) is a declarative language that provides for a full range of tests +for a Spoofax language project. As such, it includes the ability to run an +arbitrary Stratego strategy on the results of parsing an arbitrary piece of +the language you're working with -- seemingly perfect for our interest in +trying our different Stratego transformations. + +So, we can just take our `test3` expression above and make it a part of +an SPT test suite, which we will call `test/manual-suite.spt`: +```SPT +{! ../test/manual-suite.spt terminate: '(.*run dnf)' !} +``` + +Once we have saved this file, the tests run automatically. What does this mean? +The file seems to be just "sitting there;" there's no indication that anything +is happening. That's because this test we've just written **succeeds**. All we +asked is that Spoofax run the `dnf` transformation on the results of parsing +the test expression. It did that, and the transformation succeeded. So all is +well, and no output is generated. + +But of course, we want to see what the _result_ of the transformation was. One +way of arranging that is to ask that SPT compare that result to a given AST. +If we use an AST like `Atom("x")` that can't possibly be the actual output +(since "x" does not occur in the input), then the error message will show +what the transformation actually produced. So we add just a bit to +`test/manual-suite.spt`: +```SPT +{! ../test/manual-suite.spt terminate: '(.*run dnf.*)$' !} +``` + +and now sure enough a little error symbol appears next to the test. If you hover +over it, a popup will show up, indicating that SPT was expecting `Atom("x")`, +but got... wait! What's this monstrosity? +``` +Got: Or(And(Not(Atom("r"{TermIndex("test/manual-suite.spt",1)}){TermIndex + ("test/manual-suite.spt",2)}),Atom("p"{TermIndex("test/manual-suite.spt",9)}) + {TermIndex("test/manual-suite.spt",10)}),And(And(Atom("p"{TermIndex("test/manual- + suite.spt",3)}){TermIndex("test/manual-suite.spt",4)},Atom("q"{TermIndex + ("test/manual-suite.spt",5)}){TermIndex("test/manual-suite.spt",6)}){TermIndex + ("test/manual-suite.spt",7)},Atom("p"{TermIndex("test/manual-suite.spt",9)}) + {TermIndex("test/manual-suite.spt",10)})) +``` + +Well, it is actually the result of running the `dnf` strategy on the result of +parsing ` {! ../syntax/examples/sec4.2_test3.spl !} `. It's just that Spoofax +automatically annotates every subterm of the parsed term with its location in +the input, and those annotations are carried through the Stratego +transformation. While this can be very helpful in figuring out exactly what +happened in the course of the transformation, it can also make the output +practically unreadable. + +Fortunately, we can strip this annotation if we like, by modifying the +`editor-analyze` rule in `trans/analysis.str` like so: +```Stratego +{! ../trans/analysis.str terminate: Debugging!} [rest of file omitted] +``` + +Now rebuild the project and re-run the SPT manual suite. (You may need to +do an irrelevant edit and save of the `test/manual-suite.spt` file, or +you can select this file in the project explorer and select the menu item +"Spoofax (meta) > Run all selected tests" to pop up a convenient window of +all test results.) Now you should see the much more readable +``` +Got: Or(And(Not(Atom("r")),Atom("p")),And(And(Atom("p"),Atom("q")),Atom("p"))) +``` +in the error message for the `sec4_2_test3` test. + +Of course, if you know the AST you expect to generate with your transformation, +you can also just tell SPT to compare against that, for example in our case +by adding a test to the manual suite like this: +```SPT +{! ../test/manual-suite.spt extract: + start: '(test sec4_2_test3_ex.*\n?)$' + stop: '^(.*run.*)$' +!} +``` + +Now if there is no error or warning on this test then you know the +`dnf` strategy produced the result shown in the `to` clause, and otherwise, +the actual result will be shown in the error popup. +**/