Index: modules/pt/pkgIndex.tcl ================================================================== --- modules/pt/pkgIndex.tcl +++ modules/pt/pkgIndex.tcl @@ -54,11 +54,11 @@ package ifneeded pt::rde 1.1 [list source [file join $dir pt_rdengine.tcl]] package ifneeded pt::rde::oo 1.1 [list source [file join $dir pt_rdengine_oo.tcl]] # Note: The last two numbers are the rde::nx version itself. The # preceding version information is the rde::oo version it is based on. -package ifneeded pt::rde::nx 1.1.1.0 [list source [file join $dir pt_rdengine_nx.tcl]] +package ifneeded pt::rde::nx 1.1.1.1 [list source [file join $dir pt_rdengine_nx.tcl]] # PEG grammar specification, as CONTAINER package ifneeded pt::peg::container::peg 1 [list source [file join $dir pt_peg_container_peg.tcl]] Index: modules/pt/pt_rdengine_nx.tcl ================================================================== --- modules/pt/pt_rdengine_nx.tcl +++ modules/pt/pt_rdengine_nx.tcl @@ -1,72 +1,148 @@ # -*- tcl -*- # -# Copyright (c) 2016-2017 by Stefan Sobernig +# Copyright (c) 2016-2018 by Stefan Sobernig # # ## ### ##### ######## ############# ##################### ## Package description -## ... - +## An NX implementation of the PackRat Machine (PARAM), a virtual +## machine on top of which parsers for Parsing Expression Grammars +## (PEGs) can be realized. This implementation is tied to the PARAM's +## TclOO implementation and it is automatically derived from the +## corresponding TclOO class (pt::rde::oo) upon loading the package. # # ## ### ##### ######## ############# ##################### ## Requisites package require pt::rde::oo package req nx namespace eval ::pt::rde { - ## - ## Helper: An NX metaclass, which allows for deriving an NX class from - ## a given TclOO class. - ## - - nx::Class create ClassFactory -superclass nx::Class { - :property prototype:required - :method init {args} { - :alias instvar ::nsf::methods::object::instvar - namespace eval [namespace qualifier [self]] { - namespace import ::nsf::my - } - - set vars [info class variables ${:prototype}] - if {[llength $vars]} { - set vars [concat :instvar $vars] - } - - ## clone constructor - lassign [info class constructor ${:prototype}] ctorParams ctorBody - - set ctorBody [string map [list @body@ $ctorBody @vars@ $vars] { - :require namespace; apply [list {} { - namespace import ::nsf::my - @vars@ - @body@ - } [self]] - }] - - :method init $ctorParams $ctorBody - - ## clone all methods - foreach m [info class methods ${:prototype} -private] { - lassign [info class definition ${:prototype} $m] params body - :method $m $params [string map [list @body@ $body @vars@ $vars] { - @vars@ - @body@ - }] - } - } - } - - ## - ## ::pt::rde::nx: - ## - ## The NX derivative of ::pt::rde::oo, to be inherited - ## by the generated grammar class. - ## - - ClassFactory create nx -prototype ::pt::rde::oo - -} - -package provide pt::rde::nx [package req pt::rde::oo].1.0 + ## + ## Helper: An NX metaclass and class generator, which allows for + ## deriving an NX class from the ::pt::rde::oo class. + ## + + nx::Class create ClassFactory -superclass nx::Class { + :property prototype:required + + :method mkMethod {name vars params body tmpl} { + set objVars [list] + set debugObjVars [list] + foreach v $vars { + if {[string first $v $body] > -1} { + lappend objVars :$v $v + } else { + lappend debugObjVars :$v $v + } + } + + if {[llength $objVars]} { + set objVars [list upvar 0 {*}$objVars] + } + + if {[llength $debugObjVars]} { + set debugObjVars [list debug.pt/rdengine \ + "\[[list upvar 0 {*}$debugObjVars]\]"] + } + + set mappings [list @body@ $body @objVars@ $objVars \ + @debugObjVars@ $debugObjVars @params@ $params] + + set finalBody [string map $mappings $tmpl] + + :method $name $params $finalBody + + }; # mkMethod + + :method init {args} { + + namespace eval [namespace qualifier [self]] { + namespace import ::nsf::my + } + + :method debugPrep {cls} { + :object method TraceInitialization [list [list cls $cls]] { + set mh [$cls info methods -callprotection all TraceInitialization] + if {$mh ne ""} { + set script [$cls info method body $mh] + apply [list {} $script [self]] + } + } + return + } + + :method debugOn {} { + interp alias {} [namespace current]::Instruction {} [self]::Instruction + interp alias {} [namespace current]::InstReturn {} [self]::InstReturn + interp alias {} [namespace current]::State {} [self]::State + interp alias {} [namespace current]::TraceSetupStacks {} [self]::TraceSetupStacks + return + } + + :method debugOff {} { + interp alias {} [namespace current]::Instruction {} + interp alias {} [namespace current]::InstReturn {} + interp alias {} [namespace current]::State {} + interp alias {} [namespace current]::TraceSetupStacks {} + return + } + + set vars [info class variables ${:prototype}] + + ## clone constructor + lassign [info class constructor ${:prototype}] ctorParams ctorBody + + :mkMethod init $vars $ctorParams $ctorBody { + debug.pt/rdengine {[:debugPrep [current class]][self] TraceInitialization indirection} + :require namespace; + apply [list {} { + namespace import ::nsf::my + @objVars@ + @body@ + } [self]] + + debug.pt/rdengine {[:debugOn][self] DebugCmd indirection on} + } + + :public method destroy {args} { + debug.pt/rdengine {[:debugOff][self] DebugCmd indirection off} + next + } + + ## clone all methods + foreach m [info class methods ${:prototype} -private] { + lassign [info class definition ${:prototype} $m] params body + + :mkMethod $m $vars $params $body { + @objVars@ + @debugObjVars@ + @body@ + } + } + + return + }; # init + }; # ClassFactory + + ## + ## ::pt::rde::nx: + ## + ## The NX derivative of ::pt::rde::oo, to be inherited + ## by the generated grammar class. + ## + + ClassFactory create nx -prototype ::pt::rde::oo + + namespace export nx +} + +package provide pt::rde::nx [package req pt::rde::oo].1.1 + +# Local variables: +# mode: tcl +# tcl-indent-level: 2 +# indent-tabs-mode: nil +# End: + Index: modules/pt/pt_rdengine_oo.tcl ================================================================== --- modules/pt/pt_rdengine_oo.tcl +++ modules/pt/pt_rdengine_oo.tcl @@ -783,16 +783,16 @@ # wanted to match, and the message will contain the entire # string token. In the regular sequence we would see the exact # point of the mismatch instead, with the message containing # the expected character. - set myok [expr {$tok eq $lex}] - - if {$myok} { + if {$tok eq $lex} { + set myok 1 set myloc $last set myerror {} } else { + set myok 0 set myerror [list $myloc [list [list str $tok]]] incr myloc -1 } debug.pt/rdengine {[InstReturn]} return @@ -817,15 +817,16 @@ set mycurrent [string index $mytoken $myloc] # Note what is needle versus hay. The token, i.e. the string # of allowed characters is the hay in which the current # character is looked, making it the needle. - set myok [expr {[string first $mycurrent $tok] >= 0}] - if {$myok} { + if {[string first $mycurrent $tok] >= 0} { + set myok 1 set myerror {} } else { + set myok 0 set myerror [list $myloc [list [list cl $tok]]] incr myloc -1 } debug.pt/rdengine {[InstReturn]} return @@ -845,14 +846,15 @@ debug.pt/rdengine {[InstReturn]} return } set mycurrent [string index $mytoken $myloc] - set myok [expr {$tok eq $mycurrent}] - if {$myok} { + if {$tok eq $mycurrent} { + set myok 1 set myerror {} } else { + set myok 0 set myerror [list $myloc [list [list t $tok]]] incr myloc -1 } debug.pt/rdengine {[InstReturn]} return @@ -872,17 +874,16 @@ debug.pt/rdengine {[InstReturn]} return } set mycurrent [string index $mytoken $myloc] - set myok [expr { - ([string compare $toks $mycurrent] <= 0) && - ([string compare $mycurrent $toke] <= 0) - }] ; # {} - if {$myok} { + if {([string compare $toks $mycurrent] <= 0) && + ([string compare $mycurrent $toke] <= 0)} { + set myok 1 set myerror {} } else { + set myok 0 set myerror [list $myloc [list [pt::pe range $toks $toke]]] incr myloc -1 } debug.pt/rdengine {[InstReturn]} return Index: modules/pt/pt_rdengine_tcl.tcl ================================================================== --- modules/pt/pt_rdengine_tcl.tcl +++ modules/pt/pt_rdengine_tcl.tcl @@ -771,16 +771,16 @@ # wanted to match, and the message will contain the entire # string token. In the regular sequence we would see the exact # point of the mismatch instead, with the message containing # the expected character. - set myok [expr {$tok eq $lex}] - - if {$myok} { + if {$tok eq $lex} { + set myok 1 set myloc $last set myerror {} } else { + set myok 0 set myerror [list $myloc [list [pt::pe str $tok]]] incr myloc -1 } debug.pt/rdengine {[InstReturn]} return @@ -805,15 +805,16 @@ set mycurrent [string index $mytoken $myloc] # Note what is needle versus hay. The token, i.e. the string # of allowed characters is the hay in which the current # character is looked, making it the needle. - set myok [expr {[string first $mycurrent $tok] >= 0}] - if {$myok} { + if {[string first $mycurrent $tok] >= 0} { + set myok 1 set myerror {} } else { + set myok 0 set myerror [list $myloc [list [pt::pe class $tok]]] incr myloc -1 } debug.pt/rdengine {[InstReturn]} return @@ -833,14 +834,15 @@ debug.pt/rdengine {[InstReturn]} return } set mycurrent [string index $mytoken $myloc] - set myok [expr {$tok eq $mycurrent}] - if {$myok} { + if {$tok eq $mycurrent} { + set myok 1 set myerror {} } else { + set myok 0 set myerror [list $myloc [list [pt::pe terminal $tok]]] incr myloc -1 } debug.pt/rdengine {[InstReturn]} return @@ -860,17 +862,16 @@ debug.pt/rdengine {[InstReturn]} return } set mycurrent [string index $mytoken $myloc] - set myok [expr { - ([string compare $toks $mycurrent] <= 0) && - ([string compare $mycurrent $toke] <= 0) - }] ; # {} - if {$myok} { + if {([string compare $toks $mycurrent] <= 0) && + ([string compare $mycurrent $toke] <= 0)} { + set myok 1 set myerror {} } else { + set myok 0 set myerror [list $myloc [list [pt::pe range $toks $toke]]] incr myloc -1 } debug.pt/rdengine {[InstReturn]} return