2021-01-15 17:57:30 +00:00
|
|
|
/** md
|
|
|
|
Title: Running a Strategy, continued
|
|
|
|
|
|
|
|
## Disjunctive Normal Form
|
|
|
|
|
|
|
|
The next Stratego example, in {! ../docrefs/sec4.2.md !}, extends
|
|
|
|
`prop-eval-rules` to convert SPL propositions into disjunctive normal form (DNF).
|
|
|
|
Once again, we can place the Stratego code in `trans/prop-dnf-rules.str`:
|
|
|
|
|
|
|
|
```Stratego
|
|
|
|
**/
|
|
|
|
/** md Include this code in documentation: */
|
|
|
|
module prop-dnf-rules
|
|
|
|
imports prop-eval-rules
|
|
|
|
rules
|
|
|
|
E : Impl(x, y) -> Or(Not(x), y)
|
|
|
|
E : Eq(x, y) -> And(Impl(x, y), Impl(y, x))
|
|
|
|
|
|
|
|
E : Not(Not(x)) -> x
|
|
|
|
|
|
|
|
E : Not(And(x, y)) -> Or(Not(x), Not(y))
|
|
|
|
E : Not(Or(x, y)) -> And(Not(x), Not(y))
|
|
|
|
|
|
|
|
E : And(Or(x, y), z) -> Or(And(x, z), And(y, z))
|
|
|
|
E : And(z, Or(x, y)) -> Or(And(z, x), And(z, y))
|
|
|
|
/* end of code inclusion **/
|
|
|
|
/** md rest of documentation
|
|
|
|
```
|
|
|
|
and create a `trans/prop-dnf.str` that defines a strategy for applying the
|
|
|
|
DNF rules and supplies the glue needed between ESV and Stratego:
|
|
|
|
```Stratego
|
|
|
|
{! prop-dnf.str !}
|
|
|
|
```
|
|
|
|
Now just importing `prop-dnf` in `trans/spoofax-propositional-language.str`
|
|
|
|
and adding a menu item to `editor/Manual.esv`:
|
|
|
|
```ESV
|
|
|
|
...
|
2021-01-17 18:15:32 +00:00
|
|
|
{! ../editor/Manual.esv extract: {start: menus, stop: dnf3} !}
|
2021-01-15 17:57:30 +00:00
|
|
|
```
|
|
|
|
should suffice to make the dnf strategy available in the "Spoofax > Manual"
|
|
|
|
menu.
|
|
|
|
|
|
|
|
Indeed, we can try it out on `syntax/examples/sec4.2_test3.spl`:
|
|
|
|
```SPL
|
|
|
|
{! ../syntax/examples/sec4.2_test3.spl !}
|
|
|
|
```
|
|
|
|
to produce
|
|
|
|
```
|
|
|
|
{! ../syntax/examples/sec4.2_test3.dnf.aterm !}
|
|
|
|
```
|
2021-01-16 23:11:47 +00:00
|
|
|
as verified in the manual (again, modulo the "ATom" typo in the manual).
|
2021-01-15 17:57:30 +00:00
|
|
|
|
|
|
|
However, we also want to use this second example to show another method of
|
|
|
|
running Stratego strategies from the Eclipse IDE.
|
|
|
|
|
2021-01-16 23:11:47 +00:00
|
|
|
### Spoofax Testing Language
|
2021-01-15 17:57:30 +00:00
|
|
|
|
2021-01-16 23:11:47 +00:00
|
|
|
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
|
2021-01-20 03:29:48 +00:00
|
|
|
{! ../test/manual-suite.spt extract:
|
2021-01-20 05:00:56 +00:00
|
|
|
start: '\*\*[/]'
|
2021-01-20 03:29:48 +00:00
|
|
|
terminate: '(.*run dnf)' !}
|
2021-01-16 23:11:47 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
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
|
2021-01-20 03:29:48 +00:00
|
|
|
{! ../test/manual-suite.spt extract:
|
2021-01-20 05:00:56 +00:00
|
|
|
start: '\*\*[/]'
|
2021-01-20 03:29:48 +00:00
|
|
|
terminate: '(.*run dnf.*)$' !}
|
2021-01-16 23:11:47 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
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.
|
|
|
|
**/
|