# -*- tcl -*- # Testsuite for pt::peg::op. # Copyright (c) 2018 Stefan Sobernig # [ok] drop unreachable # [ok] drop unrealizable # [ok] flatten # [ok] minimize # [ok] called # [ok] realizable # [ok] reachable # [ok] dechain # [ok] modeopt # ------------------------------------------------------------------------- # Basic syntax foreach op { called dechain flatten minimize modeopt reachable realizable {drop unreachable} {drop unrealizable} } { test pt-peg-op-set:${setimpl}-${op}-0.0 "$op, wrong#args, not enough" -body { pt::peg::op {*}$op } -returnCodes error -result "wrong # args: should be \"pt::peg::op $op container\"" test pt-peg-op-set:${setimpl}-${op}-0.1 "$op, wrong#args, too many" -body { pt::peg::op {*}$op Container X } -returnCodes error -result "wrong # args: should be \"pt::peg::op $op container\"" } # ------------------------------------------------------------------------- # General support for testing transforms proc sl {v} { # Remove comment lines regsub -all -line {^\s*#.*$} $v {} } proc g {s r} { # quick constructor of a grammar value return [list pt::grammar::peg [list rules $r start $s]] } proc TestTransformation {op data setImpl} { # Convert operation and data table into series of test cases set debug 0 # Note, the `op` changes the container (here ::In) in-place. append bodyScript [list {*}::pt::peg::op::$op ::In] \; if {$debug} { append bodyScript "puts stderr \"ASIS \[::In serialize\]\"" \; append bodyScript "puts stderr \"TOBE \[::Expected serialize\]\"" \; } # After the op, when all is well, the content of ::In should be # the same as ::Expected. append bodyScript "pt::peg equal \[::In serialize\] \[::Expected serialize\]" \; set n 1 foreach {inStart inRulesSet outStart outRulesSet} [sl $data] { set testLabel "pt-peg-op-set:${setImpl}-[join $op -]-$n" if {$debug} { puts stderr >>>>$testLabel<<<< } test $testLabel "OP '$op' vs. expected" -setup { pt::peg::container ::In deserialize [g $inStart $inRulesSet] pt::peg::container ::Expected deserialize [g $outStart $outRulesSet] } -body $bodyScript -result 1 -cleanup { ::In destroy ::Expected destroy } incr n } } # ------------------------------------------------------------------------- # op: called set n 0 foreach {inStart inRulesSet expectedSym} [sl { # --- epsilon {} {{} {}} # --- {n S} { S {is {x {t A} {* {n SYM}} {t B} {n OTHER} {n SYM}} mode value} A {is {n A} mode value} } {{} S A A S {SYM OTHER}} # --- {n S} { S {is {x {t A} {t B}} mode value} A {is {t a} mode value} B {is {t b} mode value} } {{} S A {} B {} S {}} # --- {n S} { S {is {epsilon} mode value} } {{} S S {}} }] { test pt-peg-op-set:${setimpl}-called.$n {op called} -setup { pt::peg::container ::In deserialize [g $inStart $inRulesSet] } -body { set r [pt::peg::op called ::In] dict filter $r script {key val} { ::tcl::mathop::in $key [lsort [dict keys $r]] } } -cleanup { ::In destroy } -result $expectedSym incr n } unset n # ------------------------------------------------------------------------- # op: flatten TestTransformation flatten { # --- stays as-is #1 epsilon {} epsilon {} # --- stays as-is #2 {n S} { S {is {n A} mode value} A {is {t a} mode value} } {n S} { S {is {n A} mode value} A {is {t a} mode value} } # --- flatten start expr and rules: single-element sequences {x {n S}} { S {is {x {n A}} mode value} A {is {n A} mode value} } {n S} { S {is {n A} mode value} A {is {n A} mode value} } # --- flatten start expr and rules: single-element choices {/ {n S}} { S {is {/ {n A}} mode value} A {is {n A} mode value} } {n S} { S {is {n A} mode value} A {is {n A} mode value} } # --- flatten start expr and rules: nested sequences {x {n S}} { S {is {x {n A} {x {n A} {n A}}} mode value} A {is {n A} mode value} } {n S} { S {is {x {n A} {n A} {n A}} mode value} A {is {n A} mode value} } # --- flatten start expr and rules: nested choices {x {n S}} { S {is {/ {n A} {/ {n A} {n A}}} mode value} A {is {n A} mode value} } {n S} { S {is {/ {n A} {n A} {n A}} mode value} A {is {n A} mode value} } } $setimpl # ------------------------------------------------------------------------- # op: realizable set n 0 foreach {inStart inRulesSet expectedSym} [sl { # --- just start expression epsilon {} {{}} # -- all realizable, incl. start expression {n S} { S {is {n X} mode value} X {is {t x} mode leaf} } {{} S X} # -- not even start expression {n S} { S {is {n X} mode value} X {is {n X} mode value} } {} # -- not even start expression {n S} { S {is {n X} mode value} X {is {n X} mode value} } {} # -- X is unrealizable {n S} { S {is {? {n X}} mode value} X {is {n X} mode value} } {{} S} # -- X is unrealizable {n S} { S {is {/ {n X} {t y}} mode value} X {is {n X} mode value} } {{} S} # -- X <- 'A' 'B' X / 'C' X 'A'; X is unrealizable {n S} { S {is {/ {n X} {t y}} mode value} X {is {/ {x {t A} {t B} {n X}} {x {t C} {n X} {t A}}} mode value} } {{} S} # -- X <- 'A' 'B' X / 'C' X 'A' / 'x'; X *is* realizable {n S} { S {is {/ {n X} {t y}} mode value} X {is {/ {x {t A} {t B} {n X}} {x {t C} {n X} {t A}} {t x}} mode value} } {{} S X} # -- E is unrealizable {n S} { S {is {/ {x {n B} {t b}} {x {n C} {t c}} {x {n E} {t e}}} mode value} B {is {/ {x {n B} {t b}} {t b}} mode value} C {is {/ {x {n C} {t c}} {t c}} mode value} E {is {x {n E} {t e}} mode value} } {{} B C S} # -- S remains realizable (*) {n S} { S {is {* {n X}} mode value} X {is {n X} mode value} } {{} S} }] { test pt-peg-op-set:${setimpl}-realizable.$n {op realizable} -setup { pt::peg::container ::In deserialize [g $inStart $inRulesSet] } -body { lsort [pt::peg::op realizable ::In] } -cleanup { ::In destroy } -result $expectedSym incr n } unset n # ------------------------------------------------------------------------- # op: drop unrealizable TestTransformation "drop unrealizable" { # (1) stays as-is epsilon {} epsilon {} # (2) S <-- X; X <-- X; => epsilon {n S} { S {is {n X} mode value} X {is {n X} mode value} } epsilon {} # (3) S <-- X?; X <-- X; => S <-- epsilon {n S} { S {is {? {n X}} mode value} X {is {n X} mode value} } {n S} { S {is epsilon mode value} } # (4) S <-- X*; X <-- X; => S <-- epsilon {n S} { S {is {* {n X}} mode value} X {is {n X} mode value} } {n S} { S {is epsilon mode value} } # (5) S <-- X 'y'; X <-- X; => epsilon {n S} { S {is {x {n X} {t y}} mode value} X {is {n X} mode value} } epsilon {} # (6) S <-- X / 'y'; X <-- X; => S <-- 'y' (unflattened!) {n S} { S {is {/ {n X} {t y}} mode value} X {is {n X} mode value} } {n S} { S {is {/ {t y}} mode value} } } $setimpl # ------------------------------------------------------------------------- # op: reachable set n 0 foreach {inStart inRulesSet expectedSym} [sl { # --- none epsilon {} {} # -- D is not reachable {n S} { S {is {/ {x {n B} {t b}} {x {n C} {t c}} {x {n E} {t e}}} mode value} B {is {/ {x {n B} {t b}} {t b}} mode value} C {is {/ {x {n C} {t c}} {t c}} mode value} D {is {/ {x {n B} {t d}} {x {n C} {t d}} {t d}} mode value} E {is {x {n E} {t e}} mode value} } {B C E S} # -- all reachable {n S} { S {is {/ {x {n A} {n B}} {t a}} mode value} A {is {x {t a} {n A}} mode value} B {is {t a} mode leaf} } {A B S} }] { test pt-peg-op-set:${setimpl}-reachable.$n {op reachable} -setup { pt::peg::container ::In deserialize [g $inStart $inRulesSet] } -body { lsort [pt::peg::op reachable ::In] } -cleanup { ::In destroy } -result $expectedSym incr n } unset n # ------------------------------------------------------------------------- # op: drop unreachable TestTransformation "drop unreachable" { # (1) stays as-is epsilon {} epsilon {} # S <-- a; A <-- a ==> S <-- a (A not reachable, dropped) {n S} { S {is {t a} mode leaf} A {is {t a} mode void} } {n S} { S {is {t a} mode leaf} } # S <-- a; A <-- B; B <-- a ==> A, B unreachable, dropped {n S} { S {is {t a} mode leaf} A {is {n B} mode void} B {is {t a} mode void} } {n S} { S {is {t a} mode leaf} } } $setimpl # ------------------------------------------------------------------------- # op: dechain TestTransformation dechain { # --- stays as-is epsilon {} epsilon {} {n S} { S {is {x {n A} {t s}} mode value} A {is {n B} mode value} B {is {t b} mode value} } {n S} { S {is {x {n A} {t s}} mode value} A {is {n B} mode value} B {is {t b} mode value} } # --- basic chain: A <- B <- C (leaf) <- c |> A <- C (leaf) <- c {n S} { S {is {x {n A} {t s}} mode value} A {is {n B} mode value} B {is {n C} mode value} C {is {t c} mode value} } {n S} { S {is {x {n A} {t s}} mode value} A {is {n C} mode value} B {is {n C} mode value} C {is {t c} mode value} } # --- longer chain {n S} { S {is {x {n A} {t s}} mode value} E {is {t e} mode leaf} A {is {n B} mode value} D {is {n E} mode value} B {is {n C} mode value} C {is {n D} mode value} } {n S} { S {is {x {n A} {t s}} mode value} A {is {n E} mode value} B {is {n D} mode value} C {is {n E} mode value} D {is {n E} mode value} E {is {t e} mode leaf} } # --- basic cycle: A <- B <- A {n S} { S {is {x {n A} {t s}} mode value} A {is {n B} mode value} B {is {n A} mode value} } {n S} { S {is {x {n A} {t s}} mode value} A {is {n B} mode value} B {is {n A} mode value} } # --- basic (indirect) cycle: A <- B <- C <- A {n S} { S {is {x {n A} {t s}} mode value} A {is {n B} mode value} B {is {n C} mode value} C {is {n A} mode value} } {n S} { S {is {x {n A} {t s}} mode value} A {is {n B} mode value} B {is {n C} mode value} C {is {n A} mode value} } # --- basic chain plus renaming for self-recursive leaves {n S} { S {is {x {n A} {t s}} mode value} A {is {n B} mode value} B {is {n C} mode value} C {is {x {n C} {t c}} mode value} } {n S} { S {is {x {n A} {t s}} mode value} A {is {n C} mode value} B {is {n C} mode value} C {is {x {n C} {t c}} mode value} } # {n S} { # S {is {x {n A} {t s}} mode value} # A {is {x {n A} {t c}} mode value} # B {is {x {n B} {t c}} mode value} # C {is {x {n C} {t c}} mode value} # } # --- start expression: {} <- Z <- S <- s |> {} <- Z <- s {n Z} { Z {is {n S} mode value} S {is {t s} mode value} } {n Z} { Z {is {n S} mode value} S {is {t s} mode value} } # --- TODO: start expression: {} <- Z <- S (leaf) <- s |> {} <- S <- s # {n Z} { # Z {is {n S} mode value} # S {is {t s} mode value} # } # {n S} { # S {is {t s} mode value} # } # --- broken chain #1 (undefined leaves?) {n S} { S {is {x {n A} {t s}} mode value} A {is {n B} mode value} } {n S} { S {is {x {n A} {t s}} mode value} A {is {n B} mode value} } # --- broken chain #2 (undefined leaves?) {n S} { S {is {x {n A} {t s}} mode value} A {is {n B} mode value} B {is {n C} mode value} } {n S} { S {is {x {n A} {t s}} mode value} A {is {n C} mode value} B {is {n C} mode value} } # --- intermittents {n S} { S {is {x {n A} {t s}} mode value} A {is {n B} mode value} B {is {n C} mode value} C {is {x {n X} {t c}} mode value} X {is {n Y} mode value} Y {is {n Z} mode value} Z {is {x {n Z} {t z}} mode value} } {n S} { S {is {x {n A} {t s}} mode value} A {is {n C} mode value} B {is {n C} mode value} C {is {x {n X} {t c}} mode value} X {is {n Z} mode value} Y {is {n Z} mode value} Z {is {x {n Z} {t z}} mode value} } # {n S} { # S {is {x {n A} {t s}} mode value} # A {is {x {n X} {t c}} mode value} # B {is {x {n X} {t c}} mode value} # C {is {x {n X} {t c}} mode value} # X {is {x {n X} {t z}} mode value} # Y {is {x {n Y} {t z}} mode value} # Z {is {x {n Z} {t z}} mode value} # } # --- incompat modes #1a {n S} { S {is {x {n A} {t s}} mode value} A {is {n B} mode void} B {is {n C} mode void} C {is {t c} mode value} } {n S} { S {is {x {n A} {t s}} mode value} A {is {n C} mode void} B {is {n C} mode void} C {is {t c} mode value} } # --- incompat modes #1b {n S} { S {is {x {n A} {t s}} mode value} A {is {n B} mode void} B {is {n C} mode value} C {is {t c} mode value} } {n S} { S {is {x {n A} {t s}} mode value} A {is {n B} mode void} B {is {n C} mode value} C {is {t c} mode value} } # X <- Z # # X Z dechain notes # value value| yes | value is passed {n S} { S {is {n X} mode value} X {is {n Z} mode value} Z {is {t z} mode value} } {n S} { S {is {n Z} mode value} X {is {n Z} mode value} Z {is {t z} mode value} } # X Z dechain notes # leaf value| no | generated value was discarded, inlined doesn't. Z may be implied void {n S} { S {is {n X} mode leaf} X {is {n Z} mode value} Z {is {t z} mode value} } {n S} { S {is {n X} mode leaf} X {is {n Z} mode value} Z {is {t z} mode value} } # value leaf | yes | value is passed {n S} { S {is {n X} mode value} X {is {n Z} mode leaf} Z {is {t z} mode value} } {n S} { S {is {n Z} mode value} X {is {n Z} mode leaf} Z {is {t z} mode value} } # value void | yes | X is implied void {n S} { S {is {n X} mode value} X {is {n Z} mode void} Z {is {t z} mode value} } {n S} { S {is {n Z} mode value} X {is {n Z} mode void} Z {is {t z} mode value} } # leaf leaf | no | s.a. {n S} { S {is {n X} mode leaf} X {is {n Z} mode leaf} Z {is {t z} mode value} } {n S} { S {is {n X} mode leaf} X {is {n Z} mode leaf} Z {is {t z} mode value} } # leaf void | no | s.a. {n S} { S {is {n X} mode leaf} X {is {n Z} mode void} Z {is {t z} mode value} } {n S} { S {is {n X} mode leaf} X {is {n Z} mode void} Z {is {t z} mode value} } # void value| no | X drops value, inline doesn't {n S} { S {is {n X} mode void} X {is {n Z} mode value} Z {is {t z} mode value} } {n S} { S {is {n X} mode void} X {is {n Z} mode value} Z {is {t z} mode value} } # void leaf | no | s.a. {n S} { S {is {n X} mode void} X {is {n Z} mode leaf} Z {is {t z} mode value} } {n S} { S {is {n X} mode void} X {is {n Z} mode leaf} Z {is {t z} mode value} } # void void | yes | {n S} { S {is {n X} mode void} X {is {n Z} mode void} Z {is {t z} mode value} } {n S} { S {is {n Z} mode void} X {is {n Z} mode void} Z {is {t z} mode value} } {n S} { S {is {n S} mode value} } {n S} { S {is {n S} mode value} } } $setimpl # ------------------------------------------------------------------------- # op: modeopt TestTransformation modeopt { # --- stays as-is epsilon {} epsilon {} # --- cycle # S <-- A; A <-- A {n S} { S {is {n A} mode value} A {is {n A} mode value} } {n S} { S {is {n A} mode value} A {is {n A} mode value} } # -- undefined (deferred) symbol: B {n S} { S {is {n A} mode value} A {is {n B} mode value} } {n S} { S {is {n A} mode value} A {is {n B} mode value} } # --- rule 1 {n S} { S {is {n A} mode value} A {is {t A} mode value} } {n S} { S {is {n A} mode value} A {is {t A} mode leaf} } # --- rule 1 {n S} { S {is {n A} mode value} A {is {x {t A} {n B}} mode value} B {is {t b} mode value} } {n S} { S {is {n A} mode value} A {is {x {t A} {n B}} mode value} B {is {t b} mode leaf} } # --- rule 2 (no opt) {n S} { S {is {x {n A} {n B}} mode value} A {is {n C} mode value} B {is {n C} mode value} C {is {t c} mode leaf} } {n S} { S {is {x {n A} {n B}} mode value} A {is {n C} mode value} B {is {n C} mode value} C {is {t c} mode leaf} } # --- rule 2 (void) {n S} { S {is {x {n A} {n B}} mode value} A {is {n C} mode void} B {is {n C} mode void} C {is {t c} mode leaf} } {n S} { S {is {x {n A} {n B}} mode value} A {is {n C} mode void} B {is {n C} mode void} C {is {t c} mode void} } # --- rule 2 (leaf) {n S} { S {is {x {n A} {n B}} mode value} A {is {n C} mode leaf} B {is {n C} mode leaf} C {is {t c} mode leaf} } {n S} { S {is {x {n A} {n B}} mode value} A {is {n C} mode leaf} B {is {n C} mode leaf} C {is {t c} mode void} } # --- rule 2 (mixed) {n S} { S {is {x {n A} {n B}} mode value} A {is {n C} mode leaf} B {is {n C} mode void} C {is {t c} mode leaf} } {n S} { S {is {x {n A} {n B}} mode value} A {is {n C} mode leaf} B {is {n C} mode void} C {is {t c} mode void} } # --- rule 2 (mixed, no opt) {n S} { S {is {x {n A} {n B}} mode value} A {is {n C} mode leaf} B {is {n C} mode value} C {is {t c} mode leaf} } {n S} { S {is {x {n A} {n B}} mode value} A {is {n C} mode leaf} B {is {n C} mode value} C {is {t c} mode leaf} } # --- rule 1: applies, rule 2: n/a {n S} { S {is {x {n A} {n B}} mode value} A {is {n C} mode leaf} B {is {n C} mode value} C {is {t c} mode value} } {n S} { S {is {x {n A} {n B}} mode value} A {is {n C} mode leaf} B {is {n C} mode value} C {is {t c} mode leaf} } # --- rule 1: applies, rule 2: applies {n S} { S {is {x {n A} {n B}} mode value} A {is {n C} mode leaf} B {is {n C} mode leaf} C {is {t c} mode value} } {n S} { S {is {x {n A} {n B}} mode value} A {is {n C} mode leaf} B {is {n C} mode leaf} C {is {t c} mode void} } } $setimpl # ------------------------------------------------------------------------- # op: minimize TestTransformation minimize { # --- stays as-is epsilon {} epsilon {} # --- minimize away (unrealizable) # S <-- A; A <-- A {n S} { S {is {n A} mode value} A {is {n A} mode value} } epsilon {} # --- already minimal {n S} { S {is {n A} mode leaf} A {is {t a} mode void} } {n S} { S {is {n A} mode leaf} A {is {t a} mode void} } # --- drop unrealizable *before* unreachable # S <-- AB / a; A <-- aA; B <-- a {n S} { S {is {/ {x {n A} {n B}} {t a}} mode value} A {is {x {t a} {n A}} mode value} B {is {t a} mode leaf} } {n S} { S {is {t a} mode leaf} } # --- direct cycle {n A} { A {is {n A} mode value} } epsilon {} # --- indirect cycle {n A} { A {is {n B} mode value} B {is {n C} mode value} C {is {n A} mode value} } epsilon {} # --- dechaining creates unreachable and unrealisable rules; here: B, Y {n S} { S {is {x {n A} {t s}} mode value} A {is {n B} mode value} B {is {n C} mode value} C {is {x {n X} {t c}} mode value} X {is {n Y} mode value} Y {is {n Z} mode value} Z {is {x {t z}} mode leaf} } {n S} { S {is {x {n A} {t s}} mode value} A {is {n C} mode value} C {is {x {n X} {t c}} mode value} X {is {n Z} mode value} Z {is {t z} mode leaf} } # {n S} { # S {is {x {n A} {t s}} mode value} # A {is {x {n X} {t c}} mode value} # X {is {t z} mode leaf} # } } $setimpl # ------------------------------------------------------------------------- rename sl {} rename g {} rename TestTransformation {}