feat: Implement Chapter9
Also provides proper associativity on the operators, to avoid ambiguous parses. This completes all of the examples in the Spoofax Tutorial/Reference that use the propositional signature.
This commit is contained in:
parent
fddc94a906
commit
ba130ecb0f
17 changed files with 402 additions and 25 deletions
|
@ -58,19 +58,18 @@ test sec5_1_2_test1_cnf_ex [[
|
|||
|
||||
test sec5_1_2_test1_both [[
|
||||
(r -> p & q) & p
|
||||
]] run dcnf to Atom("x")
|
||||
//(Or(And(Not(Atom("r")),Atom("p")),And(And(Atom("p"),Atom("q")),Atom("p"))),
|
||||
// And(And(Or(Not(Atom("r")), Atom("p")),
|
||||
// Or(Not(Atom("r")), Atom("q"))),
|
||||
// Atom("p")))
|
||||
]] run dcnf to (Or(And(Not(Atom("r")),Atom("p")),And(And(Atom("p"),Atom("q")),Atom("p"))),
|
||||
And(And(Or(Not(Atom("r")), Atom("p")),
|
||||
Or(Not(Atom("r")), Atom("q"))),
|
||||
Atom("p")))
|
||||
|
||||
test sec5_3_1_test1_dnf_ex [[
|
||||
(r -> p & q) & p
|
||||
]] run dnf4 to Or(And(Not(Atom("r")),Atom("p")),And(And(Atom("p"),Atom("q")),Atom("p")))
|
||||
]] run dnf-laws to Or(And(Not(Atom("r")),Atom("p")),And(And(Atom("p"),Atom("q")),Atom("p")))
|
||||
|
||||
test sec5_3_1_test1_cnf_ex [[
|
||||
(r -> p & q) & p
|
||||
]] run cnf4 to And(And(Or(Not(Atom("r")), Atom("p")),
|
||||
]] run cnf-laws to And(And(Or(Not(Atom("r")), Atom("p")),
|
||||
Or(Not(Atom("r")), Atom("q"))),
|
||||
Atom("p"))
|
||||
|
||||
|
@ -110,15 +109,15 @@ To illustrate extending a rule, we need to give the rule we're going to extend
|
|||
a different identifier and add both definitions to that (otherwise our original
|
||||
rule `SwapArgs` would already have been extended).
|
||||
|
||||
The `chap6.str` file also includes a solution to the exercise in
|
||||
[Section 6.2](http://www.metaborg.org/en/latest/source/langdev/meta/lang/stratego/strategoxt/06-rules-and-strategies.html#what-is-a-strategy).
|
||||
On the other hand, it is not clear whether the Spoofax Eclipse IDE has a "debug"
|
||||
operator for Stratego, or if so how it would work, so the repository does not
|
||||
The `chap6.str` file also includes a solution to the exercise
|
||||
in {! ../docrefs/sec6.2.md !}. On the other hand, it is not clear whether
|
||||
the Spoofax Eclipse IDE has a "debug" operator for Stratego, or if so how
|
||||
it would work within the IDE, so the repository does not
|
||||
attempt to implement the "debug" example.
|
||||
|
||||
The remainder of the chapter (from section 6.3 on) consists of general information
|
||||
about Stratego syntax and information about the Stratego compiler. As it's not
|
||||
clear if the latter applies to the Spoofax Eclipse IDE, there are no further test
|
||||
clear whether the latter applies to the Spoofax Eclipse IDE, there are no further test
|
||||
cases in this repository beyond Section 6.2.
|
||||
**/
|
||||
|
||||
|
@ -152,10 +151,10 @@ test sec6_2_invoke_rule_ex [[
|
|||
|
||||
test sec6_2_innermost_ex [[
|
||||
p = q
|
||||
]] run dnf4 to Or(Or(And(Not(Atom("p")),Not(Atom("q"))),
|
||||
And(Not(Atom("p")),Atom("p"))),
|
||||
Or(And(Atom("q"),Not(Atom("q"))),
|
||||
And(Atom("q"),Atom("p"))))
|
||||
]] run dnf-laws to Or(Or(And(Not(Atom("p")),Not(Atom("q"))),
|
||||
And(Not(Atom("p")),Atom("p"))),
|
||||
Or(And(Atom("q"),Not(Atom("q"))),
|
||||
And(Atom("q"),Atom("p"))))
|
||||
|
||||
test sec6_2_dnf_exercise_ex [[
|
||||
p = q
|
||||
|
@ -199,7 +198,7 @@ test sec7_3_repeat_small_ex [[
|
|||
]] run repeatmaybeAB to Impl(True(), False())
|
||||
|
||||
test sec7_3_repeat_big_ex [[
|
||||
(1 -> (1 -> (1 -> (1 -> 0)))) | 0
|
||||
(1 -> 1 -> 1 -> 1 -> 0) | 0
|
||||
]] run repeatmaybeAB to Impl(True(), Impl(True(), Impl(True(),
|
||||
Impl(True(), False()))))
|
||||
|
||||
|
@ -236,3 +235,232 @@ test sec8_5_1_wrap_ex [[
|
|||
test sec8_5_2_project_ex [[
|
||||
p | !p
|
||||
]] run TermProj to Atom("p")
|
||||
|
||||
/** md
|
||||
### Chapter 9
|
||||
|
||||
This chapter is much more in the style of the early chapters: there are several
|
||||
explicit Stratego modules, and we incorporate each one into this repository. As
|
||||
before, we need to differentiate the names in some modules since they all end
|
||||
up being loaded at once; but we also take advantage of the common sections of
|
||||
some of the modules and re-use rather than repeat the code. In addition, the
|
||||
disjunctive and conjunctive normal forms of the same test expression as used
|
||||
in Chapter Five are used for test cases in `trans/manual-suite.spt`.
|
||||
|
||||
**/
|
||||
|
||||
test chap9_dnf4_ex [[
|
||||
(r -> p & q) & p
|
||||
]] run dnf4 to Or(And(Not(Atom("r")),Atom("p")),And(And(Atom("p"),Atom("q")),Atom("p")))
|
||||
|
||||
test chap9_dnf6_ex [[
|
||||
(r -> p & q) & p
|
||||
]] run dnf6 to Or(And(Not(Atom("r")),Atom("p")),And(And(Atom("p"),Atom("q")),Atom("p")))
|
||||
|
||||
test chap9_dnf7_ex [[
|
||||
(r -> p & q) & p
|
||||
]] run dnf7 to Or(And(Not(Atom("r")),Atom("p")),And(And(Atom("p"),Atom("q")),Atom("p")))
|
||||
|
||||
test chap9_cnf7_ex [[
|
||||
(r -> p & q) & p
|
||||
]] run cnf7 to And(And(Or(Not(Atom("r")), Atom("p")),
|
||||
Or(Not(Atom("r")), Atom("q"))),
|
||||
Atom("p"))
|
||||
|
||||
/** md
|
||||
The key point to know about
|
||||
[Chapter 9](http://www.metaborg.org/en/latest/source/langdev/meta/lang/stratego/strategoxt/09-traversal-strategies.html),
|
||||
however, is that there is a mistake that affects examples `prop-dnf8` through
|
||||
`prop-dnf10`. The difficulty is in this definition:
|
||||
```Stratego
|
||||
strategies
|
||||
propbu(s) = proptr(propbu(s)); s
|
||||
```
|
||||
|
||||
Recall that `proptr` is defined as follows: (Note that our implementation calls
|
||||
it `proptr7` to distinguish it from different definitions for `proptr` in other
|
||||
examples.)
|
||||
```Stratego
|
||||
{! ../trans/prop-dnf7.str extract:
|
||||
start: '(rules\n*)'
|
||||
stop: strategies
|
||||
!}
|
||||
```
|
||||
|
||||
So `propbu` must be defined as:
|
||||
```Stratego
|
||||
{! ../trans/prop-dnf8.str extract:
|
||||
start: strategies
|
||||
stop: '(.*propbu8.*)'
|
||||
!}
|
||||
```
|
||||
|
||||
The point is that `proptr` cannot apply to `Atom`s and logical constants, and so
|
||||
fails when it reaches such nodes in the AST. Without the `try` in the definition
|
||||
of the `propbu` traversal, any such failure propagates to a failure of the entire
|
||||
strategy.
|
||||
**/
|
||||
|
||||
test chap9_dnf8_ex [[
|
||||
(r -> p & q) & p
|
||||
]] run dnf8 to Or(And(Not(Atom("r")),Atom("p")),And(And(Atom("p"),Atom("q")),Atom("p")))
|
||||
|
||||
test chap9_cnf8_ex [[
|
||||
(r -> p & q) & p
|
||||
]] run cnf8 to And(And(Or(Not(Atom("r")), Atom("p")),
|
||||
Or(Not(Atom("r")), Atom("q"))),
|
||||
Atom("p"))
|
||||
|
||||
/** md
|
||||
Example `prop-dnf9` simply re-uses `propbu8`.
|
||||
**/
|
||||
|
||||
test chap9_dnf9_ex [[
|
||||
(r -> p & q) & p
|
||||
]] run dnf9 to Or(And(Not(Atom("r")),Atom("p")),And(And(Atom("p"),Atom("q")),Atom("p")))
|
||||
|
||||
test chap9_cnf9_ex [[
|
||||
(r -> p & q) & p
|
||||
]] run cnf9 to And(And(Or(Not(Atom("r")), Atom("p")),
|
||||
Or(Not(Atom("r")), Atom("q"))),
|
||||
Atom("p"))
|
||||
|
||||
/** md
|
||||
And a similar fix is made to `prop-dnf10`:
|
||||
```Stratego
|
||||
{! ../trans/prop-dnf10.str !}
|
||||
```
|
||||
|
||||
**/
|
||||
|
||||
test sec9_1_dnf10_ex [[
|
||||
(r -> p & q) & p
|
||||
]] run dnf10 to Or(And(Not(Atom("r")),Atom("p")),And(And(Atom("p"),Atom("q")),Atom("p")))
|
||||
|
||||
test sec9_1_cnf10_ex [[
|
||||
(r -> p & q) & p
|
||||
]] run cnf10 to And(And(Or(Not(Atom("r")), Atom("p")),
|
||||
Or(Not(Atom("r")), Atom("q"))),
|
||||
Atom("p"))
|
||||
|
||||
/** md
|
||||
There is another issue in the "Format Checking" example in section 9.1. It lies
|
||||
with the strategy used to determine if an expression is an atom or the negation
|
||||
of an atom. The expression shown is `Not(Atom(x)) <+ Atom(x)`. This appears to
|
||||
be a left choice of two congruences. But a congruence expects a strategy as an
|
||||
argument, whereas here `x` is simply a free variable. There are a couple of
|
||||
fixes to write an expression that checks whether a term is just an `Atom()` call
|
||||
or the negation of one. The first possibility is to use match expressions, e.g.
|
||||
`?Not(Atom(x)) <+ ?Atom(x)`. However, as that can run into issues with the scoping
|
||||
of the variable `x`, we opted for sticking with the congruences, just using a
|
||||
strategy that always succeeds in the inner position, namely `id`:
|
||||
```Stratego
|
||||
{! ../trans/sec9_1.str terminate: exercise !}
|
||||
```
|
||||
**/
|
||||
|
||||
test sec9_1_disj-nf_fails [[
|
||||
(r -> p & q) & p
|
||||
]] run disj-nf fails
|
||||
|
||||
test sec9_1_conj-nf_fails [[
|
||||
(r -> p & q) & p
|
||||
]] run conj-nf fails
|
||||
|
||||
test sec9_1_disj-nf [[
|
||||
(!r & p) | (p & q & p)
|
||||
]] run disj-nf
|
||||
|
||||
test sec9_1_conj-nf [[
|
||||
(!r | p) & (!r | q) & p
|
||||
]] run conj-nf
|
||||
|
||||
test sec9_1_dnf11_ex [[
|
||||
(r -> p & q) & p
|
||||
]] run dnf11 to Or(And(Not(Atom("r")),Atom("p")),And(And(Atom("p"),Atom("q")),Atom("p")))
|
||||
|
||||
test sec9_1_cnf11_ex [[
|
||||
(r -> p & q) & p
|
||||
]] run cnf11 to And(And(Or(Not(Atom("r")), Atom("p")),
|
||||
Or(Not(Atom("r")), Atom("q"))),
|
||||
Atom("p"))
|
||||
|
||||
/** md
|
||||
Also note that the repository does not include `prop-dnf12` because at this
|
||||
point the strategies there have become identical to the ones
|
||||
in {! ../docrefs/sec6.2.md !} used to introduce the idea of splitting
|
||||
transformations into local rewrite rules applied via a traversal strategy. So
|
||||
they have already been implemented and tested above.
|
||||
|
||||
On the other hand, in `trans/sec9_1.str`, the repository does contain a
|
||||
solution for the second exercise in
|
||||
[Section 9.1.2](http://www.metaborg.org/en/latest/source/langdev/meta/lang/stratego/strategoxt/09-traversal-strategies.html#visiting-one-subterm).
|
||||
**/
|
||||
|
||||
test sec9_1_2_second_exercise_inner_ex [[
|
||||
!!p | (!!q | r)
|
||||
]] run inner-soln to Or(Atom("p"), Or(Atom("q"), Atom("r")))
|
||||
|
||||
test sec9_1_2_second_exercise_outer_ex [[
|
||||
!!p | (!!q | r)
|
||||
]] run outer-soln to Impl(Not(Atom("p")), Impl(Not(Atom("q")), Atom("r")))
|
||||
|
||||
/* Note that the actual output of the following test matches
|
||||
the inner application. However, according to the manual, it would
|
||||
also be a correct implementation for it to produce
|
||||
`Impl(Not(Atom("p")), Or(Atom("q"), Atom("r")))`, which could not
|
||||
result from either outer or inner application.
|
||||
*/
|
||||
test sec9_1_2_second_exercise_random_ex [[
|
||||
!!p | (!!q | r)
|
||||
]] run random-soln to Atom("x")
|
||||
|
||||
test sec9_2_eval_bottomup_ex [[
|
||||
1 & !(0 | 1)
|
||||
]] run eval1 to False()
|
||||
|
||||
/* This test fails deliberately, to show that topdown evaluation
|
||||
does not go all the way to completion.
|
||||
*/
|
||||
test sec9_2_eval_topdown [[
|
||||
1 & !(0 | 1)
|
||||
]] run eval2 to False()
|
||||
|
||||
test sec9_2_eval_exercise_bottomup_ex [[
|
||||
(1 | 0) & (0 | 1)
|
||||
]] run eval1 to True()
|
||||
|
||||
/* Ditto for this one.*/
|
||||
test sec9_2_eval_exercise_topdown [[
|
||||
(1 | 0) & (0 | 1)
|
||||
]] run eval2 to True()
|
||||
|
||||
test sec9_2_desugar_topdown_ex [[
|
||||
p = q
|
||||
]] run desugar to And(Or(Not(Atom("p")),Atom("q")),Or(Not(Atom("q")),Atom("p")))
|
||||
|
||||
/* And ditto for this one. */
|
||||
test sec9_2_desugar_bottomup [[
|
||||
p = q
|
||||
]] run desugar2 to And(Or(Not(Atom("p")),Atom("q")),Or(Not(Atom("q")),Atom("p")))
|
||||
|
||||
test sec9_2_impl-nf_repeated_ex [[
|
||||
p & q
|
||||
]] run impl-nf1 to Impl(Impl(Atom("p"),Impl(Atom("q"),False())),False())
|
||||
|
||||
/* And ditto for this one. */
|
||||
test sec9_2_impl-nf_once [[
|
||||
p & q
|
||||
]] run impl-nf2 to Impl(Impl(Atom("p"),Impl(Atom("q"),False())),False())
|
||||
|
||||
/** md
|
||||
I couldn't think of a natural application of paramorphism in the context of
|
||||
the Spoofax Propositional Language, so there is no solution provided for the
|
||||
exercise just before
|
||||
[Section 9.2.1](http://www.metaborg.org/en/latest/source/langdev/meta/lang/stratego/strategoxt/09-traversal-strategies.html#cascading-transformations).
|
||||
|
||||
The rest of Chapter 9 and all of the remaining chapters deal
|
||||
either with signatures other than SPL or
|
||||
just with abstract principles, so that concludes the Stratego examples provided
|
||||
in this repository.
|
||||
**/
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue