Index: library/lib/doc-assets/command.html.tmpl =================================================================== diff -u -N -r9e98d057e87eb5d9bf8cd3a25dc679ed02cd6399 -rb067e586fadae95916358904fd8392d073c7c87c --- library/lib/doc-assets/command.html.tmpl (.../command.html.tmpl) (revision 9e98d057e87eb5d9bf8cd3a25dc679ed02cd6399) +++ library/lib/doc-assets/command.html.tmpl (.../command.html.tmpl) (revision b067e586fadae95916358904fd8392d073c7c87c) @@ -1,107 +1,117 @@

- Command ${:name} + Command [:print_name -status]

- -
[:as_text]
- -
- -[:?var :@command { -
-
-

Subcommands

-
-
- - [:for sub [:!get -sortedby name @command] { - - [$sub name] - - }] - -
-
-
-
- [:for sub [:!get -sortedby name @command] { -
-

[$sub name] -

-
- [:? {[$sub eval {info exists :@return}] && [[$sub @return] spec] ne ""} {<[[$sub @return] spec]>} ] - ${:name} - [$sub name] - [$sub pinfo get -default "" bundle parametersyntax] - -
- [$sub as_text] - [:?objvar $sub @param { -
-
Subcommand parameters:
- [:for param $@param { -
- [$param name] - [:? {[$param eval {info exists :spec}] && [$param spec] ne ""} {<[$param spec]>}] +[join [:pinfo get -default "" validation]
]
+
+ [:? {[info exists :@return] && [${:@return} spec] ne ""} {<[${:@return} spec]>} ] + ${:name} + [:pinfo get -default "" bundle parametersyntax] + + [:?var :@command { +
+
+
+

Subcommands

+
+
+ + [:for sub [:!get -sortedby name @command] { + + [$sub name] + + }] + +
+
+
+
+ [:for sub [:!get -sortedby name @command] { +
+

[$sub print_name] +

+
+ [:? {[$sub eval {info exists :@return}] && [[$sub @return] spec] ne ""} {<[[$sub @return] spec]>} ] + ${:name} [$sub name] + [$sub pinfo get -default "" bundle parametersyntax] - [$param as_text] -
- }] -
+
+ [$sub as_text] + [:?objvar $sub @parameter { +
+
Parameters:
+ [:for param [$sub !get @parameter] { +
+ [$param name] + [:? {[$param eval {info exists :spec}] && [$param spec] ne ""} {<[$param spec]>}] + + [$param as_text] + [join [$param pinfo get -default "" validation]
]
+
+ }] +
+ }] + [:?objvar $sub @return { + [:!let subreturn [$sub @return]] +
+
Returns: + +
+
[$subreturn as_text][join [$subreturn pinfo get -default "" validation]
]
+
+ }] +
+
+
+
}] - [:?objvar $sub @return { -
-
Returns: - -
-
[[$sub @return] as_text]
-
- }] -
-
-
+
- }]
+ + } - { +
+
+ [:?var :@parameter { +
+
Parameters:
+ [:for param [:!get @parameter] { +
+ [$param name] + [:? {[$param eval {info exists :spec}] && [$param spec] ne ""} {<[$param spec]>}] + + [$param statusmark] + [$param as_text] + [join [$param pinfo get -default "" validation]
]
+
+ }] +
+ }] + + [:?var :@return { +
+
Returns: + +
+
[${:@return} as_text]
+
+ }]
+
+ }] -} - { -[:?var :@param { -
-
Parameters:
- [:for param [:!get @param] { -
- [$param name] - <[:? {[$param eval {info exists :spec}]} {[$param spec]}]> - - [$param as_text] -
- }] -
-}] -[:?var :@return { -
-
Returns: - -
-
[${:@return} as_text]
-
-}] -}] - - - - + Index: library/lib/doc-assets/entity.html.tmpl =================================================================== diff -u -N -r9e98d057e87eb5d9bf8cd3a25dc679ed02cd6399 -rb067e586fadae95916358904fd8392d073c7c87c --- library/lib/doc-assets/entity.html.tmpl (.../entity.html.tmpl) (revision 9e98d057e87eb5d9bf8cd3a25dc679ed02cd6399) +++ library/lib/doc-assets/entity.html.tmpl (.../entity.html.tmpl) (revision b067e586fadae95916358904fd8392d073c7c87c) @@ -38,7 +38,7 @@ - [:!let self_owned_parts [[:origin] owned_parts]] + [:!let self_owned_parts [[:origin] owned_parts -class ::nx::doc::StructuredEntity]] [:!let owned_parts [dict merge $project_entities $self_owned_parts]]
Index: library/lib/doc-assets/glossary.html.tmpl =================================================================== diff -u -N -r26ce746b45449fbff64f88c6d9e9050a63b89449 -rb067e586fadae95916358904fd8392d073c7c87c --- library/lib/doc-assets/glossary.html.tmpl (.../glossary.html.tmpl) (revision 26ce746b45449fbff64f88c6d9e9050a63b89449) +++ library/lib/doc-assets/glossary.html.tmpl (.../glossary.html.tmpl) (revision b067e586fadae95916358904fd8392d073c7c87c) @@ -1,5 +1,6 @@ -[:?var :@glossary { -[:!let entries [sorted ${:@glossary} name]] +[:!let gls [:@glossary]] +[:? {$gls ne ""} { +[:!let entries [sorted $gls name]]
[:for entry $entries { [:!let ddesc [$entry as_text]] @@ -19,7 +20,8 @@ $dtext
$ddesc [:?objvar $entry refs { - [:!let refs [sort_by_value [$entry eval {set :refs}]]] + [:? {[$entry eval [concat dict exists \${:refs} [current]]]} { + [:!let refs [sort_by_value [$entry eval [concat dict get \${:refs} [current]]]]]
@@ -37,6 +39,7 @@
}] + }]
}] }] Index: library/lib/doc-assets/package.html.tmpl =================================================================== diff -u -N -r170cefa7618f2b44f91102711607fc6fa7d12c4f -rb067e586fadae95916358904fd8392d073c7c87c --- library/lib/doc-assets/package.html.tmpl (.../package.html.tmpl) (revision 170cefa7618f2b44f91102711607fc6fa7d12c4f) +++ library/lib/doc-assets/package.html.tmpl (.../package.html.tmpl) (revision b067e586fadae95916358904fd8392d073c7c87c) @@ -25,7 +25,7 @@
    [:!let idx 0] - [:for class ${:@class} { + [:for class [:!get -sortedby name @class] {
  • [${class} print_name -status]
  • [incr idx; return] } ] @@ -41,7 +41,7 @@
      [:!let idx 0] - [:for obj ${:@object} { + [:for obj [:!get -sortedby name @object] {
    • [${obj} print_name -status]
    • [incr idx; return] @@ -59,7 +59,7 @@
        [:!let idx 0] - [:for cmd ${:@command} { + [:for cmd [:!get -sortedby name @command] {
      • [$cmd print_name -status]
      • [incr idx; return] Index: library/lib/doc-tools.tcl =================================================================== diff -u -N -r4e92917e1690fdcfa4566d89489f7d6c58e57628 -rb067e586fadae95916358904fd8392d073c7c87c --- library/lib/doc-tools.tcl (.../doc-tools.tcl) (revision 4e92917e1690fdcfa4566d89489f7d6c58e57628) +++ library/lib/doc-tools.tcl (.../doc-tools.tcl) (revision b067e586fadae95916358904fd8392d073c7c87c) @@ -237,7 +237,6 @@ set cmd $target } } - if {$cmd eq "" || ![::nsf::isobject $cmd] || ![$cmd info has type Tag]} { return [list 1 "The entity type '@$axis' is not available."] } @@ -535,7 +534,15 @@ } :attribute pdata - :public method validate {} {;} + :public method validate {} { + if {[info exists :pdata] && \ + [:pinfo get -default complete status] ne "missing"} { + if {[[:origin] as_list] eq ""} { + :pinfo propagate status mismatch + :pinfo lappend validation "Provide a short, summarising description!" + } + } + } :public method "pinfo get" {{-default ?} args} { if {![info exists :pdata] || ![dict exists ${:pdata} {*}$args]} { return $default; @@ -548,10 +555,16 @@ dict exists ${:pdata} {*}$args } + :public method "pinfo lappend" args { + if {![info exists :pdata]} return; + dict lappend :pdata {*}$args + } + :public method "pinfo set" args { if {![info exists :pdata]} return; dict set :pdata {*}$args } + :public method "pinfo propagate" args { :pinfo set {*}$args @@ -623,19 +636,18 @@ } else { set pathspec [split $pathspec .] } - #puts stderr "PATHSPEC $pathspec PATHNAMES $pathnames" lassign [::nx::doc::Tag normalise $pathspec $pathnames] err res if {$err} { error "Invalid @use values provided: $res" } lassign $res pathspec pathnames - + #puts stderr "PATHSPEC $pathspec PATHNAMES $pathnames" lassign [::nx::doc::Tag find $pathspec $pathnames] err res if {$err} { error "Generating an entity handle failed: $res" } - #puts stderr "next $domain $prop $res" + # puts stderr "NEXT $domain $prop $res" next [list $domain $prop $res] } @@ -685,9 +697,7 @@ Class create StructuredEntity -superclass Entity { :public method part_attributes {} { - #set slots [:info lookup slots] - set slots [::nsf::dispatch [::nsf::self] ::nsf::methods::object::info::lookupslots -type ::nx::Slot] - + set slots [:info lookup slots] set attrs [list] foreach s $slots { if {![$s info has type ::nx::doc::PartAttribute] || ![$s eval {info exists :part_class}]} continue; @@ -696,9 +706,18 @@ return $attrs } - :public method owned_parts {} { + :public method owned_parts { + -class:object + } { set r [dict create] foreach {s cls} [:part_attributes] { + # + # Note: For the time being, we skip over the bottom-most level of + # entities, i.e. those which are not structured entities + # themselves. + # + if {[info exists class] && \ + [[$s part_class] info superclass -closure $class] eq ""} continue; set accessor [$s name] if {[info exists :$accessor]} { dict set r $s [sorted [:$accessor] name] @@ -708,7 +727,7 @@ } :public method validate {} { - + next dict for {s entities} [:owned_parts] { foreach e $entities { # TODO: for now, it is sufficient to escape @use chains @@ -850,8 +869,19 @@ :attribute creationdate :attribute {version ""} + :attribute depends:0..*,object,type=[current] + :attribute @glossary -class ::nx::doc::PartAttribute { set :part_class ::nx::doc::@glossary + :public method get {domain prop} { + set l [next] + if {[$domain eval {info exists :depends}]} { + foreach d [$domain depends] { + lappend l {*}[$d $prop] + } + } + return [lsort -unique $l] + } } :attribute @package -class ::nx::doc::PartAttribute { @@ -925,10 +955,50 @@ # TODO: [${:part_class}] resolves to the attribute slot # object, not the global @command object. is this intended, in # line with the intended semantics? - return [${:part_class} [current method] -partof_name [$domain name] -scope ${:scope} $value] + return [${:part_class} [current method] \ + -partof_name [$domain name] \ + -scope ${:scope} -- $value] } set :part_class ::nx::doc::@command } + + :public method validate {} { + if {[info exists :pdata] && \ + [:pinfo get -default complete status] ne "missing"} { + + if {![info exists :@command]} { + set params [list] + set param_names [list] + if {[info exists :@parameter]} { + foreach p [:@parameter] { + set value [$p name] + lappend param_names $value + if {[$p eval {info exists :default}] || $value eq "args" } { + set value "?$value?" + } + lappend params $value + } + } + + set ps [:pinfo get -default "" bundle parameter] + dict for {actualparam paraminfo} $ps { + if {$actualparam ni $param_names} { + set p [:@parameter $actualparam] + $p pdata [lappend paraminfo status missing] + } + } + } + + if {![:pinfo exists bundle parametersyntax]} { + :pinfo set bundle parametersyntax $params + } + + # Note: [next] will cause the missing parameter created to + # be validated and will have the appropriate status + # propagated upstream! + next + } + } } QualifierTag create @object \ @@ -1269,14 +1339,23 @@ :public method validate {} { + # + # TODO: For now, we escape from @param validaton on command + # parameters. There is no equivalent to [info parameter] + # available, so we would need to cook a substitute based on + # the parametersyntax. Review later ... + # + if {${:name} eq "__out__" && [${:partof} info has type ::nx::doc::@command]} return; if {[info exists :pdata] && [:pinfo get -default complete status] ne "missing"} { + # valid for both object and method parameters set pspec [:pinfo get -default "" bundle spec] if {[info exists :spec] && \ ${:spec} ne $pspec} { :pinfo propagate status mismatch - :pinfo set validation "Specification mismatch. Expected: '${:spec}' Got: '$pspec'." + :pinfo lappend validation "Specification mismatch. Expected: '${:spec}' Got: '$pspec'." } + next } else { ${:partof} pinfo propagate status mismatch } @@ -1670,7 +1749,7 @@ # TODO: Should I wrap up delegating calls to the originator # entity behind a unified interface (a gatekeeper?) # - return [[:origin] owned_parts] + return [[:origin] owned_parts -class ::nx::doc::StructuredEntity] } :method listing {{-inline true} script} { @@ -1835,7 +1914,7 @@ # First occurrance of an acronym entry! # if {!$acronym(short) && ($acronym(long) || ![info exists :refs] || \ - ![dict exists ${:refs} $source])} { + ![dict exists ${:refs} [:current_project] $source])} { set print_name "$print_name (${:@acronym})" set res "$print_name" } else { @@ -1852,8 +1931,9 @@ if {![info exists :refs]} { set :refs [dict create] } - dict incr :refs $source - + dict update :refs [:current_project] prj { + dict incr prj $source + } return $res } }; # NxDocRenderer::@glossary @@ -1893,9 +1973,6 @@ dict set hash access ${:@modifier} return $hash } - :public method render_start {} { - #:validate - } }; # NxDocRenderer::@method }; # NxDocTemplating @@ -2146,7 +2223,22 @@ return $is } + ::interp invokehidden "" proc ::nx::doc::paraminfo { + value {default ""} + } { + set colon [string first : $value] + set spec "" + if {$colon == -1} { + set name $value + } else { + set spec [string range $value [expr {$colon+1}] end] + set name [string range $value 0 [expr {$colon -1}]] + } + return [list $name [list $spec $default]] + } + + proc __trace_pkg {} { #puts stderr ">>> INIT [package names]" @@ -2229,11 +2321,36 @@ lassign $delta_pkg pkg_name filepath set filepath [file normalize $filepath] + + # TODO: Temporary hack to reflect that we provide for a + # helper objsys to retrieve command parameter specs and + # parametersyntax prints. + if {[info commands ::nsf::createobjectsystem] ne "" && \ + [::nsf::configure objectsystem] eq ""} { + set rootclass ::nx::doc::_%&obj + set rootmclass ::nx::doc::_%&cls + ::nsf::createobjectsystem ::nx::doc::_%&obj ::nx::doc::_%&cls + } else { + lassign {*}[::nsf::configure objectsystem] rootclass rootmclass + } + foreach {cmd isexported} $delta_commands { + set bundle [dict create] + if {![catch {set syntax [::nsf::dispatch $rootclass ::nsf::methods::object::info::method parametersyntax $cmd]} _]} { + dict set bundle parametersyntax $syntax + } + + if {![catch {set pa [::nsf::dispatch $rootclass ::nsf::methods::object::info::method parameter $cmd]} _]} { + foreach pspec $pa { + dict set bundle parameter {*}[::nx::doc::paraminfo {*}$pspec] + } + } + ::nx::doc::__at_register_command $cmd \ ->cmdtype @command \ ->source $filepath \ - ->nsexported $isexported + ->nsexported $isexported \ + ->bundle $bundle } } @@ -2276,10 +2393,18 @@ # 1) provide for tracing NSF objects if {[info commands ::nsf::configure] ne "" && \ [::nsf::configure objectsystem] ne ""} { - ::nsf::configure keepinitcmd true; - + set objsys [lindex [::nsf::configure objectsystem] 0] + set m [lassign $objsys rootclass rootmclass] + # + # TODO: Temporary hack to reflect that we provide for a + # helper objsys to retrieve command parameter specs and + # parametersyntax prints. + # + if {$rootclass ne "::nx::doc::_%&obj"} { + + ::nsf::configure keepinitcmd true; - array set sysmeths [concat {*}[lassign {*}[::nsf::configure objectsystem] rootclass rootmclass]] + array set sysmeths [concat {*}$m] set ::nx::doc::rootns [namespace qualifier $rootmclass] $rootmclass $sysmeths(-class.create) ${::nx::doc::rootns}::__Tracer ::nsf::method ${::nx::doc::rootns}::__Tracer \ @@ -2304,12 +2429,8 @@ {*}[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 ${::nx::doc::rootns}::__Tracer + ::nsf::mixin $rootmclass ${::nx::doc::rootns}::__Tracer + # ::nsf::relation $rootmclass class-mixin ${::nx::doc::rootns}::__Tracer if {[info commands "::nx::Object"] ne ""} { $rootmclass $sysmeths(-class.create) ${::nx::doc::rootns}::__ObjTracer @@ -2364,9 +2485,10 @@ return [array get ""] } - ::nsf::relation $rootclass class-mixin ${::nx::doc::rootns}::__ObjTracer + ::nsf::mixin $rootclass ${::nx::doc::rootns}::__ObjTracer + #::nsf::relation $rootclass class-mixin ${::nx::doc::rootns}::__ObjTracer } - + } ::interp invokehidden "" proc ::nx::doc::handleinfo {handle} { set definition [::nsf::dispatch ${::nx::doc::rootns}::__Tracer ::nsf::methods::object::info::method definition $handle] if {$definition ne ""} { @@ -2400,22 +2522,8 @@ } return [list $obj $scope $name] } - - ::interp invokehidden "" proc ::nx::doc::paraminfo { - value {default ""} - } { - set colon [string first : $value] - set spec "" - if {$colon == -1} { - set name $value - } else { - set spec [string range $value [expr {$colon+1}] end] - set name [string range $value 0 [expr {$colon -1}]] - } - return [list $name [list $spec $default]] - } + - rename ::nsf::method ::nsf::_%&method ::interp invokehidden "" proc ::nsf::method { object @@ -2649,7 +2757,8 @@ } { if {[info exists nspatterns]} { set opts [join $nspatterns |] - set nspatterns "^($opts)::\[^\:\]+\$" + # set nspatterns "^($opts)\[^\:\]*\$" + set nspatterns "^($opts)\$" } dict filter ${:registered_commands} script {cmd props} { dict with props { @@ -2818,7 +2927,14 @@ puts stderr "[current]->[uplevel 1 [list ::nsf::current method]]: $msg" } - :public class-object method process {-sandboxed:switch {-type project} thing} { + :public class-object method process { + -sandboxed:switch + -validate:switch + {-type project} + -include + -exclude + thing + } { if {$type ne "project"} { # TODO: Fix the naming requirements ... set project [@project new -name "_%@"] @@ -2827,15 +2943,110 @@ set project $thing } - $project sandbox [Sandbox new -interp [expr {$sandboxed?[interp create]:""}]] + set box [$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" + + set provided_entities [list] dict for {type instances} $sources { - :[current method]=$type $project $instances + lappend provided_entities {*}[:[current method]=$type $project $instances] } + + if {$validate} { + set present_entities [::nx::doc::filtered $provided_entities {[[:origin] eval {info exists :pdata}]}] + # TODO: the nspatterns should be consumed from the source + # specification and should not be hardcoded here ... review + # later ... + #puts stderr "NSF: [join [dict keys [$box get_registered_commands -exported -types @command]] \n]" + # ISSUE: -exported turns out to be a weak filter criterion, it + # excludes slot objects from being processed! + set nsfilters [list] + if {[info exists include] && $include ne ""} { + set nsfilters [list $include] + } + if {[info exists exclude] && $exclude ne ""} { + set nsfilters [list -not $exclude] + } + + set generated_commands [dict merge \ + [$box get_registered_commands -types { + @object + @class + @command + } {*}$nsfilters] \ + [$box get_registered_commands -types { + @method + } {*}$nsfilters]] + set map [dict create] + foreach pe $present_entities { + if {[$pe pinfo exists bundle handle]} { + set fqn [$pe pinfo get bundle handle] + } else { + set fqn [$pe get_fqn_command_name] + } + dict unset generated_commands $fqn + dict set map $fqn $pe + } + + # 2. generated entities (doc[no]->program[yes]) + # => all registered_commands without doc entity + #puts stderr "== TO GENERATE == [join [dict keys $generated_commands] \n]" + dict for {cmd info} $generated_commands { + dict with info { + # + # TODO: for now, we assume objects beyond this point + # ... relax later! + # + if {$cmdtype ni [list @command @object @class @method]} continue; + if {$cmdtype eq "@object" && [string match *::slot::* $cmd]} { + if {[dict exists $info bundle objtype] && [dict get $info bundle objtype] eq "ensemble"} continue; + set name [namespace tail $cmd] + set scope "" + set obj [namespace qualifiers [namespace qualifiers $cmd]] + if {![dict exists $map $obj]} continue; + set partof_entity [dict get $map $obj] + set entity [$partof_entity @[join [list {*}${scope} attribute] -] $name] + } elseif {$cmdtype eq "@method"} { + lassign [dict get $bundle handleinfo] obj scope name + # ! we assume the partof entity is present or has been generated + if {![dict exists $map $obj]} continue; + set partof_entity [dict get $map $obj] + if {![$partof_entity info has type ::nx::doc::@object]} continue; + set owning_entity $partof_entity + foreach subm $name { + set en [$partof_entity @[join [list {*}${scope} method] -] id $subm] + if {$en ni $provided_entities} { + set partof_entity [$partof_entity @[join [list {*}${scope} method] -] $subm] + } else { + set partof_entity $en + } + } + set entity $partof_entity + if {[dict exists $info bundle parameter]} { + dict for {pname paraminfo} [dict get $info bundle parameter] { + lassign $paraminfo spec default + set paramid [@parameter id $entity "" $pname] + set ppdata [list bundle [list spec $spec default $default]] + if {$paramid ni $provided_entities} { + set paramid [$entity @parameter $pname] + lappend ppdata status missing + } + $paramid pdata $ppdata + } + } + } else { + set entity [@ $cmdtype $cmd] + } + + #puts stderr "SETTING missing PDATA $entity $cmd" + $entity pdata [lappend info status missing] + dict set map [$entity get_fqn_command_name] $entity + } + } + } return $project } @@ -2880,105 +3091,13 @@ foreach script $scripts { lappend provided_entities {*}[:readin $script] } - + return $provided_entities # output # 1. absent entities (doc[yes]->program[no]) # => all doc entities without pdata # ::nx::doc::entities::method::nx::Class::class::info # ::nsf::classes::nx::Class::info #puts stderr "--- $provided_entities" - set present_entities [::nx::doc::filtered $provided_entities {[[:origin] eval {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]] - # ISSUE: -exported turns out to be a weak filter criterion, it - # excludes slot objects from being processed - set generated_commands [dict merge [$box get_registered_commands -types {@object @class @command}] [$box get_registered_commands -types @method]] - set map [dict create] - foreach pe $present_entities { - if {[$pe pinfo exists bundle handle]} { - set fqn [$pe pinfo get bundle handle] - } else { - set fqn [$pe get_fqn_command_name] - } - dict unset generated_commands $fqn - dict set map $fqn $pe - } - - # 2. generated entities (doc[no]->program[yes]) - # => all registered_commands without doc entity - #puts stderr "== TO GENERATE == [join [dict keys $generated_commands] \n]" - dict for {cmd info} $generated_commands { - dict with info { - # - # TODO: for now, we assume objects beyond this point - # ... relax later! - # - if {$cmdtype ni [list @command @object @class @method]} continue; - if {$cmdtype eq "@object" && [string match *::slot::* $cmd]} { - if {[dict exists $info bundle objtype] && [dict get $info bundle objtype] eq "ensemble"} continue; - set name [namespace tail $cmd] - set scope "" - set obj [namespace qualifiers [namespace qualifiers $cmd]] - if {![dict exists $map $obj]} continue; - set partof_entity [dict get $map $obj] - set entity [$partof_entity @[join [list {*}${scope} attribute] -] $name] - } elseif {$cmdtype eq "@method"} { - lassign [dict get $bundle handleinfo] obj scope name - # ! we assume the partof entity is present or has been generated - if {![dict exists $map $obj]} continue; - set partof_entity [dict get $map $obj] - if {![$partof_entity info has type ::nx::doc::@object]} continue; - set owning_entity $partof_entity - foreach subm $name { - # - # TODO: [info info] causes an issue because in terms of - # doc entities, it overwrites the info alias for the doc - # entity object ... verify: - # ::nx::doc::entities::method::nx::Object::class::info::info: unable to dispatch method '::nx::doc::entities::method::nx::Object::class::info' - # ::nx::doc::entities::method::nx::Object::class::info->info - # invoked from within - # ":info class" - # (procedure "make_link" line 4) - # ::nx::doc::entities::method::nx::Object::class::info ::nx::doc::NxDocRenderer::Entity->make_link - # invoked from within - # "$src make_link [current]" - - # - if {[$partof_entity name] eq "info" && $subm eq "info"} break; - set en [$partof_entity @[join [list {*}${scope} method] -] id $subm] - if {$en ni $provided_entities} { - set partof_entity [$partof_entity @[join [list {*}${scope} method] -] $subm] - } else { - set partof_entity $en - } - - } - # ISSUE: the following line is part of the [info info] fix, review later ... - if {$partof_entity in $provided_entities} continue; - set entity $partof_entity - if {[dict exists $info bundle parameter]} { - dict for {pname paraminfo} [dict get $info bundle parameter] { - lassign $paraminfo spec default - set paramid [@parameter id $entity "" $pname] - set ppdata [list bundle [list spec $spec default $default]] - if {$paramid ni $provided_entities} { - set paramid [$entity @parameter $pname] - lappend ppdata status missing - } - $paramid pdata $ppdata - } - } - } else { - set entity [@ $cmdtype $cmd] - } - - #puts stderr "SETTING missing PDATA $entity $cmd" - $entity pdata [lappend info status missing] - dict set map [$entity get_fqn_command_name] $entity - } - } } :protected class-object method process=source {project filepath} {;} Index: library/nx/nx.nxd =================================================================== diff -u -N -re4a5c3979effc10d1e807063956d51c72994db6e -rb067e586fadae95916358904fd8392d073c7c87c --- library/nx/nx.nxd (.../nx.nxd) (revision e4a5c3979effc10d1e807063956d51c72994db6e) +++ library/nx/nx.nxd (.../nx.nxd) (revision b067e586fadae95916358904fd8392d073c7c87c) @@ -913,14 +913,6 @@ # @pretty_name Slot # @pretty_plural Slots -# @glossary class -# -# A class represents a family of object sharing a minimal common -# structure and behaviour. -# -# @pretty_name Class -# @pretty_plural Classes - # @glossary method_handle # # A method handle represents Index: nsf.nxd =================================================================== diff -u -N -r170cefa7618f2b44f91102711607fc6fa7d12c4f -rb067e586fadae95916358904fd8392d073c7c87c --- nsf.nxd (.../nsf.nxd) (revision 170cefa7618f2b44f91102711607fc6fa7d12c4f) +++ nsf.nxd (.../nsf.nxd) (revision b067e586fadae95916358904fd8392d073c7c87c) @@ -8,18 +8,104 @@ # @version 1.0.0a # @namespace ::nsf +# @glossary alias +# +# An alias is a placeholder for a command, its target, which is made +# available as a proper method of the alias-owning object. +# +# @pretty_name Alias +# @pretty_plural Aliases -# @command assertion +# @glossary class # -# @parameter object:object -# @parameter assertionsubcmd:required -# @parameter arg +# A class represents a family of object sharing a minimal common +# structure and behaviour. +# +# @pretty_name Class +# @pretty_plural Classes -# @command existsvar +# @glossary method_handle # -# @parameter object:object -# @parameter var +# A method handle is a fully qualified, directly executable reference +# to scripted procs and methods, as well as C-implemented commands and +# methods. An handle is a unique identifier for a given '''interp'''. +# +# @pretty_name Method handle +# @pretty_plural Method handles +# @glossary cframe +# +# NSF provides adds a set of callframe types, e.g., to carry +# object-specific callstack information, to realise variable- and +# command-resolution schemes etc. The callframe types are realised by +# piggybacking standard Tcl callframe structures. The following +# callframe types can be found: ... +# +# @pretty_name Callframe +# @pretty_plural Callframes + + + +# @command alias +# +# A factory command which creates an <<@gls alias>> method for an +# object or a class. The aliased (or target) command so appears as a +# member of the method record of the object or the instances of the +# alias-defining class. Beware, method <<@glspl alias>> and this factory +# command are not related to Tcl's interpreter aliases and their +# '''interp alias''' helper. +# +# @parameter object The target object to own the alias method +# @parameter -per-object If the target object is a <<@gls +# class>>, one can specify the owner +# scope (i.e., per-object or per-class) +# of the alias method +# @parameter methodName:optional The name of the alias method. Under +# this name, the alias method is listed +# in the method signature interface. The +# alias method name and the target name +# so can differ from each other. +# @parameter -frame Denotes the type of <<@gls cframe>> to +# be stacked upon invoking the alias +# method. Permissible options are: +# '''method''', '''object''', +# '''default''' +# @parameter cmdName The alias source as a <<@gls method_handle>> +# @return The <<@gls method_handle>> representing the +# alias method just created + + +# @command assertion +# +# A helper command to (a) define assertion expressions and (b) to +# selectively activate checking of certain assertion types on a given +# object. +# +# @parameter object Denotes an object or class as the +# subject of assertion checking. It also +# stores the assertion expressions to be +# evaluated. +# @parameter assertionsubcmd The subcommand '''check''' allows you to +# specify the category of assertions to +# be checked, while '''object-invar''' and +# '''class-invar''' actually set +# assertion expressions in terms of +# object or class invariants. +# @parameter arg:optional Either: (a) subcommand '''check''': A list +# of assertion checks to activate +# (permissible options: '''all''', +# '''pre''', '''post''', +# '''object-invar''', +# '''class-invar'''); if omitted, the +# currently active assertion type is +# returned. +# (b) subcommands '''object-invar''' and +# '''class-invar''': A list of assertion +# expressions (in the sense of Tcl +# expression statements). A list of +# assertion expressions is evaluated +# under a logical AND. + # @command methodproperty # # @parameter object:object @@ -37,34 +123,134 @@ # @command createobjectsystem # -# @parameter rootClass -# @parameter rootMetaClass -# @parameter systemMethods:optional +# A factory command for specifying an NSF object system. By providing +# the object names of a root class and a root-meta class, you obtain +# two barebone objects as a starting point to define the basic class +# and object interfaces for your object system. In addition, you may +# map system hooks required by the NSF runtime to methods specific to +# your object system. For instance, the Nx object system is defined as follows: +# ''' +# ::nsf::createobjectsystem ::nx::Object ::nx::Class { +# -class.alloc alloc +# -class.create create +# -class.dealloc dealloc +# -class.recreate recreate +# -class.requireobject __unknown +# -object.configure configure +# -object.defaultmethod defaultmethod +# -object.destroy destroy +# -object.init init +# -object.move move +# -object.objectparameter objectparameter +# -object.residualargs residualargs +# -object.unknown unknown +# } +# ''' +# +# @parameter rootClass The name of the class at the root of +# your class hierarchy. +# @parameter rootMetaClass The name of the meta-class at the root +# of your meta-class hierarchy. +# @parameter systemMethods:optional A map which provides bindings +# between system hooks (e.g., +# '''-class.create''') and +# methods defined on the root +# class and the root meta-class. +# @command deprecated +# +# A helper command which prints a notice that a given command is +# deprecated, optionally pointing to its successor, if any. +# +# @parameter what Identifies the command type (proc, method, ...) +# @parameter oldCmd Gives the name of the deprecated command +# @parameter newCmd:optional Points to the successor command + + # @command dispatch # -# @parameter object:object -# @parameter -objscope -# @parameter command -# @parameter args +# The command gives script-level access to the NSF infrastructure for +# method dispatch. It can be used to bypass standard method +# dispatching (as defined by a given object system) and to devise your +# own method dispatch scheme. Likewise, it provides means to create +# programs which operate over several object systems and their method +# dispatching schemes (e.g., a serializer, a program structure +# analyzer). +# +# @parameter object Indicates the name of the receiving object +# @parameter -frame Denotes the type of <<@gls cframe>> to +# be stacked upon invoking the alias +# method. Permissible options are: +# '''method''', '''object''', +# '''default''' +# @parameter command Specifies the receiving command, to be invoked in +# the callframe scope of the receiver +# object. The receiving command can be +# specified as a <<@gls method_handle>> +# @parameter args The actual invocation arguments, to be +# funneled to the receiving command. +# @return The result value as returned by the receiving +# command -# @command deprecated +# @command existsvar # -# @parameter what -# @parameter oldCmd -# @parameter newCmd:optional +# A low-level introspection command to query the existance of an +# object variable, given the variable's name and the holder object. By +# existance, we mean whether a variable has been 'created' (and not +# necessarily 'defined', in terms of Tcl variable semantics). It, +# therefore, pairs with Tcl's '''[info exists]'''. +# +# @parameter object The variable-holding object +# @parameter varname The variable name +# @return If the variable exists, the test returns +# '''1'''; '''0''' otherwise -# @command objectproperty +# @command exithandler # -# @parameter object:object -# @parameter objectkind Accepts one of: '''type''', '''object''', -# '''class''', '''baseclass''', '''metaclass''', '''hasmixin''' -# @parameter value:optional +# This command is used to register and manage an application-level +# handler which is to be executed upon shutting down a NSF-enabled +# '''interp'''. The handler takes the form of a script which is +# evaluated early upon calling <<@command finalize>>. +# +# @parameter args A variable argument vector, identifying a +# subcommand ('''set''', '''get''', '''unset''') +# and an optional value which carries the +# handler script to be set. +# @command finalize +# +# The command manually triggers the disciplined shutdown and +# destruction of an entire object system in a given +# '''interp'''. First, the application-level exit handler script is +# evaluated. You may provide your own exit handler using <<@command +# exithandler>>. Second, the object system itself is cleared and +# removed from the '''interp'''. This discrete destruction trigger is +# convenient to control an object system's lifespan in environments +# with more complex '''interp''' lifecycles (e.g., in threaded Tcl +# programs, '''interp''' reuse, etc.). + # @command importvar # -# @parameter object:object -# @parameter args +# A command used to create a link to an object variable in the current +# callframe context (i.e., a proc or eval frame). It arranges for a +# one or several local variables in the current callframe to refer to +# variables held by an object. The command resembles the variable +# binding semantics of '''upvar''', '''uplevel''', and +# '''global'''. While the local link variable does not have to exist +# at the time of calling this command, as it will be lazily created +# upon first use, there must not exist a local variable by the name of +# the specified link variable. +# +# @parameter object The variable-holding object +# @parameter args A variable argument vector, defining +# the intended mappings between object +# and local variables. Each mapping is a +# single- or double-valued list. A +# single-valued mapping will create a +# local link variable with the same name +# as the object variable. A +# double-valued mapping will give the +# link variable a different name. # @command parametercheck # @@ -192,9 +378,23 @@ # @command configure # # A top-level configuration facility which allows you modify -# properties of the "Next" object system for the scope of an entire +# properties of the a given object system for the scope of an entire # '''interp'''. +# @command.sub-command {configure debug} +# +# The NSF runtime provides you with the <<@command log>> command to +# drop logging statements, filtered by custom debug levels. To +# activate a certain debug level, use this configuration facility. The +# runtime defaults to debug level '''0'''. A debug level greater than +# '''0''' increases the runtime's native verbosity (i.e., selected +# warnings and debugging-critical information will be displayed). +# +# @parameter level:optional If provided, sets the runtime's debug +# level. If omitted, you obtain the +# debug level currently active. + + # @command.sub-command {configure filter} # # Allows turning on or off filters globally for the current @@ -203,7 +403,7 @@ # 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" +# @parameter toggle Accepts either '''on''' or '''off''' # @return The current filter activation state # @command.sub-command {configure softrecreate} @@ -222,25 +422,25 @@ # 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. +# instances of '''B''' are re-classed to the object system's root +# class. When softrecreate is set, the class hierarchy remains +# untouched. # -# @parameter toggle Accepts either "on" or "off" +# @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": +# current object system, i.e., the ruling root class and the root +# meta-class. It is the introspective counterpart of <<@command +# createobjectsystem>>. # -# ''' -# configure objectsystems; # returns "::nx::Object ::nx::Class" -# ''' -# -# @return The active pair of root class and root meta-class +# @return A list of currently specified object systems. Each +# sublist gives the pair of root class and +# root meta-class and (if available) the mappings of +# system hooks to system methods. # @command.sub-command {configure keepinitcmd} # @@ -255,35 +455,121 @@ # @parameter value:boolean Either '''true''' or '''false''' # @return The current setting -# @command alias +# @command.sub-command {configure checkarguments} # -# @parameter object:object The target object which becomes the owner of -# the aliased command (method, object or command). +# NSF provides optional type checkers for arguments to method +# invocations, based on method parameter specifications. This +# configuration options lets you activate or deactive type checking on +# method arguments for the scope of a given '''interp'''. # -# @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 ...) +# @parameter value:boolean Either '''true''' or '''false''' +# @return The current setting, either '''1''' or '''0''' -# @command finalize +# @command.sub-command {configure checkresults} +# +# NSF provides optional type checkers for result values of method +# executions. For details, see <<@command methodproperty>>. This +# configuration options lets you activate or deactive this type +# checking for the scope of a given '''interp'''. +# +# @parameter value:boolean Either '''true''' or '''false''' +# @return The current setting, either '''1''' or '''0''' + # @command interp # -# @parameter name -# @parameter args +# A convenience wrapper command around '''[interp]'''. When '''[interp +# create]''' is intercepted, the resulting slave '''interp''' is +# equipped with the NSF extension by calling the extension's +# '''*_Init()''' function on the new '''interp'''. Roughly, it +# corresponds to the following scripted version: +# +# ''' +# ::proc ::nsf::interp {subcmd args} { +# set r [uplevel [list ::interp $subcmd {*}$args]] +# switch -- $subcmd { +# create { +# $r eval [list package req nsf] +# } +# } +# return $r +# } +# ''' +# +# @parameter name The name of the slave '''interp''' +# @parameter args A variable argument vector, +# carrying subcommand-specific arguments. +# @command log +# +# Provides script-level access to NSF's logging facilities. You may +# specify logging statements to be filtered by custom-defined debug +# levels. By convention, level '''0''' represents the lowest verbosity +# level. To set the actual debug level, use <<@command.command +# {configure debug}>>. +# +# @parameter level A numeric debugging level, e.g.: '''0''', '''1''', +# ... +# @parameter msg The logging statement to display + # @command is # -# @parameter value -# @parameter constraint -# @parameter -hasmixin -# @parameter -type -# @parameter arg +# The command tests whether a given string is a valid according to a +# value constraint. Depending on the nature of the tested string value +# (i.e., a Tcl value structure, an NSF object, or an NSF class), you +# can express various constraint types. +# +# 1. Constraint types on Tcl value representations ('''Tcl_Obj'''), +# i.e. arbitrary strings: +# +# You may use any character class provided by '''[string is]''', e.g.: +# ''' +# ::nsf::is boolean|double|false|integer|list|lower|true|upper|wideinteger /value/ +# ''' +# A Tcl value may be tested whether it represents an NSF object (see +# also <<@command isobject>>): +# ''' +# ::nsf::is object /value/ +# ''' +# 2. Constraint types on NSF objects: +# +# Objects may be tested whether they qualify as a class and whether +# they have a particular object-type: +# ''' +# ::nsf::is object,type=/class/ /object/ +# ::nsf::is class /object/ +# ''' +# 3. Constraint types on NSF classes: +# +# Classes can be tested for their relationship status, e.g., whether +# they serve as meta-class for other classes: +# ''' +# ::nsf::is metaclass /class/ +# ''' +# +# @parameter -complain:switch If set, a constraint violation will +# result in a Tcl error being fired. +# @parameter constraint The actual value constraint expression +# @parameter value The value to test +# @return In the non-complaining mode +# ('''-complain''' has been omitted), a +# pass is signalled by '''1''', a +# violation by '''0'''. In complaining +# mode, a Tcl error is raised in case of +# a constraint violation along with a +# '''0''' return value. +# @command isobject +# +# Tests whether a given Tcl command represents an NSF object. The +# command incurs the least dispatch overhead to identify an object and +# is preferred over its derivates, such as <<@command is>>. +# +# @parameter value The value to test +# @return If the value represents an object, '''1''' is +# signalled, '''0''' otherwise. + + # @command my # # @parameter -local Index: tests/doc.test =================================================================== diff -u -N -r239888ee1ee6ed6d7b9afa5e170f49c5224a186d -rb067e586fadae95916358904fd8392d073c7c87c --- tests/doc.test (.../doc.test) (revision 239888ee1ee6ed6d7b9afa5e170f49c5224a186d) +++ tests/doc.test (.../doc.test) (revision b067e586fadae95916358904fd8392d073c7c87c) @@ -1082,16 +1082,47 @@ package nsf }] -set project [processor process -sandboxed $project] +set ::nsf::includes { + ::nsf::alias + ::nsf::configure + ::nsf::current + ::nsf::finalize + ::nsf::interp + ::nsf::is + ::nsf::log + ::nsf::my + ::nsf::next + ::nsf::relation + ::nsf::tmpdir + ::nsf::assertion + ::nsf::createobjectsystem + ::nsf::dispatch + ::nsf::existsvar + ::nsf::exithandler + ::nsf::forward + ::nsf::importvar + ::nsf::isobject + ::nsf::method + ::nsf::methodproperty + ::nsf::provide_method + ::nsf::qualify + ::nsf::require_method + ::nsf::setter + ::nsf::setvar +} +set project [processor process \ + -sandboxed \ + -validate \ + -include $::nsf::includes $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 \ @@ -1100,90 +1131,23 @@ -@namespace "::nx" \ -sources { package nx - }] + } -depends $project] # ISSUE: If calling '-namespace "::nx"' instead of '-@namespace # "::nx"', we get an irritating failure. VERIFY! - processor process -sandboxed $project + processor process \ + -validate \ + -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" \ -# -sources { -# {package nx} -# {scriptfile generic/nsf.tcl} -# {script {}} -# }] - -# # 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] - -# #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] -# } - -# 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} - -# # 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} -# } - - # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #