# -*- tcl -*- # Testsuite for pt::pgen. # Called by the ../pt_pgen.test driver file. #---------------------------------------------------------------------- ## I. Testing the generator operation itself # TODO testing of the pt::pgen command API (#args, options, outputs) ... #---------------------------------------------------------------------- ## II. Using generated parsers to test behaviour on good and bad ## input, i.e. the error handling implemented in our PEG parsers. ## See data/gr/README.txt for the documentation of the directory ## structure used to organize the test-cases used here. foreach {format notes} { container {grammar interpreter - reference} snit {snit::type Tcl parser} oo {TclOO class Tcl parser} critcl {PARAM based C class parser} } { # Choose test constraint based on the current format. switch -exact -- $format { critcl { set cons critcl } oo { set cons tcloo } default { set cons {} } } TestFilesProcessIn $mytestdir gr def -> n glabel grfile grdata { # Make parser instance. Shared across tests. Amortize the time # spent on dynamically making it. if {!(($format eq "critcl" && ![tcltest::testConstraint critcl]) || ($format eq "oo" && ![tcltest::testConstraint tcloo]))} { set p [make-parser $format $glabel $grdata] } else { set p {} } # Test parser on good inputs for the grammar. TestFilesProcess $mytestdir gr ok-${glabel} ok-${glabel}-res -> k label infile text expected { test pt-pgen-parse:${parseimpl}-rde:${rdeimpl}-stack:${stackimpl}-f:${format}-g:${glabel}-t:${label}-1.$n.$k \ "$format parser $glabel, good input - $label" -constraints $cons -setup { } -body { $p parset $text } -result $expected } # Test parser on bad inputs for the grammar. ## # Note how the expected output depends not only on grammar, # but the parser format as well. Different optimizations and # such leading to different instructions implementing matches. # Example: "next_str" vs. "sequence of next_char". TestFilesProcess $mytestdir gr fail-${glabel} fail-${glabel}-${format}-res -> k label infile text expected { test pt-pgen-parse:${parseimpl}-rde:${rdeimpl}-stack:${stackimpl}-f:${format}-g:${glabel}-t:${label}-2.$n.$k \ "$format parser $glabel, bad input - $label" -constraints $cons -setup { } -body { set code [catch { $p parset $text } msg] # msg = list ("pt::rde" location list(msg)) # Sort the messages for a canonical result. # NOTE: The data out of the RDE/critcl is sorted # by msg id, that is not necessarily # lexicographical, nor matching the Tcl results. lassign $msg tag loc mlist set msg [list $tag $loc [lsort -dict $mlist]] # TODO: Convert message to readable. list $code $msg } -result $expected } yes ;# Allow missing testsets, for two reasons: # # (a) Easier during testsuite development, allowing incremental buildup # # (b) Some grammar construction *cannot* fail (Ex: x*), thus we cannot provide # # failure cases either. # Kill shared parser instance. if {$p eq {}} continue $p destroy } # Testing the handling of generated parsers for single # characters, for characters special to Tcl, C, and # PEGs. I.e. ensure that the various forms of quoting are done # correctly. foreach {n peg input message hmsg} $chars { set glabel "T_$hmsg" set grdata [string map [list @ $peg] $gtemplate] set edata [string map [list @ $hmsg] $etemplate] # Make parser instance. Shared across tests. # Amortize the time spent on dynamically making it. if {!(($format eq "critcl" && ![tcltest::testConstraint critcl]) || ($format eq "oo" && ![tcltest::testConstraint tcloo]))} { set p [make-parser $format $glabel $grdata] } else { set p {} } test pt-pgen-parse:${parseimpl}-rde:${rdeimpl}-stack:${stackimpl}-f:${format}-g:${glabel}-3.$n \ "$format parser $glabel, good input" -constraints $cons -setup { } -body { $p parset $input } -result {} test pt-pgen-parse:${parseimpl}-rde:${rdeimpl}-stack:${stackimpl}-f:${format}-g:${glabel}-4.$n \ "$format parser $glabel, bad input, tcl error" -constraints $cons -setup { } -body { set code [catch { $p parset X } msg] lassign $msg tag loc mlist list $tag $loc [lsort -dict $mlist] } -result [list pt::rde 0 [list $message]] test pt-pgen-parse:${parseimpl}-rde:${rdeimpl}-stack:${stackimpl}-f:${format}-g:${glabel}-5.$n \ "$format parser $glabel, bad input, readable error" -constraints $cons -setup { } -body { set code [catch { $p parset X } msg] lassign $msg tag loc mlist pt::util::error2readable [list $tag $loc [lsort -dict $mlist]] X } -result $edata # Kill shared parser instance. if {$p eq {}} continue $p destroy } } #----------------------------------------------------------------------