# -*- tcl -*- # aycock.test -- # # Tests for the Aycock-Earley-Horspool parser generator # # Tests for the Aycock-Earley-Horspool parser generator are quite rudimentary # at this point; they walk through only basic functionality and surely do not # explore corner cases. # ------------------------------------------------------------------------- source [file join \ [file dirname [file dirname [file join [pwd] [info script]]]] \ devtools testutilities.tcl] testsNeedTcl 8.5 testsNeedTcltest 2.0 support { useLocal aycock-runtime.tcl grammar::aycock::runtime grammar::aycock useLocalKeep aycock-debug.tcl grammar::aycock::debug grammar::aycock } testing { useLocalKeep aycock-build.tcl grammar::aycock grammar::aycock } # ------------------------------------------------------------------------- proc parser1 {} { grammar::aycock::parser { S ::= if E then S else S { set _ } S ::= if E then S { set _ } S ::= X {} } } test aycock-1.1 {basic parser for an ambiguous grammar} { -body { set parser [parser1] set result [$parser parse \ {if E then if E then X else X } \ {if E1 then if E2 then S1 else S2}] $parser destroy unset parser set result } -cleanup {unset result} -result {if E1 then {if E2 then S1 else S2}} } test aycock-1.2 {basic parser, another case} { -setup { set parser [parser1] } -body { $parser parse \ {if E then if E then X else X else if E then X else X } \ {if E1 then if E2 then S1 else S2 else if E3 then S3 else S4} } -cleanup {$parser destroy; unset parser} -result {if E1 then {if E2 then S1 else S2} else {if E3 then S3 else S4}} } test aycock-2.1 {save and restore a parser} { -body { set parser1 [parser1] set saved [$parser1 save] $parser1 destroy set parser2 [eval $saved] $parser2 parse \ {if E then if E then X else X } \ {if E1 then if E2 then S1 else S2} } -cleanup { catch {$parser2 destroy} catch {unset parser2} catch {unset saved} catch {$parser1 destroy} catch {unset parser1} } -result {if E1 then {if E2 then S1 else S2}} } rename parser1 {} test aycock-3.1 {dangling else grammar, another form} { -body { set parser [grammar::aycock::parser { S ::= if E then S elsepart { set _ } elsepart ::= else S { set _ } elsepart ::= { list (empty) } S ::= X {} }] list [$parser parse \ {if E then if E then X else X } \ {if E1 then if E2 then S1 else S2}] \ [$parser parse \ {if E then if E then X else X else if E then X else X } \ {if E1 then if E2 then S1 else S2 else if E3 then S3 else S4}] } -cleanup { catch {$parser destroy} catch {unset parser} } -result {{if E1 then {if E2 then S1 (empty)} {else S2}} {if E1 then {if E2 then S1 {else S2}} {else {if E3 then S3 {else S4}}}}} } test aycock-3.2 {unary and binary operations, wrong precedence} { -body { set parser [grammar::aycock::parser { E ::= E - E {set _} E ::= E + E {set _} E ::= UMINUS E {set _} E ::= X {set _} UMINUS ::= - {list UMINUS} }] list \ [$parser parse \ {- X - X} \ {- a - b}] \ [$parser parse \ {X - X - X} \ {a - b - c}] \ [$parser parse \ {X + X - X} \ {a + b - c}] } -cleanup { catch {$parser destroy} catch {unset parser} } -result {{UMINUS {a - b}} {{a - b} - c} {{a + b} - c}} } test aycock-4.1 {parses with lots of ambiguity} { -body { set parser [grammar::aycock::parser { A ::= b B {set _} B ::= P P Q {linsert $_ 0 rule1} B ::= P Q Q {linsert $_ 0 rule2} P ::= p {} P ::= {list empty P} Q ::= q {} Q ::= {list empty Q} }] list \ [$parser parse {b} {b}] \ [$parser parse {b p q} {b p q}] \ [$parser parse {b q q} {b q q}] } -cleanup { catch {$parser destroy} catch {unset parser} } -result {{b {rule1 {empty P} {empty P} {empty Q}}} {b {rule1 {empty P} p q}} {b {rule2 {empty P} q q}}} } test aycock-5.1 {desk calculator skeleton} { -body { set p [grammar::aycock::parser { start ::= E {} E ::= E + T {expr {[lindex $_ 0] + [lindex $_ 2]}} E ::= T {} T ::= T * F {expr {[lindex $_ 0] * [lindex $_ 2]}} T ::= F {} F ::= NUMBER {} F ::= ( E ) {lindex $_ 1} }] list \ [$p parse \ {NUMBER * NUMBER + NUMBER} \ {2 * 3 + 4 }] \ [$p parse \ {NUMBER * ( NUMBER + NUMBER )} \ {2 * ( 3 + 4 )}] } -cleanup { catch {$p destroy} catch {unset p} } -result {10 14} } # ------------------------------------------------------------------------- tcltest::cleanupTests return