Index: generic/nsf.nxd =================================================================== diff -u -N --- generic/nsf.nxd (revision 26ce746b45449fbff64f88c6d9e9050a63b89449) +++ generic/nsf.nxd (revision 0) @@ -1,309 +0,0 @@ -# -*- Tcl -*- - -# @command assertion -# -# @parameter object:object -# @parameter assertionsubcmd:required -# @parameter arg - -# @command existsvar -# -# @parameter object:object -# @parameter var - -# @command methodproperty -# -# @parameter object:object -# @parameter -per-object:switch -# @parameter methodName -# @parameter methodproperty Accepts one of: '''protected''', -# '''redefine-protected''', '''returns''', '''slotobj''' -# @parameter value - -# @command setter -# -# @parameter object:object -# @parameter -per-object:switch -# @parameter parameter - -# @command createobjectsystem -# -# @parameter rootClass -# @parameter rootMetaClass -# @parameter systemMethods:optional - -# @command dispatch -# -# @parameter object:object -# @parameter -objscope -# @parameter command -# @parameter args - -# @command deprecated -# -# @parameter what -# @parameter oldCmd -# @parameter newCmd:optional - -# @command objectproperty -# -# @parameter object:object -# @parameter objectkind Accepts one of: '''type''', '''object''', -# '''class''', '''baseclass''', '''metaclass''', '''hasmixin''' -# @parameter value:optional - -# @command importvar -# -# @parameter object:object -# @parameter args - -# @command parametercheck -# -# @parameter -nocomplain -# @parameter param -# @parameter value:optional - -# @command forward -# -# @parameter object:object -# @parameter -per-object:switch -# @parameter method -# @parameter -default -# @parameter -earlybinding:switch -# @parameter -methodprefix -# @parameter -objscope:switch -# @parameter -onerror -# @parameter -verbose:switch -# @parameter target -# @parameter args - -# @command setvar -# -# @parameter object:object -# @parameter variable -# @parameter value - -# @command method -# -# @parameter object:object -# @parameter -inner-namespace -# @parameter -per-object -# @parameter -public -# @parameter name -# @parameter args -# @parameter body -# @parameter -percondition -# @parameter -postcondition - -# @command next -# -# Invokes the shadowed (i.e, same-named) method which is next along -# the precedence path and returns the results of this invocation. If -# '''next''' is called without arguments, the arguments of the current -# method (i.e., the arguments as present at the current callframe) are -# passed through to the shadowed method. If next is invoked with the -# flag --noArgs, the shadowed method is called without the active -# callframe arguments. If other arguments are specified for '''next''' -# explicitly, these will be passed instead. -# -# @parameter --noArgs:optional Deactivates the forward-passing of the current callframe's arguments -# @parameter args Explicitly declared arguments to pass to shadowed methods - - -# @command current -# -# An introspective command which allows you to explore the callstack -# from within the scope of a method (or a proc bound to an object via -# '''alias'''). If executed without specifying a subcommand, -# i.e. '''[current]''', it defaults to <<@command.command "current -# object">>. While '''current''' operates on the Tcl callstack, it is -# aware of object-specific callstack and frame information. To some -# extent, this object introspection protocol can be approximated at -# the script level by instrumenting '''[info frame]'''. -# -# If invoked outside of an object's scope (e.g., an ordinary proc, the -# global namespace), it fails and reports '''No current object'''. -# -# It comes with a variety of sub-commands to query the object-specific -# callstack information available. See below. -# -# @sub-command class Returns the name of the class holding the -# currently executing per-class method, if and only if called from -# within a per-class method. Note, that this method-owning class may -# be different to the class of the current object. If called from -# within a per-object method, it returns an empty string. -# -# @sub-command method Returns the name of the currently executing method. -# -# @sub-command callingclass Returns the name of the class which is -# calling into the executing method. -# -# @sub-command callingobject Returns the name of the object which is -# calling into the executing method. -# -# @sub-command calledclass Returns the name of the class that holds -# the originally (and now shadowed) target method (applicable in -# mixin classes and filters). -# -# @sub-command calledmethod Returns the name of the target method -# (applicable in a filter only). -# -# @sub-command isnextcall Returns 1 if the executing method was -# invoked via <<@command next>>, 0 otherwise. -# -# @sub-command next Returns the name of the method next on the -# precedence path as a string. -# -# @sub-command filterreg In a method serving as active filter, -# returns the name of the object (class) on which the method is -# registered as a filter. -# -# @command callinglevel Resolves the callstack level which represents -# the originating invocation into the currently executing method. Levels -# of indirection (e.g., filters) and method combination along the -# class linearisation path ('''next''') are ignored. The callstack is -# returned as an absolute level number (# followed by a digit). The -# level number returned can be directly used as the first argument to -# '''uplevel''' or '''upvar''' calls. See also <<@command.command -# "current activelevel">> -# -# @sub-command activelevel Returns the actual callstack level calling -# into the executing method. The active might correspond the -# '''callinglevel''', but this is not necessarily the case. The -# '''activelevel''' counts <<@command next>> call. The level -# is returned in a form so that it can be used as first argument in -# '''uplevel''' or '''upvar'''. - -# @command.command {current object} -# -# The default sub-command returns the name of the object currently -# active on the callstack. - - -# @command configure -# -# A top-level configuration facility which allows you modify -# properties of the "Next" object system for the scope of an entire -# '''interp'''. - -# @command.sub-command {configure filter} -# -# Allows turning on or off filters globally for the current -# interpreter. By default, the filter state is turned off. This -# function returns the old filter state. This filterless '''interp''' -# state is needed for the serializer which should introspect and stream the -# objects and classes without being affected by active filter. -# -# @parameter toggle Accepts either "on" or "off" -# @return The current filter activation state - -# @command.sub-command {configure softrecreate} -# -# Allows controlling the scheme applied when recreating an object or a -# class. By default, it is set to '''off'''. This means that the -# object/class is destroyed and all relations -# (e.g. subclass/superclass) to other objects/classes are revoked as -# well. If softrecreate is set to '''on''', the object is re-set, but not -# destroyed, the relations are -# kept. -# -# A "soft" recreation is important for e.g. reloading a file with -# class definitions (e.g. when used in OpenACS with file watching and -# reloading). With softrecreate set, it is not necessary to recreate -# dependent subclasses etc. Consider the example of a class hierarchy -# '''A <- B <- C'''. Without '''softrecreate''' set, a reload of -# '''B''' means first a destroy of B, leading to '''A <- C''', and -# instances of '''B''' are re-classed to <<@class -# ::nx::Object>>. When softrecreate is set, the class hierarchy -# remains untouched. -# -# @parameter toggle Accepts either "on" or "off" -# @return The current toggle value - - -# @command.sub-command {configure objectsystems} -# -# A mere introspection subcommand. It gives you the top level of the -# current object system, i.e., the ruling root class and root -# meta-class. For "Next": -# -# ''' -# configure objectsystems; # returns "::nx::Object ::nx::Class" -# ''' -# -# @return The active pair of root class and root meta-class - -# @command.sub-command {configure keepinitcmd} -# -# Usually, initcmd scripts are discarded by the '''interp''' once -# having been evaluated (in contrast to '''proc''' and '''method''' -# bodies). If you need them preserved for later introspection and -# processing (as in the "Next" documentation system), set this option -# to '''true'''. Then, the initcmd scripts are retained as a -# particular object variable ('''__initcmd''') of classes and -# objects. It defaults to '''false'''. -# -# @parameter value:boolean Either '''true''' or '''false''' -# @return The current setting - -# @command alias -# -# @parameter object:object The target object which becomes the owner of -# the aliased command (method, object or command). -# -# @parameter -per-object:switch If the target object is a class, one can -# specify the binding scope (i.e., per-object or per-class) of the -# aliased command -# -# @parameter methodName The name of the alias. -# @parameter -nonleaf:switch ... -# @parameter -objscope:switch ... -# @parameter cmdName The alias source as a command handle (as returned by ...) - -# @command finalize - -# @command interp -# -# @parameter name -# @parameter args - -# @command is -# -# @parameter value -# @parameter constraint -# @parameter -hasmixin -# @parameter -type -# @parameter arg - -# @command my -# -# @parameter -local -# @parameter method -# @parameter args - -# @command relation -# -# @parameter object -# @parameter relationtype -# @parameter value - -# @command provide_method -# -# @parameter require_name -# @parameter definition -# @parameter script:optional - -# @command require_method -# -# @parameter object -# @parameter name -# @parameter per_object - -# @command mixin -# -# @parameter object -# @parameter args - -# @command tmpdir -# -# @return The platform-specific path name to the system-wide temporary directory \ No newline at end of file Index: library/lib/doc-assets/api.css =================================================================== diff -u -N -r18ff1444fef5c209dfb40cf2ae694206c0d10309 -r170cefa7618f2b44f91102711607fc6fa7d12c4f --- library/lib/doc-assets/api.css (.../api.css) (revision 18ff1444fef5c209dfb40cf2ae694206c0d10309) +++ library/lib/doc-assets/api.css (.../api.css) (revision 170cefa7618f2b44f91102711607fc6fa7d12c4f) @@ -265,3 +265,23 @@ font-style: normal; /* for use with dfn */ } +span.status { + display:none; + padding: 0 5px 0 5px; + background:url(status.png) no-repeat scroll 0 0; +} + +span.missing { + display:inline; + background-position: -12px 0; +} + +span.extra { + display:inline; + background-position: 2px 0; +} + +span.mismatch { + display:inline; + background-position: -24px 0; +} \ No newline at end of file Index: library/lib/doc-assets/class.html.tmpl =================================================================== diff -u -N -r5d5f67b7b4a9806e10419e44efdcfe724bfcff9b -r170cefa7618f2b44f91102711607fc6fa7d12c4f --- library/lib/doc-assets/class.html.tmpl (.../class.html.tmpl) (revision 5d5f67b7b4a9806e10419e44efdcfe724bfcff9b) +++ library/lib/doc-assets/class.html.tmpl (.../class.html.tmpl) (revision 170cefa7618f2b44f91102711607fc6fa7d12c4f) @@ -6,7 +6,7 @@

Class - ${:name} + [:print_name -status] [:?var :@superclass { - subclass of @@ -71,12 +71,10 @@ }]
- - - }] -}] + - + }] +}] [:!let iattrs [:inherited @class-attribute]] [:? {$iattrs ne ""} { @@ -170,6 +168,7 @@ }] + }] [:!let imethods [:inherited @class-method]] @@ -202,7 +201,6 @@ [:?var :@method { Undocumented Methods: [:undocumented] }] - [:?var :@object-method { Index: library/lib/doc-assets/entity.html.tmpl =================================================================== diff -u -N -r5d5f67b7b4a9806e10419e44efdcfe724bfcff9b -r170cefa7618f2b44f91102711607fc6fa7d12c4f --- library/lib/doc-assets/entity.html.tmpl (.../entity.html.tmpl) (revision 5d5f67b7b4a9806e10419e44efdcfe724bfcff9b) +++ library/lib/doc-assets/entity.html.tmpl (.../entity.html.tmpl) (revision 170cefa7618f2b44f91102711607fc6fa7d12c4f) @@ -57,8 +57,8 @@ [:include glossary.html.tmpl] }] - +
[:include leftbar.html.tmpl]
Index: library/lib/doc-assets/method.html.tmpl =================================================================== diff -u -N -r26ce746b45449fbff64f88c6d9e9050a63b89449 -r170cefa7618f2b44f91102711607fc6fa7d12c4f --- library/lib/doc-assets/method.html.tmpl (.../method.html.tmpl) (revision 26ce746b45449fbff64f88c6d9e9050a63b89449) +++ library/lib/doc-assets/method.html.tmpl (.../method.html.tmpl) (revision 170cefa7618f2b44f91102711607fc6fa7d12c4f) @@ -1,12 +1,13 @@ +[:!let paramblock [:parameters]]

[:? {[info exists :@return] && [${:@return} spec] ne ""} {<[[${:@return} spec] spec]>} ] ${:name} - [:parameters] + $paramblock - [:? {[:has_property interally-called]} { + [:? {[:@syshook]} {
Internally called method, can be redefined. }] [:? {[[[:partof] name] info methods ${:name}] ne "" && Index: library/lib/doc-assets/package.html.tmpl =================================================================== diff -u -N -r26ce746b45449fbff64f88c6d9e9050a63b89449 -r170cefa7618f2b44f91102711607fc6fa7d12c4f --- library/lib/doc-assets/package.html.tmpl (.../package.html.tmpl) (revision 26ce746b45449fbff64f88c6d9e9050a63b89449) +++ library/lib/doc-assets/package.html.tmpl (.../package.html.tmpl) (revision 170cefa7618f2b44f91102711607fc6fa7d12c4f) @@ -26,7 +26,7 @@ @@ -42,7 +42,8 @@ @@ -59,7 +60,8 @@ Index: library/lib/doc-assets/status.png =================================================================== diff -u -N Binary files differ Index: library/lib/doc-assets/status.svg =================================================================== diff -u -N --- library/lib/doc-assets/status.svg (revision 0) +++ library/lib/doc-assets/status.svg (revision 170cefa7618f2b44f91102711607fc6fa7d12c4f) @@ -0,0 +1,405 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + 2005-11-01 + + + Jean-Victor Balin + + + jean.victor.balin@gmail.com + + + + icon + arrow + + + fr-FR + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Index: library/lib/doc-tools.tcl =================================================================== diff -u -N -r5d5f67b7b4a9806e10419e44efdcfe724bfcff9b -r170cefa7618f2b44f91102711607fc6fa7d12c4f --- library/lib/doc-tools.tcl (.../doc-tools.tcl) (revision 5d5f67b7b4a9806e10419e44efdcfe724bfcff9b) +++ library/lib/doc-tools.tcl (.../doc-tools.tcl) (revision 170cefa7618f2b44f91102711607fc6fa7d12c4f) @@ -95,6 +95,17 @@ return $result } + proc filtered {instances filteredBy} { + set filtered [list] + foreach v $instances { + if {[$v eval [list expr $filteredBy]]} { + lappend filtered $v + } + } + return $filtered + } + + proc sort_by_value {d} { set haystack [list] dict for {key value} $d { @@ -120,14 +131,35 @@ Class create MixinLayer -superclass Class { :attribute {prefix ""} + :public method init {} { + set :active_mixins [dict create] + next + } :public method apply {} { + if {${:active_mixins} ne ""} { + puts stderr "Warning: mixin layer has not been revoked!" + set :active_mixins [dict create] + } foreach mixin [:info children -type [current class]::Mixin] { set base "${:prefix}::[namespace tail $mixin]" if {[::nsf::isobject $base]} { - set scope [expr {[$mixin scope] eq "object" && [$base info is class]?"class-object":""}] + set scope [expr {[$mixin scope] eq "object" && \ + [$base info is class]?"class-object":""}] + dict lappend :active_mixins $base $mixin $base {*}$scope mixin add $mixin } + } } + + :public method revoke {} { + dict for {base mixins} ${:active_mixins} { + foreach m $mixins { + set scope [expr {[$m scope] eq "object" && \ + [$base info is class]?"class-object":""}] + $base {*}$scope mixin delete $m + } + } + set :active_mixins [dict create] } Class create [current]::Mixin -superclass Class { @@ -285,19 +317,9 @@ } :method createOrConfigure {id args} { - # puts stderr "createOrConfigure id $id" - # This method handles verifies whether an entity object based on - # the given id exists. If so, it returns the resolved name. If - # not, it provides for generating an object with the precomputed - # id for the first time! - # - # @param id The identifier string generated beforehand - # @return The identifier of the newly generated or resolved entity object - # @see {{@method id}} namespace eval $id {} if {[::nsf::isobject $id]} { $id configure {*}$args - # return $id } else { :create $id {*}$args } @@ -432,11 +454,11 @@ [$value info has type ${:part_class}]} { return $value } - # puts stderr "NEWWWWWW ${:part_class} new \ - # -name [lindex $value 0] \ - # -partof $domain \ - # -part_attribute [current] \ - # -@doc [lrange $value 1 end]" + # puts stderr "NEWWWWWW ${:part_class} new \ + # -name [lindex $value 0] \ + # -partof $domain \ + # -part_attribute [current] \ + # -@doc [lrange $value 1 end]" return [${:part_class} new \ -name [lindex $value 0] \ -partof $domain \ @@ -467,6 +489,20 @@ } } + ::nx::MetaSlot create SwitchAttribute -superclass ::nx::Attribute { + :public method init args { + set :defaultmethods [list get get] + next + } + :public method get {obj prop} { + set def [expr {[info exists :default]?${:default}:0}] + if {[$obj eval [list set :$prop]] == $def} { + return [::nsf::setvar $obj $prop [expr {!$def}]] + } + return [next] + } + } + Class create Entity { # # Entity is the base class for the documentation classes @@ -482,9 +518,14 @@ next [list [list @doc:optional __initcmd:initcmd,optional]] } + :class-object attribute current_project:object,type=::nx::doc::@project,allowempty + :public forward current_project [current] %method + :attribute partof:object,type=::nx::doc::StructuredEntity :attribute part_attribute:object,type=::nx::doc::PartAttribute + :attribute pdata + :public method get_upward_path { -relative:switch {-attribute {set :name}} @@ -494,22 +535,33 @@ if {!$relative} { lappend path [list [current] [:eval $attribute]] } - #puts stderr ARGS=[current args]-[info exists :partof] - #puts stderr HELP=$path - if {[info exists :partof] && [${:partof} info has type $type]} { - #puts stderr "CHECK ${:partof} info has type $type -> [${:partof} info has type $type]" - + if {[info exists :partof] && [${:partof} info has type $type]} { set path [concat [${:partof} [current method] -attribute $attribute -type $type] $path] } - #puts stderr PATHRETURN=$path return [concat {*}$path] } :attribute @doc:multivalued {set :incremental 1} :attribute @see -slotclass ::nx::doc::PartAttribute - :attribute @properties -slotclass ::nx::doc::PartAttribute + :attribute @deprecated:boolean -slotclass ::nx::doc::SwitchAttribute { + set :default 0 + } + :attribute @stashed:boolean -slotclass ::nx::doc::SwitchAttribute { + set :default 0 + } + :attribute @c-implemented:boolean -slotclass ::nx::doc::SwitchAttribute { + set :default 0 + } + + # :attribute @properties -slotclass ::nx::doc::PartAttribute + :public method @property {props} { + foreach prop $props { + :@$prop + } + } + :attribute @use { :public method assign {domain prop value} { # @command nx @@ -565,51 +617,19 @@ return [current] } - :method has_property {prop} { - if {![info exists :@properties]} {return 0} - expr {$prop in ${:@properties}} - } - - # @method _doc - # - # The method _doc can be use to obtain the value of the documentation - # from another doc entity. This should avoid redundant documentation pieces. - :method _doc {doc use what value} { - if {$@doc ne ""} {return $doc} - if {$use ne ""} { - foreach thing {@command @object} { - set docobj [$thing id $use] - if {[::nsf::isobject $docobj]} break - } - if {[::nsf::isobject $docobj]} { - if {![$docobj eval [list info exists :$what]]} {error "no attribute $what in $docobj"} - set names [list] - foreach v [$docobj $what] { - if {[$v name] eq $value} {return [$v @doc]} - lappend names [$v name] - } - error "can't use $use, no $what with name $value in $docobj (available: $names)" - } else { - error "can't use $use, no documentation object $docobj" - } + :public method as_list {} { + if {[info exists :@doc] && ${:@doc} ne ""} { + set non_empty_elements [lsearch -all -not -exact ${:@doc} ""] + return [lrange ${:@doc} [lindex $non_empty_elements 0] [lindex $non_empty_elements end]] } } - # @method text + # @method as_text # # text is used to access the content of doc of an Entity, and # performs substitution on it. The substitution is not essential, # but looks for now convenient. - # - :public method as_list {} { - if {[info exists :@doc] && ${:@doc} ne ""} { - #puts stderr DOC=${:@doc} - set non_empty_elements [lsearch -all -not -exact ${:@doc} ""] - return [lrange ${:@doc} [lindex $non_empty_elements 0] [lindex $non_empty_elements end]] - } - } - :public method as_text {} { set doc [list] set lines [:as_list] @@ -628,6 +648,7 @@ Class create StructuredEntity -superclass Entity { + :public method part_attributes {} { set slots [:info lookup slots] set attrs [list] @@ -637,18 +658,11 @@ } return $attrs } + :public method owned_parts {} { set r [dict create] foreach {s cls} [:part_attributes] { - # - # TODO: there is no equivalent to mixinof/has mixin for the - # superclass-subclass axis: info superclassof | /cls/ has - # superclass | info subclassof | /cls/ has subclass; are info - # subclass and superclass sufficient? - # - # if {![$s info has type ::nx::doc::PartAttribute] || ![$s eval {info exists :part_class}] || [current class] ni [[$s eval {set :part_class}] info superclass -closure]} continue; set accessor [$s name] -# puts stderr "PROCESSING ACCESSOR $accessor, [info exists :$accessor]" if {[info exists :$accessor]} { dict set r $s [sorted [:$accessor] name] } @@ -757,6 +771,17 @@ } } + :method destroy {} { + foreach {attr part_class} [:part_attributes] { + #$part_class class-object mixin add [current class]::Containable + if {[$part_class eval {info exists :container}] && \ + [$part_class container] eq [current]} { + $part_class eval {unset :container} + } + } + next + } + :public method register {containable:object,type=::nx::doc::Entity} { set tag [[$containable info class] tag] if {[:info lookup methods -source application "@$tag"] ne ""} { @@ -766,6 +791,10 @@ } Tag create @project -superclass ContainerEntity { + + :attribute sandbox:object,type=::nx::doc::Sandbox + :attribute sources + :attribute url :attribute license :attribute creationdate @@ -778,6 +807,29 @@ :attribute @package -slotclass ::nx::doc::PartAttribute { set :part_class ::nx::doc::@package } + + :public method destroy {} { + # + # TODO: Using the auto-cleanup feature in [Test case ...] does + # not respect explicit destroy along object relations. Turn the + # test environment more passive by checking for the existance + # before calling destroy! + # + if {[::nsf::isobject ${:sandbox}]} { + ${:sandbox} destroy + } + :current_project "" + next + } + + :method init {} { + # + # TODO: the way we provide the project as a context object to + # all entities is not easily restricted. Review later ... + # + :current_project [current]; # sets a per-class-object variable on Entity! + next + } } # @@ -920,16 +972,21 @@ # and/or generalisable: For instance, is the scope # requested (from the part_attribute) applicable to the # partof object, which is the object behind [$domain name]? - if {[info exists :scope] && - ![::nsf::is ${:scope} [$domain name]]} { - error "The entity '[$domain name]' does not qualify as '${:scope}'" - } + + # TODO: disable for the moment ... how to rewrite to fit + # the sandboxed environment? + # if {[info exists :scope] && + # ![::nsf::is ${:scope} [$domain name]]} { + # error "The entity '[$domain name]' does not qualify as '${:scope}'" + # } next } } :method inherited {member} { - if {[${:name} info is class]} { + set prj [:current_project] + set box [$prj sandbox] + if {[$box eval [list ::nsf::is class ${:name}]]} { set inherited [dict create] foreach c [lreverse [${:name} info heritage]] { set entity [[::nsf::current class] id $c] @@ -959,6 +1016,9 @@ # PartTag create @method \ -superclass StructuredEntity { + :attribute @syshook:boolean -slotclass ::nx::doc::SwitchAttribute { + set :default 0 + } :attribute {@modifier public} -slotclass ::nx::doc::PartAttribute :attribute @parameter -slotclass ::nx::doc::PartAttribute { set :part_class ::nx::doc::@param @@ -1081,6 +1141,9 @@ set comment "Perfect match" } else { set comment "actual parameter: $actualParams" + if {[info exists :pdata]} { + lappend :pdata status mismatch + } } append comment "
Syntax: obj ${:name} $syntax" } else { @@ -1200,7 +1263,7 @@ interp alias {} ::nx::doc::@acrfirst {} ::nx::doc::@glossary namespace export CommentBlockParser @command @object @class @package \ - @project @method @attribute @parameter @ + @project @method @attribute @parameter @ MixinLayer } @@ -1398,7 +1461,12 @@ set preprocessed [join [:as_list] " "] set preprocessed [:map $preprocessed] set preprocessed [:unescape $preprocessed] - return [subst $preprocessed] + # TODO: For now, we take a passive approach: Some docstrings + # might fail because they contain substitution characters + # ($,[]); see nx.tcl + # ... + catch {set preprocessed [subst $preprocessed]} msg + return $preprocessed } } @@ -1472,8 +1540,8 @@ # is called from within a public forward. This should qualify as # a valid call site (from "within" the same object!), shouldn't it? # :protected class-object attribute current_project:object,type=::nx::doc::@project - :class-object attribute current_project:object,type=::nx::doc::@project - :public forward current_project [current] %method + # :class-object attribute current_project:object,type=::nx::doc::@project + # :public forward current_project [current] %method # # TODO: For now, this acts as the counterweight to "origin", @@ -1484,8 +1552,23 @@ :class-object attribute rendered_entity:object,type=::nx::doc::Entity :public forward rendered_entity [current] %method - :public forward print_name %current name + # :public forward print_name %current name + :public method print_name {-status:switch} { + set status_mark "" + if {$status} { + set cls "" + if {[info exists :pdata]} { + set cls [expr {[dict exists ${:pdata} status]?\ + [dict get ${:pdata} status]:""}] + } else { + set cls "extra" + } + set status_mark " " + } + return "${:name}$status_mark" + } + :method fit {str max {placeholder "..."}} { if {[llength [split $str ""]] < $max} { return $str; @@ -1537,7 +1620,7 @@ set tagpath [split [string trimleft $tag @] .] lassign [::nx::doc::Tag normalise $tagpath $names] err res if {$err} { - puts stderr RES=$res + # puts stderr RES=$res return "?"; } lassign [::nx::doc::Tag find -all -strict {*}$res] err path @@ -1814,177 +1897,818 @@ } # -# post processor for initcmds and method bodies +# sandboxing # -namespace eval ::nx { - namespace import -force ::nx::doc::* - ::nx::Object create doc { - :method log {msg} { - puts stderr "[current]->[uplevel 1 [list ::nsf::current method]]: $msg" +namespace eval ::nx::doc { + namespace import -force ::nx::* + Class create Sandbox { + + :public class-object method type=in {name value arg} { + if {$value ni [split $arg |]} { + error "The value '$value' provided for parameter $name not permissible." + } + return $value } - # @method process + :public class-object method type=fqn {name value} { + if {[string first "::" $value] != 0} { + error "The value '$value' must be a fully-qualified Tcl name." + } + return $value + } + + :public class-object method type=fpathtype {name value arg} { + # + # Note: We might receive empty strings in case of [eval]s! + # + set pt [file pathtype $value] + if {$value ne "" && $pt ne $arg} { + error "The filepath '$value' must be $arg, rather than $pt." + } + return $value + } + + :public class-object method type=nonempty {name value} { + if {$value eq ""} { + error "An empty value is not allowed for parameter '$name'." + } + return $value + } + + :protected attribute {current_packages "*"} + :attribute {permissive_pkgs:multivalued "*"} { + set :incremental 1 + } + # - # There is a major distinction: Is the entity the comment block is - # referring to given *extrinsically* (to the comment block) or - # *intrinsically* (as a starting tag). - # - # a. extrinsic: 'thing' is a valid class or object name - # b. intrinsic: 'thing' is a arbitrary string block describing - # a script. - # - :public method process {{-noeval false} thing args} { - # 1) in-situ processing: a class object - if {[::nsf::isobject $thing]} { - if {[$thing eval {info exists :__initcmd}]} { + # some callbacks invoked from within the sandbox interp + # + + :public method at_source {filepath} { + set cpackage [lindex ${:current_packages} end] + if {$cpackage in ${:permissive_pkgs}} { + lappend :source $cpackage $filepath + } + } + + :public method at_register_package {pkg_name} { + lappend :current_packages [string tolower $pkg_name] + } + :public method at_deregister_package {} { + set :current_packages [lrange ${:current_packages} 0 end-1] + } + # [list ->status:in,arg=complete|missing|prototype|mismatch,slot=[current] missing] + :public method at_register_command [list \ + name:fqn,slot=[current] \ + ->cmdtype:in,arg=object|proc|method,slot=[current] \ + ->source:fpathtype,arg=absolute,slot=[current] \ + {->nsexported:boolean 0} \ + {->nsimported:boolean 0} \ + ->docstring:optional,nonempty,slot=[current] \ + ] { + # peek the currently processed package (if any) + set storable_vars [info vars >*] + set cpackage [lindex ${:current_packages} end] + if {$cpackage in ${:permissive_pkgs}} { + dict set :registered_commands $name package $cpackage + foreach svar $storable_vars { + dict set :registered_commands $name [string trimleft $svar >] [set $svar] + } + } + } + + :public method at_deregister_command [list name:fqn,slot=[current]] { + set cpackage [lindex ${:current_packages} end] + if {$cpackage in ${:permissive_pkgs}} { + dict unset :registered_commands $name + } + } + + :public method init args { + :do { + + # + # hide selected built-in Tcl commands and put simple + # forwarding proxies in place ... + # + # TODO: refactor the proxy handling ... + # + interp hide "" proc + interp hide "" namespace + interp hide "" source + interp hide "" load + interp hide "" package + interp hide "" auto_import + + interp invokehidden "" proc ::proc args { + #set ns [uplevel [list interp invokehidden "" namespace current]] + uplevel [list interp invokehidden "" proc {*}$args] + } + + proc ::namespace args { + #set ns [uplevel [list interp invokehidden "" namespace current]] + #interp invokehidden "" -namespace $ns namespace {*}$args + uplevel [list interp invokehidden "" namespace {*}$args] + } + + proc ::source args { + uplevel [list interp invokehidden "" source {*}$args] + } + + proc ::load args { + # set ns [uplevel [list interp invokehidden "" namespace current]] + # interp invokehidden "" -namespace $ns load {*}$args + uplevel [list interp invokehidden "" load {*}$args] + + } + + proc ::package args { + # set ns [uplevel [list interp invokehidden "" namespace current]] + # interp invokehidden "" -namespace $ns package {*}$args + uplevel [list interp invokehidden "" package {*}$args] + } + + proc ::auto_import args { + # set ns [uplevel [list interp invokehidden "" namespace current]] + # interp invokehidden "" -namespace $ns auto_import {*}$args + uplevel [list interp invokehidden "" auto_import {*}$args] + } + + namespace eval ::nx::doc { - :analyze_initcmd [expr {[::nsf::is class $thing]?"@class":"@object"}] $thing [$thing eval {set :__initcmd}] - } - } elseif {![catch {package present $thing} msg]} { - # For tcl packages, we assume that the package is sourceable - # in the current interpreter. - set i [interp create] - set cmd [subst -nocommands { - package req nx::doc - namespace import -force ::nx::*; - ::nx::Class create SourcingTracker { - :method create args { - set obj [next]; - #[::nsf::current class] eval { - # if {![info exists :scripts([info script])]} { - #dict create :scripts - #dict set :scripts [info script] objects - # } - #} - #puts stderr "dict lappend :scripts([info script]) objects [current]" - [::nsf::current class] eval [list dict set :scripts [info script] objects \$obj _] - return \$obj + proc is_exported {name} { + # + # ! ISSUE: The built-in [namespace] command is hidden in our + # ! sandbox interp when [is_exported] is used during a + # ! 2pass!!!! + # + set calling_ns [uplevel [list interp invokehidden "" namespace current]] + set ns [interp invokehidden "" namespace current]::_?_ + interp invokehidden "" namespace eval $ns \ + [list interp invokehidden "" namespace import -force $name] + set is [expr {[info commands ${ns}::[interp invokehidden "" namespace tail $name]] ne ""}] + interp invokehidden "" namespace delete $ns + return $is + } + + + proc __trace_pkg {} { + + #puts stderr ">>> INIT [package names]" + # ::interp hide "" source + ::proc ::source {path} { + set ns [uplevel [list namespace current]] + if {[file tail $path] ne "pkgIndex.tcl"} { + ::nx::doc::__at_source [file normalize $path] + } + uplevel [list interp invokehidden "" source $path] } + + proc list_commands {{parent ""}} { + set ns [dict create] + #set cmds [string trim "[join [info commands ${parent}::*] \" 0 \"] 0" 0] + # + # Note: We trigger a [namespace import] for the + # currently processed namespace before requesting the + # command list in order to have the auto_load feature + # initialise commands otherwise found too late, + # i.e. after having computed the [info + # commands] snapshot! + # +# namespace eval ::nx::doc::__x [list namespace import -force ${parent}::*] + set cmds [info commands ${parent}::*] + + set exported [list] + foreach cmd $cmds { + dict set ns ::[string trimleft $parent :] $cmd [is_exported $cmd] + +#[expr {[info commands ::nx::doc::__x::[namespace tail $cmd]] ne ""}] + } + + foreach nsp [namespace children ${parent}::] { + set ns [dict merge $ns [list_commands ${nsp}]] + } + return $ns + } + + + ::proc ::load args { + + set ns [uplevel [list namespace current]] + + # + # pre-state + # + # set pre_loaded [dict values \ + # [dict create {*}[concat {*}[info loaded ""]]]] + set pre_loaded [lreverse [concat {*}[info loaded ""]]] + set pre [::nx::doc::list_commands] + set pre_commands [dict create {*}[concat {*}[dict values $pre]]] + set pre_namespaces [dict keys $pre] + + interp invokehidden "" -namespace $ns load {*}$args + + # + # post-state + # + #set post_loaded [dict create {*}[concat {*}[info loaded ""]]] + set post_loaded [lreverse [concat {*}[info loaded ""]]] + set post [::nx::doc::list_commands] + set post_commands [dict create {*}[concat {*}[dict values $post]]] + set post_namespaces [dict keys $post] + + # + # deltas + # + set delta_commands [dict remove $post_commands {*}[dict keys $pre_commands]] + + set delta_namespaces [dict keys [dict remove [dict create {*}"[join $post_namespaces " _ "] _"] {*}$pre_namespaces]] + + set delta_pkg [dict remove \ + [dict create {*}$post_loaded] \ + [dict keys [dict create {*}$pre_loaded]]] + + #puts stderr "DELTAS pkg $delta_pkg" + #puts stderr "DELTAS namespace $delta_namespaces" + #puts stderr "DELTAS commands $delta_commands" + + lassign $delta_pkg pkg_name filepath + set filepath [file normalize $filepath] + foreach {cmd isexported} $delta_commands { + ::nx::doc::__at_register_command $cmd \ + ->cmdtype proc \ + ->source $filepath \ + ->nsexported $isexported + } + } + + ::proc ::package {subcmd args} { + set ns [uplevel [list namespace current]] + set was_registered 0 + switch -glob -- $subcmd { + ifneeded { + lassign $args pkg_name version script + append wrapped_script "::nx::doc::__at_register_package $pkg_name;\n" $script "\n::nx::doc::__at_deregister_package;" + set args [list $pkg_name $version $wrapped_script] + } + } + interp invokehidden "" -namespace $ns package $subcmd {*}$args + # uplevel [list interp invokehidden "" package $subcmd {*}$args] +# if {$was_registered} { +# ::nx::doc::__at_deregister_package +# } + } + + # + # Note that we have to wrap up Tcl's auto_import due to + # our practise of [namespace import]'ing application + # namespaces to verify whether commands are actually + # exported; see list_commands. Currently, we escape to a + # generic package called TCL_LIBRARY to filter out + # commands lazily acquired through the auto_load + # mechanism, triggered by the [namespace import] + # probing. + # + #::interp hide "" auto_import + ::proc ::auto_import {pattern} { + set ns [uplevel [list namespace current]] + ::nx::doc::__at_register_package TCL_LIBRARY; + interp invokehidden "" -namespace $ns auto_import $pattern + ::nx::doc::__at_deregister_package; + } } - ::nx::Object mixin add SourcingTracker - package forget $thing - package req $thing - ::nx::Object mixin delete SourcingTracker - #puts stderr sourced_scripts=[SourcingTracker eval {dict keys \${:scripts}}] - dict for {script entities} [SourcingTracker eval {set :scripts}] { - doc process \$script \$entities + proc __init {} { + # 1) provide for tracing NSF objects + if {[info commands ::nsf::configure] ne "" && \ + [::nsf::configure objectsystem] ne ""} { + ::nsf::configure keepinitcmd true; + + rename ::nsf::method ::nsf::_%&method + ::interp invokehidden "" proc ::nsf::method { + object + args + } { + set handle [uplevel [list ::nsf::_%&method $object {*}$args]] + if {$handle ne ""} { + ::nx::doc::__at_register_command $handle \ + ->cmdtype method \ + ->source [file normalize [info script]] + } + return $handle + } + + rename ::nsf::alias ::nsf::_%&alias + ::interp invokehidden "" proc ::nsf::alias { + args + } { + set handle [uplevel [list ::nsf::_%&alias {*}$args]] + if {$handle ne ""} { + ::nx::doc::__at_register_command $handle \ + ->cmdtype method \ + ->source [file normalize [info script]] + } + return $handle + } + + + + rename ::nsf::createobjectsystem ::nsf::_%&createobjectsystem + ::interp invokehidden "" proc ::nsf::createobjectsystem { + rootclass + rootmclass + args + } { + uplevel [list ::nsf::_%&createobjectsystem $rootclass $rootmclass {*}$args] + foreach r [list $rootclass $rootmclass] { + ::nx::doc::__at_register_command $r \ + ->cmdtype object \ + ->source [file normalize [info script]] \ + ->nsexported [::nx::doc::is_exported $r] \ + {*}[expr {[::nsf::existsvar $r __initcmd] && [::nsf::setvar $obj __initcmd] ne ""?[list ->docstring [::nsf::setvar $r __initcmd]]:[list]}] + } + } + + + array set sysmeths [concat {*}[lassign {*}[::nsf::configure objectsystem] rootclass rootmclass]] + set rootns [namespace qualifier $rootmclass] + $rootmclass $sysmeths(-class.create) ${rootns}::__Tracer + ::nsf::method ${rootns}::__Tracer \ + -public $sysmeths(-class.create) {name args} { + set obj [::nsf::next]; + ::nx::doc::__at_register_command $obj \ + ->cmdtype object \ + ->source [file normalize [info script]] \ + ->nsexported [::nx::doc::is_exported $obj] \ + {*}[expr {[::nsf::existsvar $obj __initcmd] && [::nsf::setvar $obj __initcmd] ne ""?[list ->docstring [::nsf::setvar $obj __initcmd]]:[list]}] + return $obj + } + # ISSUE: yields -> bad relationtype "mixin": must be + # object-mixin, class-mixin, object-filter, + # class-filter, class, superclass, or rootclass + # -> ::nsf::mixin defaults to "mixin" instead of "class-mixin" + # ::nsf::mixin $rootmclass ::nsf::__Tracer + ::nsf::relation $rootmclass class-mixin ${rootns}::__Tracer + + } + # 2) provide for tracing Tcl procs declared at "sourcing time" -> [proc] + #::interp hide "" proc + ::interp invokehidden "" proc ::proc {name arguments body} { + set ns [uplevel [list namespace current]] + interp invokehidden "" -namespace $ns proc $name $arguments $body + set fqn $name + if {[string first "::" $name] != 0} { + set fqn [string trimright $ns :]::$name + } + if {$arguments eq "" && $body eq ""} { + ::nx::doc::__at_deregister_command $fqn + } else { + ::nx::doc::__at_register_command $fqn \ + ->cmdtype proc \ + ->source [file normalize [info script]] \ + ->nsexported [::nx::doc::is_exported $fqn] \ + ->docstring $body + } + + } + # 3) provide for tracing commands namespace-imported at "sourcing time" + #::interp hide "" namespace + ::interp invokehidden "" proc ::namespace {subcmd args} { + set ns [uplevel [list interp invokehidden "" namespace current]] + switch -glob -- $subcmd { + imp* { + foreach pattern $args { + if {[string match "-*" $pattern]} continue; + foreach cmd [info commands $pattern] { + if {![::nx::doc::is_exported $cmd]} continue; + set type [expr {[info commands "::nsf::isobject"] ne "" &&\ + [::nsf::isobject $cmd]?"object":"proc"}] + + set imported_name [string trimright $ns :]::[namespace tail $cmd] + ::nx::doc::__at_register_command $imported_name \ + ->cmdtype $type \ + ->source [file normalize [info script]] \ + ->nsexported [::nx::doc::is_exported $imported_name] \ + ->nsimported 1 + } + } + } + } + interp invokehidden "" -namespace $ns namespace $subcmd {*}$args + } } - - }] - interp eval $i $cmd - return $i - } elseif {[file isfile $thing]} { - # 3) alien script file - set script "" - if {[file readable $thing]} { - # a) process the target file - set fh [open $thing r] - if {[catch {append script [read $fh]} msg]} { - catch {close $fh} - :log "error reading the file '$thing', i.e.: '$msg'" - } - catch {close $fh} } - # b) verify the existence of an *.nxd companion file - set rootname [file rootname $thing] + } + ::interp alias ${:interp} ::nx::doc::__at_register_command \ + "" [current] at_register_command + ::interp alias ${:interp} ::nx::doc::__at_deregister_command \ + "" [current] at_deregister_command + ::interp alias ${:interp} ::nx::doc::__at_register_package \ + "" [current] at_register_package + ::interp alias ${:interp} ::nx::doc::__at_deregister_package \ + "" [current] at_deregister_package + ::interp alias ${:interp} ::nx::doc::__at_source \ + "" [current] at_source + next + } + :protected attribute {interp ""}; # the default empty string points to the current interp + + :attribute registered_commands + + :public method get_companions {} { + set companions [dict create] + dict for {cmd props} ${:registered_commands} { + dict with props { + # $source, $package + dict set companions $source $package + } + } + set scripts [list] + dict for {source pkg} $companions { + set rootname [file rootname $source] + set dir [file dirname $source] set companion $rootname.nxd - if {[file isfile $companion] && [file readable $companion]} { - set fh [open $companion r] - if {[catch {append script "\n\n" [read $fh]} msg]} { + set srcs [dict create {*}"[join [list $source $rootname.nxd [file join $dir $pkg].nxd] " _ "] _"] + foreach src [dict keys $srcs] { + if {![file isfile $src] || ![file readable $src]} continue; + if {[file extension $src] eq [info sharedlibextension]} continue; + set fh [open $src r] + if {[catch {lappend scripts [read $fh]} msg]} { catch {close $fh} :log "error reading the file '$thing', i.e.: '$msg'" } catch {close $fh} } - - if {$script eq ""} { - :log "script empty, probaly file '$thing' is not readable" + } + return $scripts + } + + :public method get_registered_commands { + -exported:switch + -types + -not:switch + nspatterns:optional + } { + if {[info exists nspatterns]} { + set opts [join $nspatterns |] + set nspatterns "^($opts)::\[^\:\]+\$" + } + dict filter ${:registered_commands} script {cmd props} { + dict with props { + expr {[expr {[info exists nspatterns]?[expr {[regexp -- $nspatterns $cmd _] != $not}]:1}] && \ + [expr {$exported?[expr {$nsexported == $exported}]:1}] && \ + [expr {[info exists types]?[expr {$cmdtype in $types}]:1}]} } + } + #lsearch -inline -all -regexp $additions {^::nsf::[^\:]+$}] + } - doc analyze -noeval $noeval $script {*}$args - puts stderr FILE=$thing--[file readable $thing]-COMPANION=$companion--[file readable $companion]-ANALYZED-[string length $script]bytes + +# :forward do ::interp %1 {% set :interp} + :public method do {script} { + ::interp eval ${:interp} $script + } + + :public method destroy {} { + # + # TODO: Why am I called twice in doc.test? Because of the test + # enviroment (the auto-cleanup feature?) + # + # puts stderr "SELF [current object] interp ${:interp}" + # ::nsf::__db_show_stack + if {${:interp} ne ""} { + if {[interp exists ${:interp}]} { + interp delete ${:interp} + } } else { - # 4) we assume a string block, e.g., to be fed into eval - set i [interp create] - set cmd [subst { - package req nx::doc - namespace import -force ::nx::doc::* - doc analyze -noeval $noeval [list $thing] - }] - interp eval $i $cmd - #interp delete $i - return $i + :do { + if {[info commands ::nsf::configure] ne ""} { + ::nsf::configure keepinitcmd false; + array set sysmeths [concat {*}[lassign {*}[::nsf::configure objectsystem] rootclass rootmclass]] + # TODO: some cleanup is only needed if __init has been called + # (which is not always the case). refactor the code + # accordingly. + set rootns [namespace qualifier $rootmclass] + if {[::nsf::isobject ${rootns}::__Tracer]} { + ${rootns}::__Tracer $sysmeths(-object.destroy) + ::nsf::relation $rootmclass class-mixin {} + } + if {[info commands ::nsf::_%&createobjectsystem] ne ""} { + rename ::nsf::_%&createobjectsystem ::nsf::createobjectsystem + } + unset rootns + } + rename ::proc "" + interp expose "" proc + rename ::namespace "" + interp expose "" namespace + rename ::source "" + interp expose "" source + rename ::load "" + interp expose "" load + rename ::package "" + interp expose "" package + rename ::auto_import "" + interp expose "" auto_import + + proc ::nx::doc::__at_register_command {} {} + proc ::nx::doc::__at_deregister_command {} {} + proc ::nx::doc::__at_register_package {} {} + proc ::nx::doc::__at_deregister_package {} {} + } } + next } + } + namespace export Sandbox +} +# +# post processor for initcmds and method bodies +# +namespace eval ::nx { + + namespace import -force ::nx::doc::* + + MixinLayer create processor -prefix ::nx::doc { + namespace eval ::nx::doc { + namespace eval ::nx::doc::MixinLayer { + namespace export Mixin + } + namespace import -force ::nx::doc::MixinLayer::* + namespace export Mixin + } - :public method analyze {{-noeval false} script {additions ""}} { - # NOTE: This method is to be executed in a child/ slave - # interpreter. - if {!$noeval} { - uplevel #0 [list namespace import -force ::nx::doc::*] - set pre_commands [:list_commands] - uplevel #0 [list eval $script] - set post_commands [:list_commands] - if {$additions eq ""} { - set additions [dict keys [dict remove [dict create {*}"[join $post_commands " _ "] _"] {*}$pre_commands]] - } else { - set additions [dict keys [dict get $additions objects]] + namespace import -force ::nx::doc::* + + Mixin create [current]::Entity { + :public method get_command_name {} { + return ${:name} + } + :public method init args { + next + set prj [:current_project] + if {$prj ne ""} { + set box [$prj sandbox] + set cmdname [:get_command_name] + if {[$box eval [concat dict exists \${:registered_commands} $cmdname]]} { + :pdata [$box eval [concat dict get \${:registered_commands} $cmdname]] + } } - # puts stderr ADDITIONS=$additions + [[current class] info parent] at_processed [current] } - set blocks [:comment_blocks $script] - # :log "blocks: '$blocks'" - # 1) eval the script in a dedicated interp; provide for - # recording script-specific object additions. - # set failed_blocks [list] - foreach {line_offset block} $blocks { - # 2) process the comment blocks, however, fail gracefully here - # (most blocks, especially in initcmd and method blocks, are - # not qualified, so they are set to fail. however, record the - # failing ones for the time being - set cbp [::nx::doc::CommentBlockParser process $block] - # TODO: How to handle contingent (recoverable) conditions here? - # if {[catch {::nx::doc::CommentBlockParser process $block} msg]} { - # if {![InvalidTag behind? $msg] && ![StyleViolation behind? $msg] && ![MissingPartofEntity behind? $msg]} { - # if {[Exception behind? $msg]} { - # ::return -code error -errorinfo $::errorInfo "[$msg info class]->[$msg message]" - # # error [$msg info class]->[$msg message] - # } - # ::return -code error -errorinfo $::errorInfo $msg - # } - # } + } + + Mixin create [current]::@method -superclass [current]::Entity { + :method get_command_name {} { + return ::nsf::classes::[string trimleft [[:partof] name] :]::${:name} } - # 3) process the recorded object additions, i.e., the stored - # initcmds and method bodies. - foreach addition $additions { - # TODO: for now, we skip over pure Tcl commands and procs - if {![::nsf::is object $addition]} continue; - set kind [expr {[::nsf::is class $addition]?"@class":"@object"}] - #puts stderr "ADDITION :process [namespace origin $addition]" - if {[$addition eval {info exists :__initcmd}]} { - :analyze_initcmd $kind $addition [$addition eval {set :__initcmd}] + } + + # + # mixin layer interface + # + + :class-object method apply {} { + unset -nocomplain :processed_entities + next + } + + :class-object method revoke {} { + next + if {[info exists :processed_entities]} { + return [dict keys ${:processed_entities}] + } + } + + :public class-object method at_processed {entity} { + dict set :processed_entities $entity _ + } + + # + # processor interface + # + + :class-object method log {msg} { + puts stderr "[current]->[uplevel 1 [list ::nsf::current method]]: $msg" + } + + :public class-object method process {-sandboxed:switch {-type project} thing} { + if {$type ne "project"} { + # TODO: Fix the naming requirements ... + set project [@project new -name "_%@"] + $project sources [list $type $thing] + } else { + set project $thing + } + + $project sandbox [Sandbox new -interp [expr {$sandboxed?[interp create]:""}]] + set sources [dict create] + foreach {type name} [$project sources] { + dict lappend sources $type $name + } + #puts stderr "SOURCES $sources" + dict for {type instances} $sources { + :[current method]=$type $project $instances + } + return $project + } + + :protected class-object method process=package {project pkgs} { + set box [$project sandbox] + $box permissive_pkgs $pkgs + set 1pass "" + foreach pkg $pkgs { + if {[catch {package present $pkg} _]} { + error "Tcl package '$pkg' cannot be found." } + append 1pass "package req $pkg\n" + } - # TODO: Note, the CommentBlockParser should operate on the - # level of a single block, not entire initcmd and method body - # scripts. The process=@object ressembles some ::nx::doc - # methods, so relocated and call the parser from within. - set entity [@ $kind $addition] - #puts stderr ":process=$kind $entity" - :process=$kind $entity + # + # a) 1-pass: requiring the packages first will provide + # all dependencies (also those not to be documented). + # + $box do "::nx::doc::__trace_pkg; $1pass" + + # + # b) 2-pass: [source] will re-evaluate the package scripts + # (note, [load]-based extension packages are not covered by this!) + #" + if {[$box eval {info exists :source}]} { + foreach {pkg src} [$box eval {set :source}] { + # + # TODO: 2-pass [source]s should not trigger transitive [source]s. we + # have flattened the relevant [source] hierarchy in the + # 1-pass. + # + append 2pass \ + "::nx::doc::__at_register_package $pkg;\n" \ + "source $src;\n" \ + "::nx::doc::__at_deregister_package;\n" + } + $box do "::nx::doc::__init; $2pass" } + + set scripts [$box get_companions] + set provided_entities [list] + foreach script $scripts { + lappend provided_entities {*}[:readin $script] + } + + # output + # 1. absent entities (doc[yes]->program[no]) + # => all doc entities without pdata +# puts stderr "--- $provided_entities" + set present_entities [::nx::doc::filtered $provided_entities {[info exists :pdata]}] + # TODO: the nspatterns should be consumed from the source + # specification and should not be hardcoded here ... review + # later ... + set generated_commands [$box get_registered_commands [list ::nsf ::nx]] + foreach pe $present_entities { + dict unset generated_commands [$pe name] + } +# puts stderr "PRESENT $present_entities" +# puts stderr "ABSENT [::nx::doc::filtered $provided_entities {![info exists :pdata]}]" + # 2. generated entities (doc[no]->program[yes]) + # => all registered_commands without doc entity +# puts stderr "== TO GENERATE == [dict keys $generated_commands]" + dict for {cmd info} $generated_commands { + if {[string match ::nsf::classes::* $cmd]} continue; + if {[string match ::nsf::objects::* $cmd]} continue; + if {[string match *::slot::* $cmd]} continue; + dict with info { + # + # TODO: for now, we assume objects beyond this point + # ... relax later! + # + if {$cmdtype ni [list object proc]} continue; + set kind @command + if {$cmdtype eq "object"} { + set kind [expr {[$box do [list ::nsf::is class $cmd]]?\ + "@class":"@object"}] + } + set entity [@ $kind $cmd] + :process=$kind $project $entity + $entity pdata [lappend info status missing] + } + } } - :method list_commands {{parent ""}} { - set cmds [info commands ${parent}::*] - foreach nsp [namespace children $parent] { - lappend cmds {*}[:list_commands ${nsp}] + :protected class-object method process=source {project filepath} {;} + + :protected class-object method process=eval {project scripts} { + set box [$project sandbox] + # + # 1a) 1pass ... TODO: should tracing be enabled in this scenario? ... + # + foreach script $scripts { + $box do $script } - return $cmds + + # + # 2) 2pass ... + # + $box do [list ::nx::doc::__init] + + foreach script $scripts { + $box do $script + } + # + # 3) documentation processing + # + #puts stderr ">>> CMDS [$box get_registered_commands]" + + # 3a) top-level processing + foreach script $scripts { + :readin $script + } + + # 3b) initcmds, proc bodies ... + + dict for {cmd info} [$box get_registered_commands] { + dict with info { + # + # TODO: for now, we assume objects beyond this point + # ... relax later! + # + if {$cmdtype ne "object"} continue; + set kind [expr {[$box do [list ::nsf::is class $cmd]]?"@class":"@object"}] + if {[info exists docstring]} { + lassign [:readin \ + -docstring \ + -tag $kind \ + -name $cmd \ + -parsing_level 1 \ + $docstring] entity processed_entities + unset docstring + } else { + set entity [@ $kind $cmd] + } + :process=$kind $project $entity + } + } } + + :public class-object method readin { + -docstring:switch + -tag + -name + -partof_entity:object,type=::nx::doc::StructuredEntity + {-parsing_level:integer 0} + script + } { - :public method analyze_line {line} { + set blocks [:comment_blocks $script] + + set first_block 1 + set processed_entities [list] + foreach {line_offset block} $blocks { + array set arguments [list -initial_section context \ + -parsing_level $parsing_level] + + if {$docstring} { + if {[info exists partof_entity]} { + set arguments(-partof_entity) $partof_entity + } + if {![info exists tag] || ![info exists name]} { + error "In docstring mode, provide the tag and the name of + a docstring-owning documentation entity object." + } + if {$first_block} { + # + # TODO: Note that the two "creation procedures" are not + # idempotent; the relative one overwrites description + # blocks of pre-exisiting entities, the freestanding @ + # does not ... fix later when reviewing these parts of the + # program ... + # + set docentity [expr {[info exists partof_entity]?\ + [$partof_entity $tag $name]:[@ $tag $name]}] + set arguments(-partof_entity) $docentity + if {$line_offset <= 1} { + set arguments(-initial_section) description + set arguments(-entity) $docentity + } + } + } + + set args [array get arguments] + lappend args $block + # puts stderr "::nx::doc::CommentBlockParser process {*}$args" + #::nx::doc::Entity mixin add [current]::Entity + :apply + ::nx::doc::CommentBlockParser process {*}$args + lappend processed_entities {*}[:revoke] + set first_block 0 + } + if {$docstring && [info exists arguments(-partof_entity)]} { + return [list $arguments(-partof_entity) $processed_entities] + } else { + return $processed_entities + } + } + + :public class-object method analyze_line {line} { set regex {^[\s#]*#+(.*)$} if {[regexp -- $regex $line --> comment]} { return [list 1 [string trimright $comment]] @@ -1993,7 +2717,7 @@ } } - :public method comment_blocks {script} { + :public class-object method comment_blocks {script} { set lines [split $script \n] set comment_blocks [list] set was_comment 0 @@ -2002,12 +2726,6 @@ 0,1 { set line_offset $line_counter; set comment_block [list]; - # Note, we use [split] here to avoid stumbling over - # uncommented script blocks which contain pairs of curly - # braces which appear scattered over several physical lines - # of code. This avoids "unmatched open brace" failures when - # feeding each physical line to a list command (later, in - # the parsing machinery) lappend comment_block $text} 1,0 {lappend comment_blocks $line_offset $comment_block} 1,1 {lappend comment_block $text} @@ -2024,127 +2742,84 @@ } return $comment_blocks } - - :public method analyze_initcmd {{-parsing_level 1} docKind name initcmd} { - set first_block 1 - set failed_blocks [list] - foreach {line_offset block} [:comment_blocks $initcmd] { - set arguments [list] - if {$first_block} { - set id [@ $docKind $name] - # - # Note: To distinguish between intial comments blocks - # in initcmds and method bodies which refer to the - # surrounding entity (e.g., the object or the method) - # we use the line_offset recorded by the - # comment_blocks() scanner. Later, we plan to use the - # line_offset to compute line pointers for error - # messages. Also, we can use the line offsets of each - # comment block to identify faulty comment blocks. - # - # A acceptance level of <= 1 means that a script - # block must contain the first line of this - # special-purpose comment block either in the very - # first or second script line. - # - if {$line_offset <= 1} { - lappend arguments -initial_section description - lappend arguments -entity $id - } - set first_block 0 - } else { - set initial_section context - } - lappend arguments $block - # TODO: Filter for StyleViolations as >the only< valid case - # for a continuation. Report other issues immediately. What - # about InvalidTag?! - # TODO: Passing $id as partof_entity appears unnecessary, - # clean up the logic in CommentBlockParser->process()!!! - #puts stderr "==== CommentBlockParser process -partof_entity $id {*}$arguments" - set cbp [CommentBlockParser process -parsing_level $parsing_level -partof_entity $id {*}$arguments] - -# if {[catch {CommentBlockParser process -partof_entity $id {*}$arguments} msg]} { -# lappend failed_blocks $line_offset -# } - } - - }; # analyze_initcmd method # TODO: how can I obtain some reuse here when later @class is # distinguished from @object (dispatch along the inheritance # hierarchy?) - :public method process=@class {entity} { - set name [$entity name] + :public class-object method process=@command {project entity} {;} + + :public class-object method process=@class {project entity} { + set name [$entity name] + set box [$project sandbox] # attributes - foreach slot [$name info slots] { - if {[$slot eval {info exists :__initcmd}]} { - set blocks [:comment_blocks [$slot eval {set :__initcmd}]] - foreach {line_offset block} $blocks { - if {$line_offset > 1} break; - set scope [expr {[$slot per-object]?"class-object":"class"}] - set id [$entity @${scope}-attribute [$slot name]] - CommentBlockParser process \ - -parsing_level 2 \ - -partof_entity $entity \ - -initial_section description \ - -entity $id \ - $block - } + foreach slot [$box do [list $name info slots]] { + if {[$box do [list $slot eval {info exists :__initcmd}]]} { + # + # TODO: Here, we eagerly create doc entities, is this an issue? + # Should we mark them for removal if not further processed? + # This might be contradicting to the requirement of + # identifying documented/undocumented program structures. + # + # There are two alternatives: + # -> use a freestanding identity generator (preferred!) + # -> mark the entity for deletion + # + # set id [$entity @${scope}-attribute [$box do [list $slot name]]] + + set scope [expr {[$box do [list $slot per-object]]?"class-object":"class"}] + :readin \ + -partof_entity $entity \ + -docstring \ + -tag @${scope}-attribute \ + -name [$box do [list $slot name]] \ + -parsing_level 2 \ + [$box do [list $slot eval {set :__initcmd}]] - # :analyze_initcmd -parsing_level 2 @class $name [$name eval {set :__initcmd}] } } - foreach methodName [$name info methods \ - -methodtype scripted \ - -callprotection all] { - # TODO: should the comment_blocks parser be relocated? - set blocks [:comment_blocks [${name} info method \ - body $methodName]] - foreach {line_offset block} $blocks { - if {$line_offset > 1} break; - set id [$entity @class-method $methodName] - CommentBlockParser process \ - -parsing_level 2 \ - -partof_entity $entity \ - -initial_section description \ - -entity $id \ - $block - } + foreach methodName [$box do [list $name info methods \ + -methodtype scripted \ + -callprotection all]] { + :readin \ + -partof_entity $entity \ + -docstring \ + -tag @class-method \ + -name $methodName \ + -parsing_level 2 \ + [$box do [list ${name} info method body $methodName]] } - :process=@object $entity class-object + :process=@object $project $entity class-object } - :public method process=@object {entity {scope ""}} { + # + # TODO: how to resolve to the current project's context. For now, + # we pass a parameter value, revisit this decision once we decide + # on a location for this behaviour. + # + :public class-object method process=@object {project entity {scope ""}} { set name [$entity name] - + set box [$project sandbox] # methods - foreach methodName [${name} {*}$scope info methods\ - -methodtype scripted \ - -callprotection all] { - - set blocks [:comment_blocks [${name} {*}$scope info method \ - body $methodName]] - foreach {line_offset block} $blocks { - if {$line_offset > 1} break; - set id [$entity @class-object-method $methodName] - CommentBlockParser :process \ - -parsing_level 2 \ - -partof_entity $name \ - -initial_section description \ - -entity $id \ - $block - } + + foreach methodName [$box do [list ${name} {*}$scope info methods\ + -methodtype scripted \ + -callprotection all]] { + set tag [join [list {*}$scope method] -] + # set id [$entity @$tag $methodName] + :readin \ + -partof_entity $entity \ + -docstring \ + -tag @$tag \ + -name $methodName \ + -parsing_level 2 \ + [$box do [list ${name} {*}$scope info method body $methodName]] } } - # activate the recoding of initcmds - ::nsf::configure keepinitcmd true - } } @@ -2429,19 +3104,23 @@ # realise the sub-state (a variant of METHOD-FOR-STATES) and their # specific event handling # set :lineproc {{tag args} {return [concat {*}$args]}} - set :lineproc {{tag args} {return [list $tag $args]}} + # set :lineproc {{tag args} {puts stderr LINE=[list $tag {*}$args]; return [list $tag {*}$args]}} + set :lineproc {{tag args} {return [list $tag [expr {$args eq ""?$args:[list $args]}]]}} :method parse@tag {line} { lassign [apply [[current class] eval {set :lineproc}] {*}$line] tag line + #set line [lassign [apply [[current class] eval {set :lineproc}] {*}$line] tag] if {[:info lookup methods -source application $tag] eq ""} { set msg "The tag '$tag' is not supported for the entity type '[namespace tail [:info class]]" ${:block_parser} cancel INVALIDTAG $msg } #:$tag [lrange $line 1 end] - :$tag $line + #:$tag {*}[expr {$line eq ""?$line:[list $line]}] + #:$tag $line + :$tag {*}$line } :method parse@text {line} { -# puts stderr "ADDLINE([current]) :@doc add $line end" + #puts stderr "ADDLINE([current]) :@doc add $line end" :@doc add $line end } :method parse@space {line} {;} @@ -2623,7 +3302,6 @@ next } :method parse@tag {line} { -# puts stderr "PART parse@tag [current]" set r [next] # puts stderr GOT=$r if {[::nsf::isobject $r] && [$r info has type ::nx::doc::Entity]} { @@ -2632,9 +3310,7 @@ return $r } :method parse@text {line} { -# puts stderr "PART parse@text [current]" if {[info exists :current_part]} { -# puts stderr "${:current_part} @doc add $line end" ${:current_part} @doc add $line end } else { :event=next $line Index: library/nx/nx.nxd =================================================================== diff -u -N -r5d5f67b7b4a9806e10419e44efdcfe724bfcff9b -r170cefa7618f2b44f91102711607fc6fa7d12c4f --- library/nx/nx.nxd (.../nx.nxd) (revision 5d5f67b7b4a9806e10419e44efdcfe724bfcff9b) +++ library/nx/nx.nxd (.../nx.nxd) (revision 170cefa7618f2b44f91102711607fc6fa7d12c4f) @@ -11,7 +11,7 @@ # essential language primitives (in particular, <<@command # ::nx::next>> and <<@command ::nx::current>>). # -# @require Tcl +# @require nsf # @version 1.0.0a # @namespace ::nx Index: library/nx/nx.tcl =================================================================== diff -u -N -r24f725ccfeb6bfaad96722a6f39bb517a07d4c5c -r170cefa7618f2b44f91102711607fc6fa7d12c4f --- library/nx/nx.tcl (.../nx.tcl) (revision 24f725ccfeb6bfaad96722a6f39bb517a07d4c5c) +++ library/nx/nx.tcl (.../nx.tcl) (revision 170cefa7618f2b44f91102711607fc6fa7d12c4f) @@ -8,6 +8,9 @@ # set ::nsf::bootstrap ::nx + + puts stderr ====[::nsf::configure objectsystem] + # # First create the ::nx object system. # @@ -21,7 +24,7 @@ -object.defaultmethod defaultmethod -object.destroy destroy -object.init init - -object.move move + -object.move move -object.objectparameter objectparameter -object.residualargs residualargs -object.unknown unknown @@ -54,6 +57,10 @@ foreach cmd [info command ::nsf::methods::class::*] { set cmdName [namespace tail $cmd] if {$cmdName in [list "filterguard" "mixinguard"]} continue + # set tgt [Class ::nsf::methods::class::info::methods -methodtype alias -callprotection all $cmdName] + #if {$tgt ne "" && [::nsf::methodproperty Class $cmdName redefine-protected]} { + # ::nsf::methodproperty Class $cmdName redefine-protected false + #} ::nsf::alias Class $cmdName $cmd unset cmdName } @@ -165,7 +172,7 @@ if {[info exists precondition]} {lappend conditions -precondition $precondition} if {[info exists postcondition]} {lappend conditions -postcondition $postcondition} array set "" [:__resolve_method_path -per-object $name] - #puts "object method $(object).$(methodName) [list $arguments] {...}" + # puts "object method $(object).$(methodName) [list $arguments] {...}" set r [::nsf::method $(object) -per-object $(methodName) $arguments $body {*}$conditions] if {$r ne ""} { # the method was not deleted @@ -228,7 +235,7 @@ :method public {args} { set p [lsearch -regexp $args {^(method|alias|attribute|forward|setter)$}] if {$p == -1} {error "$args is not a method defining method"} - set r [{*}:$args] + set r [::nsf::dispatch [::nsf::current object] {*}$args] if {$r ne ""} {::nsf::methodproperty [::nsf::self] $r call-protected false} return $r } @@ -1086,7 +1093,7 @@ ############################################ ::nsf::invalidateobjectparameter MetaSlot - MetaSlot create ::nx::Attribute -superclass ObjectParameterSlot + MetaSlot create ::nx::Attribute -superclass ::nx::ObjectParameterSlot createBootstrapAttributeSlots ::nx::Attribute { {value_check once} @@ -1280,7 +1287,7 @@ # (without syntactic overhead). ################################################################## - Class create ::nx::ScopedNew -superclass Class { + Class create ::nx::ScopedNew -superclass ::nx::Class { :attribute {withclass ::nx::Object} :attribute container Index: nsf.nxd =================================================================== diff -u -N --- nsf.nxd (revision 0) +++ nsf.nxd (revision 170cefa7618f2b44f91102711607fc6fa7d12c4f) @@ -0,0 +1,318 @@ +# -*- Tcl -*- + +# @package nsf +# +# ... +# +# @require Tcl +# @version 1.0.0a +# @namespace ::nsf + + +# @command assertion +# +# @parameter object:object +# @parameter assertionsubcmd:required +# @parameter arg + +# @command existsvar +# +# @parameter object:object +# @parameter var + +# @command methodproperty +# +# @parameter object:object +# @parameter -per-object:switch +# @parameter methodName +# @parameter methodproperty Accepts one of: '''protected''', +# '''redefine-protected''', '''returns''', '''slotobj''' +# @parameter value + +# @command setter +# +# @parameter object:object +# @parameter -per-object:switch +# @parameter parameter + +# @command createobjectsystem +# +# @parameter rootClass +# @parameter rootMetaClass +# @parameter systemMethods:optional + +# @command dispatch +# +# @parameter object:object +# @parameter -objscope +# @parameter command +# @parameter args + +# @command deprecated +# +# @parameter what +# @parameter oldCmd +# @parameter newCmd:optional + +# @command objectproperty +# +# @parameter object:object +# @parameter objectkind Accepts one of: '''type''', '''object''', +# '''class''', '''baseclass''', '''metaclass''', '''hasmixin''' +# @parameter value:optional + +# @command importvar +# +# @parameter object:object +# @parameter args + +# @command parametercheck +# +# @parameter -nocomplain +# @parameter param +# @parameter value:optional + +# @command forward +# +# @parameter object:object +# @parameter -per-object:switch +# @parameter method +# @parameter -default +# @parameter -earlybinding:switch +# @parameter -methodprefix +# @parameter -objscope:switch +# @parameter -onerror +# @parameter -verbose:switch +# @parameter target +# @parameter args + +# @command setvar +# +# @parameter object:object +# @parameter variable +# @parameter value + +# @command method +# +# @parameter object:object +# @parameter -inner-namespace +# @parameter -per-object +# @parameter -public +# @parameter name +# @parameter args +# @parameter body +# @parameter -percondition +# @parameter -postcondition + +# @command next +# +# Invokes the shadowed (i.e, same-named) method which is next along +# the precedence path and returns the results of this invocation. If +# '''next''' is called without arguments, the arguments of the current +# method (i.e., the arguments as present at the current callframe) are +# passed through to the shadowed method. If next is invoked with the +# flag --noArgs, the shadowed method is called without the active +# callframe arguments. If other arguments are specified for '''next''' +# explicitly, these will be passed instead. +# +# @parameter --noArgs:optional Deactivates the forward-passing of the current callframe's arguments +# @parameter args Explicitly declared arguments to pass to shadowed methods + + +# @command current +# +# An introspective command which allows you to explore the callstack +# from within the scope of a method (or a proc bound to an object via +# '''alias'''). If executed without specifying a subcommand, +# i.e. '''[current]''', it defaults to <<@command.command "current +# object">>. While '''current''' operates on the Tcl callstack, it is +# aware of object-specific callstack and frame information. To some +# extent, this object introspection protocol can be approximated at +# the script level by instrumenting '''[info frame]'''. +# +# If invoked outside of an object's scope (e.g., an ordinary proc, the +# global namespace), it fails and reports '''No current object'''. +# +# It comes with a variety of sub-commands to query the object-specific +# callstack information available. See below. +# +# @sub-command class Returns the name of the class holding the +# currently executing per-class method, if and only if called from +# within a per-class method. Note, that this method-owning class may +# be different to the class of the current object. If called from +# within a per-object method, it returns an empty string. +# +# @sub-command method Returns the name of the currently executing method. +# +# @sub-command callingclass Returns the name of the class which is +# calling into the executing method. +# +# @sub-command callingobject Returns the name of the object which is +# calling into the executing method. +# +# @sub-command calledclass Returns the name of the class that holds +# the originally (and now shadowed) target method (applicable in +# mixin classes and filters). +# +# @sub-command calledmethod Returns the name of the target method +# (applicable in a filter only). +# +# @sub-command isnextcall Returns 1 if the executing method was +# invoked via <<@command next>>, 0 otherwise. +# +# @sub-command next Returns the name of the method next on the +# precedence path as a string. +# +# @sub-command filterreg In a method serving as active filter, +# returns the name of the object (class) on which the method is +# registered as a filter. +# +# @command callinglevel Resolves the callstack level which represents +# the originating invocation into the currently executing method. Levels +# of indirection (e.g., filters) and method combination along the +# class linearisation path ('''next''') are ignored. The callstack is +# returned as an absolute level number (# followed by a digit). The +# level number returned can be directly used as the first argument to +# '''uplevel''' or '''upvar''' calls. See also <<@command.command +# "current activelevel">> +# +# @sub-command activelevel Returns the actual callstack level calling +# into the executing method. The active might correspond the +# '''callinglevel''', but this is not necessarily the case. The +# '''activelevel''' counts <<@command next>> call. The level +# is returned in a form so that it can be used as first argument in +# '''uplevel''' or '''upvar'''. + +# @command.command {current object} +# +# The default sub-command returns the name of the object currently +# active on the callstack. + + +# @command configure +# +# A top-level configuration facility which allows you modify +# properties of the "Next" object system for the scope of an entire +# '''interp'''. + +# @command.sub-command {configure filter} +# +# Allows turning on or off filters globally for the current +# interpreter. By default, the filter state is turned off. This +# function returns the old filter state. This filterless '''interp''' +# state is needed for the serializer which should introspect and stream the +# objects and classes without being affected by active filter. +# +# @parameter toggle Accepts either "on" or "off" +# @return The current filter activation state + +# @command.sub-command {configure softrecreate} +# +# Allows controlling the scheme applied when recreating an object or a +# class. By default, it is set to '''off'''. This means that the +# object/class is destroyed and all relations +# (e.g. subclass/superclass) to other objects/classes are revoked as +# well. If softrecreate is set to '''on''', the object is re-set, but not +# destroyed, the relations are +# kept. +# +# A "soft" recreation is important for e.g. reloading a file with +# class definitions (e.g. when used in OpenACS with file watching and +# reloading). With softrecreate set, it is not necessary to recreate +# dependent subclasses etc. Consider the example of a class hierarchy +# '''A <- B <- C'''. Without '''softrecreate''' set, a reload of +# '''B''' means first a destroy of B, leading to '''A <- C''', and +# instances of '''B''' are re-classed to <<@class +# ::nx::Object>>. When softrecreate is set, the class hierarchy +# remains untouched. +# +# @parameter toggle Accepts either "on" or "off" +# @return The current toggle value + + +# @command.sub-command {configure objectsystems} +# +# A mere introspection subcommand. It gives you the top level of the +# current object system, i.e., the ruling root class and root +# meta-class. For "Next": +# +# ''' +# configure objectsystems; # returns "::nx::Object ::nx::Class" +# ''' +# +# @return The active pair of root class and root meta-class + +# @command.sub-command {configure keepinitcmd} +# +# Usually, initcmd scripts are discarded by the '''interp''' once +# having been evaluated (in contrast to '''proc''' and '''method''' +# bodies). If you need them preserved for later introspection and +# processing (as in the "Next" documentation system), set this option +# to '''true'''. Then, the initcmd scripts are retained as a +# particular object variable ('''__initcmd''') of classes and +# objects. It defaults to '''false'''. +# +# @parameter value:boolean Either '''true''' or '''false''' +# @return The current setting + +# @command alias +# +# @parameter object:object The target object which becomes the owner of +# the aliased command (method, object or command). +# +# @parameter -per-object:switch If the target object is a class, one can +# specify the binding scope (i.e., per-object or per-class) of the +# aliased command +# +# @parameter methodName The name of the alias. +# @parameter -nonleaf:switch ... +# @parameter -objscope:switch ... +# @parameter cmdName The alias source as a command handle (as returned by ...) + +# @command finalize + +# @command interp +# +# @parameter name +# @parameter args + +# @command is +# +# @parameter value +# @parameter constraint +# @parameter -hasmixin +# @parameter -type +# @parameter arg + +# @command my +# +# @parameter -local +# @parameter method +# @parameter args + +# @command relation +# +# @parameter object +# @parameter relationtype +# @parameter value + +# @command provide_method +# +# @parameter require_name +# @parameter definition +# @parameter script:optional + +# @command require_method +# +# @parameter object +# @parameter name +# @parameter per_object + +# @command mixin +# +# @parameter object +# @parameter args + +# @command tmpdir +# +# @return The platform-specific path name to the system-wide temporary directory \ No newline at end of file Index: tests/doc.test =================================================================== diff -u -N -r8bfe3ac01fe62c1917587fc5fe76952d3ff8f397 -r170cefa7618f2b44f91102711607fc6fa7d12c4f --- tests/doc.test (.../doc.test) (revision 8bfe3ac01fe62c1917587fc5fe76952d3ff8f397) +++ tests/doc.test (.../doc.test) (revision 170cefa7618f2b44f91102711607fc6fa7d12c4f) @@ -50,7 +50,7 @@ } foreach {::line ::result} $lines { - ? {foreach {is_comment text} [doc analyze_line $::line] break; set is_comment} $::result "doc analyze_line '$::line'" + ? {foreach {is_comment text} [processor analyze_line $::line] break; set is_comment} $::result "processor analyze_line '$::line'" } set script { @@ -81,7 +81,7 @@ set blocks {1 {{ @package o} { 1 2 3}} 5 {{ @object o} { 1 2 3} {} { 345} { @tag1 part1} { @tag2 part2}} 17 {{ @object o # ####} { 1 2 3} {} { 345} { @tag1 part1} { @tag2 part2}}} - ? [list ::lcompare [doc comment_blocks $script] $blocks] 1 + ? [list ::lcompare [processor comment_blocks $script] $blocks] 1 } Test case parsing { @@ -344,12 +344,17 @@ ? [list [$entity @attribute] info has type ::nx::doc::@param] 1 ? [list [$entity @attribute] as_text] "Here! we check whether we can get a valid description block for text spanning multiple lines" +} + +Test case in-situ-basics { # # basic test for in-situ documentation (initcmd block) # # set script { - Class create Foo { + package req nx + namespace import -force ::nx::Class + Class create ::Foo { # The class Foo defines the behaviour for all Foo objects # # @author gustaf.neumann@wu-wien.ac.at @@ -364,7 +369,7 @@ :attribute attr1 :attribute attr2 :attribute attr3 - + # @.method foo # # This describes the foo method @@ -374,9 +379,9 @@ :method foo {a b} {;} } } - - eval $script - doc process ::Foo + + set prj [processor process -sandboxed -type eval $script] + set entity [@class id ::Foo] ? [list ::nsf::is object $entity] 1 ? [list $entity info has type ::nx::doc::@class] 1 @@ -388,7 +393,7 @@ ? [list ::nsf::is object $entity] 1 ? [list $entity info has type ::nx::doc::@attribute] 1 ? [list $entity @see] "::nx::Attribute ::nx::MetaSlot"; - + set entity [@method id ::Foo class foo] ? [list [@class id ::Foo] @method] $entity ? [list ::nsf::is object $entity] 1 @@ -401,128 +406,134 @@ } { ? [list expr [list [$p as_text] eq $expected]] 1; } + + $prj destroy +} - # TODO: how to realise scanning and parsing for mixed ex- and - # in-situ documentation? That is, how to differentiate between - # absolutely and relatively qualified comment blocks in line-based - # scanning phase (or later)? +# TODO: how to realise scanning and parsing for mixed ex- and +# in-situ documentation? That is, how to differentiate between +# absolutely and relatively qualified comment blocks in line-based +# scanning phase (or later)? +Test case mixed-mode-parsing { + set script { + package req nx namespace import -force ::nx::* # @class ::Bar # # The class Bar defines the behaviour for all Bar objects # # @author gustaf.neumann@wu-wien.ac.at # @author ssoberni@wu.ac.at - + # @class.attribute {::Bar attr1} # # This attribute 1 is wonderful # # @see ::nx::Attribute # @see ::nx::MetaSlot - + # @class.class-method {::Bar foo} # # # This describes the foo method # # @parameter a Provides a first value # @parameter b Provides a second value - + # @class.class-object-method {::Bar foo} # # This describes the per-object foo method # # @parameter a Provides a first value # @parameter b Provides a second value - + namespace eval ::ns1 { ::nx::Object create ooo } Class create Bar { - + :attribute attr1 :attribute attr2 :attribute attr3 - + # @.method foo # # This describes the foo method in the initcmd # # @parameter a Provides a first value # @parameter b Provides a second value - + :method foo {a b} { # This describes the foo method in the method body # # @parameter a Provides a first value (refined) - + } :class-object method foo {a b c} { # This describes the per-object foo method in the method body # # @parameter b Provides a second value (refined) - # @parameter c Provides a third value (first time) - + # @parameter c Provides a third value (first time) + } - + } } - - set i [doc process $script] - + + set prj [processor process -sandboxed -type eval $script] set entity [@class id ::Bar] - ? [list $i eval [list ::nsf::is object $entity]] 1 - ? [list $i eval [list $entity info has type ::nx::doc::@class]] 1 - ? [list $i eval [list $entity as_text]] "The class Bar defines the behaviour for all Bar objects"; - ? [list $i eval [list $entity @author]] "gustaf.neumann@wu-wien.ac.at ssoberni@wu.ac.at" - + ? [list ::nsf::is object $entity] 1 + ? [list $entity info has type ::nx::doc::@class] 1 + ? [list $entity as_text] "The class Bar defines the behaviour for all Bar objects"; + ? [list $entity @author] "gustaf.neumann@wu-wien.ac.at ssoberni@wu.ac.at" + # TODO: Fix the [@param id] programming scheme to allow (a) for # entities to be passed and the (b) documented structures set entity [@attribute id [@class id ::Bar] class attr1] - ? [list $i eval [list ::nsf::is object $entity]] 1 - ? [list $i eval [list $entity info has type ::nx::doc::@attribute]] 1 - ? [list $i eval [list $entity @see]] "::nx::Attribute ::nx::MetaSlot"; - + ? [list ::nsf::is object $entity] 1 + ? [list $entity info has type ::nx::doc::@attribute] 1 + ? [list $entity @see] "::nx::Attribute ::nx::MetaSlot"; + set entity [@method id ::Bar class foo] - ? [list $i eval [list [@class id ::Bar] @method]] $entity - ? [list $i eval [list ::nsf::is object $entity]] 1 - ? [list $i eval [list $entity info has type ::nx::doc::@method]] 1 - ? [list $i eval [list $entity as_text]] "This describes the foo method in the method body"; - - foreach p [$i eval [list $entity @parameter]] expected { + ? [list [@class id ::Bar] @method] $entity + ? [list ::nsf::is object $entity] 1 + ? [list $entity info has type ::nx::doc::@method] 1 + ? [list $entity as_text] "This describes the foo method in the method body"; + + foreach p [$entity @parameter] expected { "Provides a first value (refined)" "Provides a second value" } { - ? [list expr [list [$i eval [list $p as_text]] eq $expected]] 1; + ? [list expr [list [$p as_text] eq $expected]] 1; } - - + + set entity [@method id ::Bar class-object foo] - ? [list $i eval [list [@class id ::Bar] @class-object-method]] $entity - ? [list $i eval [list ::nsf::is object $entity]] 1 - ? [list $i eval [list $entity info has type ::nx::doc::@method]] 1 - ? [list $i eval [list $entity as_text]] "This describes the per-object foo method in the method body"; - - foreach p [$i eval [list $entity @parameter]] expected { + ? [list [@class id ::Bar] @class-object-method] $entity + ? [list ::nsf::is object $entity] 1 + ? [list $entity info has type ::nx::doc::@method] 1 + ? [list $entity as_text] "This describes the per-object foo method in the method body"; + + foreach p [$entity @parameter] expected { "Provides a first value" "Provides a second value (refined)" "Provides a third value (first time)" } { - ? [list expr [list [$i eval [list $p as_text]] eq $expected]] 1; + ? [list expr [list [$p as_text] eq $expected]] 1; } + + $prj destroy +} - - interp delete $i - - +Test case tag-notations-basics { + # # Some tests on structured/navigatable tag notations # - + # adding support for parsing levels # -- @class.object.object {::D o1 o2} @@ -539,15 +550,15 @@ ? [list ::nsf::isobject $entity] 1 ? [list $entity info has type ::nx::doc::@object] 1 ? [list $entity as_text] "We have a tag notation sensitive to the parsing level" - + set block { {@..object {o2 o3} We still look for balanced specs} } - + set entity [[@ @class ::D] @object o1] set cbp [CommentBlockParser process -parsing_level 2 -partof_entity $entity $block] ? [list $cbp status ? STYLEVIOLATION] 1 - + # This fails because we do not allow uninitialised/non-existing # entity objects (@object o) along the resolution path ... set block { @@ -556,15 +567,15 @@ set cbp [CommentBlockParser process $block] ? [list $cbp status ? INVALIDTAG] 1 -# ? [list $cbp message] "The tag 'object' is not supported for the entity type '@class'" - + # ? [list $cbp message] "The tag 'object' is not supported for the entity type '@class'" + set block { {@class.method.attribute attr1 We have an imbalanced specification (the names are underspecified!)} } set cbp [CommentBlockParser process $block] ? [list $cbp status ? STYLEVIOLATION] 1 ? [list $cbp message] "Imbalanced tag line spec: 'class method attribute' vs. 'attr1'" - + # For now, we do not verify and use a fixed scope of permissive tag # names. So, punctuation errors or typos are most probably reported # as imbalanced specs. In the mid-term run, this should rather @@ -575,14 +586,16 @@ set cbp [CommentBlockParser process $block] ? [list $cbp status ? STYLEVIOLATION] 1 ? [list $cbp message] "Imbalanced tag line spec: 'cla ss method parameter' vs. '::C foo p1'" - + set block { {@cla,ss.method.parameter {::C foo p1} We mistyped a tag fragment} } set cbp [CommentBlockParser process $block] ? [list $cbp status ? INVALIDTAG] 1 ? [list $cbp message] "The entity type '@cla,ss' is not available." +} +Test case tag-notations-extended { set script { # @class ::C # @@ -591,11 +604,11 @@ # @attribute attr1 Here we can only provide a description block for object parameters # @class.attribute {::C attr1} Here, we could also write '@class.class-attribute \{::C attr1\}', @attribute is a mere forwarder! In the context section, only one-liners are allowed! - + # @class.object.attribute {::C foo p1} A short description is ... # # .. is overruled by a long one ... - + # If addressing to a nested object, one strategy would be to use # @object and provide the object identifier (which reflects the # nesting, e.g. ::C::foo). However, we cannot distinguish between @@ -643,17 +656,17 @@ # @parameter p1 The most specific level! return [current method]-$p1-[current] }] - + # @.class-object-method.parameter {bar p1} # # This extended form allows to describe a method parameter with all # its structural features! set barHandle [:class-object method bar {p1} { return [current method]-$p1-[current] }] - + # @.object foo 'foo' needs to be defined before referencing any of its parts! - + # @.object.attribute {foo p1} # # The first element in the name list is resolved into a fully @@ -680,7 +693,7 @@ # @.class.class-object-attribute {Foo p2} Y Class create [current]::Foo { - + # @..attribute p1 # # @@ -710,7 +723,7 @@ # The desc of the ensemble object 'sub' # # @sub-method bar Only description available here ... - + # ISSUE: Should the helper object "sub" be documentable in its own # right? This would be feasible with the dotted notation from # within and outside the initcmd script block, e.g. "@object sub" or @@ -721,9 +734,9 @@ # way? Having an "@class-object-submethod" would not make much sense to # me?! :alias "sub bar" $barHandle - + # @.class-object-method sub A brief desc - + # @.class-object-method {"sub foo2"} # # could allow both (@sub-method is the attribute name, @method is a @@ -735,13 +748,14 @@ :class-object alias "sub foo2" $fooHandle } } - + # # 1) process the top-level comments (PARSING LEVEL 0) # - - doc analyze -noeval true $script - + + processor readin $script + + # --testing-- "@class ::C" set entity [@class id ::C] ? [list ::nsf::isobject $entity] 1 @@ -795,23 +809,30 @@ # 2) process the initcmd comments (PARSING LEVEL 1) # + ::nsf::configure keepinitcmd true eval $script - - doc analyze_initcmd @class ::C [::C eval {set :__initcmd}] - + ::nsf::configure keepinitcmd false + lassign [processor readin \ + -parsing_level 1 \ + -docstring \ + -tag @class \ + -name ::C \ + [::C eval {set :__initcmd}]] _ processed_entities + # a) existing, but modified ... - + set entity [@class id ::C] + ? $_ $entity ? [list ::nsf::isobject $entity] 1 ? [list $entity info has type ::nx::doc::@class] 1 ? [list $entity as_text] "This is the initcmd-level description of ::C which overwrites the global description (see above)" - + set entity [@attribute id $entity class attr1] ? [list ::nsf::isobject $entity] 1 ? [list $entity info has type ::nx::doc::@attribute] 1 ? [list $entity as_text] {This is equivalent to writing "@class-attribute attr1"} - - + + set entity [@object id ::C::foo] ? [list ::nsf::isobject $entity] 1 ? [list $entity info has type ::nx::doc::@object] 1 @@ -820,25 +841,25 @@ ? [list ::nsf::isobject $entity] 1 ? [list $entity info has type ::nx::doc::@attribute] 1 ? [list $entity as_text] "The first element in the name list is resolved into a fully qualified (absolute) entity, based on the object owning the initcmd!" - + # b) newly added ... - + # --testing-- @class-object-attribute attr2 set entity [@attribute id [@class id ::C] class-object attr2] ? [list ::nsf::isobject $entity] 1 ? [list $entity info has type ::nx::doc::@attribute] 1 ? [list $entity as_text] "Carries a short desc only"; - + # --testing-- @child-class Foo # TODO: provide a check against fully-qualified names in part specifications set entity [@class id ::C::Foo] ? [list ::nsf::isobject $entity] 1 ? [list $entity info has type ::nx::doc::@class] 1 ? [list $entity as_text] {By providing a fully-qualified identifier ("::Foo") you leave the context of the initcmd-owning object, i.e. you would NOT refer to a nested class object named "Foo" anymore!} - + set entity [@attribute id [@class id ::C] class p1] ? [list ::nsf::isobject $entity] 0; # should be 0 at this stage! - + # --testing -- @method foo set entity [@method id ::C class foo] ? [list ::nsf::isobject $entity] 1 @@ -858,19 +879,19 @@ set entity [@attribute id $cl class-object p2] ? [list ::nsf::isobject $entity] 1 ? [list $entity as_text] "Y" - + set entity [@method id ::C class sub] ? [list ::nsf::isobject $entity] 1 ? [list $entity as_text] "The desc of the ensemble object 'sub'" - + set entity [@method id ::C class sub::bar] ? [list ::nsf::isobject $entity] 1 ? [list $entity as_text] "Only description available here ..." - + set entity [@method id ::C class-object sub] ? [list ::nsf::isobject $entity] 1 ? [list $entity as_text] "A brief desc" - + set entity [@method id ::C class-object sub::foo2] ? [list ::nsf::isobject $entity] 1 ? [list $entity info has type ::nx::doc::@method] 1 @@ -881,37 +902,44 @@ set entity [@parameter id $entity "" p1] ? [list ::nsf::isobject $entity] 1 ? [list $entity as_text] "Some words on p1" - + # # 3a) process the attribute initcmds and method bodies (PARSING LEVEL 2)! # - - doc process=@class [@class id ::C] + set project [@project new -name "_%@"] + $project sandbox [Sandbox new] + processor process=@class $project [@class id ::C] + # methods ... - + set entity [@method id ::C class foo] ? [list ::nsf::isobject $entity] 1 ? [list $entity as_text] "Here goes some method-body-level description" set entity [@parameter id [@method id ::C class foo] "" p1] ? [list ::nsf::isobject $entity] 1 ? [list $entity as_text] "The most specific level!" - + # attributes ... - + # attr1 set entity [@attribute id [@class id ::C] class attr1] ? [list ::nsf::isobject $entity] 1 ? [list $entity info has type ::nx::doc::@attribute] 1 ? [list $entity as_text] {This description does not apply to the object parameter "attr1" owned by the ::C class, rather it is a description of the attribute slot object! How should we deal with this situation? Should this level overwrite the top-level and initcmd-level descriptions?} - + # # 3b) nested objects/ classes (PARSING LEVEL 2)! - # - - doc analyze_initcmd -parsing_level 2 @object ::C::foo [::C::foo eval {set :__initcmd}] - doc process=@object [@object id ::C::foo] - + # + processor readin \ + -docstring \ + -parsing_level 2 \ + -tag @object \ + -name ::C::foo \ + [::C::foo eval {set :__initcmd}] + + processor process=@object $project [@object id ::C::foo] + set entity [@object id ::C::foo] ? [list ::nsf::isobject $entity] 1 ? [list $entity info has type ::nx::doc::@object] 1 @@ -920,10 +948,15 @@ ? [list ::nsf::isobject $entity] 1 ? [list $entity info has type ::nx::doc::@attribute] 1 ? [list $entity as_text] {This is equivalent to stating "@class-object-attribute p1"} - - doc analyze_initcmd -parsing_level 2 @class ::C::Foo [::C::Foo eval {set :__initcmd}] - doc process=@class [@class id ::C::Foo] - + + processor readin \ + -docstring \ + -parsing_level 2 \ + -tag @class \ + -name ::C::Foo \ + [::C::Foo eval {set :__initcmd}] + processor process=@class $project [@class id ::C::Foo] + set cl [@class id ::C::Foo] ? [list ::nsf::isobject $cl] 1 set entity [@attribute id $cl class p1] @@ -932,108 +965,225 @@ set entity [@attribute id $cl class-object p2] ? [list ::nsf::isobject $entity] 1 ? [list $entity as_text] "" - - puts stderr ================================================= + # - # self documentation + # basic testing of "properties" (switch attributes) # - # if {[catch {set i [doc process nx::doc]} msg]} { - # puts stderr ERRORINFO=$::errorInfo - # if {[Exception behind? $msg]} { - # puts stderr [$msg info class]->[$msg message] - # } else { - # error $msg - # } - # } - # ? [list $i eval [list ::nsf::is object [@package id nx::doc]]] 1 - # puts stderr [$i eval [list [@package id nx::doc] text]] - # puts stderr [$i eval [list [@package id nx::doc] @require]] - # set path [file join /tmp nextdoc] - # if {[file exists $path]} { - # file delete -force $path - # } - # $i eval [list ::nx::doc::make doc \ - # -renderer ::nx::doc::TemplateData \ - # -outdir /tmp \ - # -project {name nextdoc url http://www.next-scripting.org/ version 0.1d}] - # interp delete $i - # - # core documentation - # - foreach path [list [file join [::nsf::tmpdir] NextScriptingFramework] \ - [file join [::nsf::tmpdir] NextScriptingLanguage]] { - if {[file exists $path]} { - file delete -force $path + ? [list $cl eval {set :@deprecated}] 0 + ? [list $cl eval {set :@stashed}] 0 + ? [list $cl eval {set :@c-implemented}] 0 + + ? [list $cl @deprecated] 1 + ? [list $cl @stashed] 1 + ? [list $cl @c-implemented] 1 + + ? [list $cl eval {set :@deprecated}] 1 + ? [list $cl eval {set :@stashed}] 1 + ? [list $cl eval {set :@c-implemented}] 1 + + set entity [@method id ::C class foo] + ? [list $entity eval {set :@syshook}] 0 + ? [list $entity @syshook] 1 + ? [list $entity eval {set :@syshook}] 1 + ? [list $entity @syshook 0] {wrong # args: should be "get obj prop"} + ? [list $entity eval {set :@syshook 0}] 0 + ? [list $entity @syshook] 1 + + +} + +Test case switch-parts { + + set script { + package req nx + namespace import ::nx::* + Class create Enil { + # The class Enil defines the behaviour for all Enil objects, + # however, it is deprecated and will be removed from the + # provided doc entities in the next iteration ... + # + # @author ssoberni@wu.ac.at + # @deprecated + + # @.attribute attr1 + # + # This attribute 1 will be invisibile in the generated doc + # + # @stashed + :attribute attr1 + + # @.method foo + # + # This describes the foo method which is called from within the + # nx-enabled Tcl engine + # + # @syshook + :method foo {a b} {;} + + :method baz {} { + # This method entity sets a couple of properties in series ... + # + # @property c-implemented syshook + } } } + + set prj [processor process -sandboxed -type eval $script] + set cl [@class id ::Enil] + + ? [list $cl eval {set :@deprecated}] 1 + ? [list $cl @deprecated] 1 + ? [list $cl eval {set :@c-implemented}] 0 + ? [list $cl eval {set :@stashed}] 0 + ? [list $cl @author] ssoberni@wu.ac.at + + set entity [@attribute id $cl class attr1] + ? [list $entity eval {set :@deprecated}] 0 + ? [list $entity eval {set :@stashed}] 1 + ? [list $entity @stashed] 1 + ? [list $entity eval {set :@c-implemented}] 0 + + set entity [@method id ::Enil class foo] + ? [list $entity eval {set :@deprecated}] 0 + ? [list $entity eval {set :@stashed}] 0 + ? [list $entity eval {set :@c-implemented}] 0 + ? [list $entity eval {set :@syshook}] 1 + ? [list $entity @syshook] 1 + + set entity [@method id ::Enil class baz] + ? [list $entity eval {set :@deprecated}] 0 + ? [list $entity eval {set :@stashed}] 0 + ? [list $entity eval {set :@c-implemented}] 1 + ? [list $entity @c-implemented] 1 + ? [list $entity eval {set :@syshook}] 1 + ? [list $entity @syshook] 1 + + +} - set i [interp create] - $i eval { - package req nx::doc - namespace import ::nx::* - namespace import ::nx::doc::* +puts stderr ================================================= +foreach path [list [file join [::nsf::tmpdir] NextScriptingFramework] \ + [file join [::nsf::tmpdir] NextScriptingLanguage]] { + if {[file exists $path]} { + file delete -force $path + } +} + +# TODO: Figure out where to place nsf.nxd for convenient location ... + +puts stderr >>>>>>>NextScriptingFramework<<<<<<<< +set project [::nx::doc::@project new \ + -name NextScriptingFramework \ + -url http://www.next-scripting.org/ \ + -version 1.0.0a \ + -@namespace "::nsf" \ + -sources { + package nsf + }] + +set project [processor process -sandboxed $project] + +::nx::doc::make doc \ + -renderer ::nx::doc::NxDocRenderer \ + -project $project \ + -outdir [::nsf::tmpdir] + + +puts stderr >>>>>>>NextScriptingLanguage<<<<<<<< + +set _ [time { + set project [::nx::doc::@project new \ + -name NextScriptingLanguage \ + -url http://www.next-scripting.org/ \ + -version 1.0.0a \ + -@namespace "::nx" \ + -sources { + package nx + }] + + # ISSUE: If calling '-namespace "::nx"' instead of '-@namespace + # "::nx"', we get an irritating failure. VERIFY! + processor process -sandboxed $project + ::nx::doc::make doc \ + -renderer ::nx::doc::NxDocRenderer \ + -project $project \ + -outdir [::nsf::tmpdir] +} 1] + +puts stderr ">>>>> gross timing for $project $_" +# exit + +# set i [interp create] +# $i eval { +# package req nx::doc +# namespace import ::nx::* +# namespace import ::nx::doc::* - # 1) NSF documentation project - set project [::nx::doc::@project new \ - -name NextScriptingFramework \ - -url http://www.next-scripting.org/ \ - -version 1.0.0a \ - -@namespace "::nsf"] +# # 1) NSF documentation project +# set project [::nx::doc::@project new \ +# -name NextScriptingFramework \ +# -url http://www.next-scripting.org/ \ +# -version 1.0.0a \ +# -@namespace "::nsf" \ +# -sources { +# {package nx} +# {scriptfile generic/nsf.tcl} +# {script {}} +# }] - doc process -noeval true generic/nsf.tcl +# # doc process -noeval true generic/nsf.tcl +# set project [doc process -sandboxed -type project $project] - ::nx::doc::make doc \ - -renderer ::nx::doc::NxDocRenderer \ - -project $project \ - -outdir [::nsf::tmpdir] +# ::nx::doc::make doc \ +# -renderer ::nx::doc::NxDocRenderer \ +# -project $project \ +# -outdir [::nsf::tmpdir] - #puts stderr NSF=[info commands ::nx::doc::entities::command::nsf::*] +# #puts stderr NSF=[info commands ::nx::doc::entities::command::nsf::*] - puts stderr TIMING=[time { - set project [::nx::doc::@project new \ - -name NextScriptingLanguage \ - -url http://www.next-scripting.org/ \ - -version 1.0.0a \ - -@namespace "::nx"] - # ISSUE: If calling '-namespace "::nx"' instead of '-@namespace - # "::nx"', we get an irritating failure. VERIFY! - doc process -noeval true library/nx/nx.tcl - ::nx::doc::make doc \ - -renderer ::nx::doc::NxDocRenderer \ - -project $project \ - -outdir [::nsf::tmpdir] - } 1] - } +# puts stderr TIMING=[time { +# set project [::nx::doc::@project new \ +# -name NextScriptingLanguage \ +# -url http://www.next-scripting.org/ \ +# -version 1.0.0a \ +# -@namespace "::nx"] +# # ISSUE: If calling '-namespace "::nx"' instead of '-@namespace +# # "::nx"', we get an irritating failure. VERIFY! +# doc process -noeval true library/nx/nx.tcl +# ::nx::doc::make doc \ +# -renderer ::nx::doc::NxDocRenderer \ +# -project $project \ +# -outdir [::nsf::tmpdir] +# } 1] +# } - interp delete $i +# interp delete $i - set _ { - # 2) XOTcl2 documentation project - doc process -noeval true library/xotcl/xotcl.tcl - ::nx::doc::make doc \ - -renderer ::nx::doc::NxDocTemplateData \ - -outdir [::nsf::tmpdir] \ - -project {name XOTcl2 url http://www.xotcl.org/ version 2.0.0a} +# set _ { +# # 2) XOTcl2 documentation project +# doc process -noeval true library/xotcl/xotcl.tcl +# ::nx::doc::make doc \ +# -renderer ::nx::doc::NxDocTemplateData \ +# -outdir [::nsf::tmpdir] \ +# -project {name XOTcl2 url http://www.xotcl.org/ version 2.0.0a} - # 3) NSL documentation project - doc process -noeval true library/nx/nx.tcl - ::nx::doc::make doc \ - -renderer ::nx::doc::NxDocTemplateData \ - -outdir [::nsf::tmpdir] \ - -project {name NextScriptingLanguage url http://www.next-scripting.org/ version 1.0.0a} +# # 3) NSL documentation project +# doc process -noeval true library/nx/nx.tcl +# ::nx::doc::make doc \ +# -renderer ::nx::doc::NxDocTemplateData \ +# -outdir [::nsf::tmpdir] \ +# -project {name NextScriptingLanguage url http://www.next-scripting.org/ version 1.0.0a} - # 4) Next Scripting Libraries - # doc process -noeval true ... - # ::nx::doc::make doc \ - # -renderer ::nx::doc::NxDocTemplateData \ - # -outdir [::nsf::tmpdir] \ - # -project {name NextScriptingLibraries url http://www.next-scripting.org/ version 1.0.0a} - } +# # 4) Next Scripting Libraries +# # doc process -noeval true ... +# # ::nx::doc::make doc \ +# # -renderer ::nx::doc::NxDocTemplateData \ +# # -outdir [::nsf::tmpdir] \ +# # -project {name NextScriptingLibraries url http://www.next-scripting.org/ version 1.0.0a} +# } -} - # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # @@ -1136,9 +1286,3 @@ # need namespace delimiters!) } - -# if {$log} { -# ::nx::doc::CommentState mixin delete ::nx::doc::CommentState::Log -# ::nx::doc::CommentLine mixin delete ::nx::doc::CommentLine::Log -# ::nx::doc::CommentSection mixin delete ::nx::doc::CommentSection::Log -# }