Index: library/lib/doc-tools.tcl =================================================================== diff -u -rbb292ab3dff4b1d3a65e0a532b691e8a6dcd688c -r84921e055921d2ee9adf2853048cf05b3bf62643 --- library/lib/doc-tools.tcl (.../doc-tools.tcl) (revision bb292ab3dff4b1d3a65e0a532b691e8a6dcd688c) +++ library/lib/doc-tools.tcl (.../doc-tools.tcl) (revision 84921e055921d2ee9adf2853048cf05b3bf62643) @@ -1615,9 +1615,16 @@ set preprocessed [:unescape $preprocessed] # TODO: For now, we take a passive approach: Some docstrings # might fail because they contain substitution characters - # ($,[]); see nx.tcl + # ($,[]); see nx.tcl. The same goes for legacy xodoc docstrings, + # and their code listing (see langRef.xotcl). Catching + # evaluations errors here makes it unnecessary to + # escape/unescape evaluation chars; at the same time, we can't + # distinguish errors on unintended and intended evaluations. # ... - catch {set preprocessed [subst $preprocessed]} msg + if {[catch {set preprocessed [subst $preprocessed]} msg]} { + puts stderr MSG=$msg + puts stderr IN->$preprocessed + } return $preprocessed } @@ -1680,6 +1687,7 @@ # 3) TODO: revoke the application of the mixin layer (for the sake of # some sort of bounded quantification) + [current class] revoke } # @@ -1881,7 +1889,7 @@ :public method filename {} { return "index" } - :method navigatable_parts {} { + :public method navigatable_parts {} { # # TODO: Should I wrap up delegating calls to the originator # entity behind a unified interface (a gatekeeper?) @@ -1992,8 +2000,10 @@ set ipath [$box do $exp] foreach c [concat $ipath ${:name}] { set entity [[:info class] id $c] - if {![::nsf::is object $entity]} continue + if {![::nsf::is object $entity]} continue; set origin [$entity origin] + if {$origin ni [concat {*}[dict values [$prj navigatable_parts]]]} continue; + if {[$origin eval [list info exists :${member}]]} { dict set inherited $entity [$entity !get \ -sortedby name \ @@ -2106,9 +2116,7 @@ } puts "\n" } - } - } # @@ -2874,13 +2882,179 @@ } namespace export Sandbox } + + +namespace eval ::nx::doc::xodoc { + + namespace import -force ::nx::* + namespace import -force ::nx::doc::* + + # xodoc -> nxdoc + # - - - - - - - - - - - - - - - - + # MetadataToken Entity + # FileToken @package + # PackageToken @package + # ConstraintToken n/a + # MethodToken n/a + # ProcToken @method (scope = object) + # InstprocToken @method (scope = class) + # ObjToken @object + # ClassToken @class + # MetaClassToken n/a + + Class create MetadataToken { + :class-object attribute analyzer + :public forward analyzer [current] %method + :method as {partof:object,type=::nx::doc::StructuredEntity} \ + -returns object,type=::nx::doc::Entity { + error "Subclass responsibility" + } + :public method emit {partof:object,type=::nx::doc::StructuredEntity} \ + -returns object,type=::nx::doc::Entity { + set entity [:as $partof] + set props [:get_properties] + if {[dict exists $props description]} { + $entity @doc [dict get $props description] + } + return $entity + } + :method get_properties {} { + if {[info exists :properties]} { + set props [dict create] + foreach p ${:properties} { + if {[info exists :$p]} { + dict set props [string tolower $p] \ + [:format [set :$p]] + } + } + return $props + } + } + :method format {value} { + # + # 1. replace @-prefixed tags etc. + # + set value [[:analyzer] replaceFormatTags $value] + + # + # 2. escape Tcl evaluation chars in code listings + # + set value [string map { + "\\" "\\\\" + "{" "\\{" + "}" "\\}" + "\"" "\\\"" + "[" "\\[" + "]" "\\]" + "$" "\\$" + } $value] + + # + # 3. box the prop value in a list (this avoids unwanted + # interactions with the line-by-line as_text post-processor) + # + return [list $value] + } + } + + Class create PackageToken -superclass MetadataToken + Class create FileToken -superclass MetadataToken { + :method as {partof:object,type=::nx::doc::StructuredEntity} \ + -returns object,type=::nx::doc::Entity { + # + # TODO: Where to retrieve the package name from? + # + return [@package new -name XOTcl] + } + :public method emit {partof:object,type=::nx::doc::StructuredEntity} \ + -returns object,type=::nx::doc::Entity { + set entity [next] + set props [dict remove [:get_properties] description] + dict for {prop value} $props { + $entity @doc add "

$prop

[join $value]" end + } + $entity @namespace [[$entity current_project] @namespace] + return $entity + } + } + + # + # Note: For whatever reason, InstprocToken is provided but never + # used, at least in XOTcl-langRef. while most probably due to a lack + # of attention or a silent revocation of a design decision in xodoc, + # it forces us into code replication for differentiating the + # per-class and per-object scopes ... in xodoc, these scopes are + # double-encoded, both in proper token subclassifications as well as + # aggregation properties: procList, instprocList ... well, I will + # have to live with it. + # + + Class create MethodToken -superclass MetadataToken + + Class create ProcToken -superclass MethodToken { + :method as {scope partof:object,type=::nx::doc::StructuredEntity} \ + -returns object,type=::nx::doc::Entity { + return [$partof @${scope}-method [:name]] + } + :public method emit {scope partof:object,type=::nx::doc::StructuredEntity} { + set entity [:as $scope $partof] + set props [:get_properties] + if {[dict exists $props description]} { + $entity @doc [dict get $props description] + } + if {[dict exists $props return]} { + $entity @return [dict get $props return] + } + return $entity + } + } + + Class create InstprocToken -superclass MethodToken + + Class create ObjToken -superclass MetadataToken { + :method as {partof:object,type=::nx::doc::ContainerEntity} \ + -returns object,type=::nx::doc::Entity { + return [@object new -name [:name]] + } + :public method emit {entity:object,type=::nx::doc::Entity} \ + -returns object,type=::nx::doc::Entity { + set entity [next] + foreach p [:procList] { + $p emit object $entity + } + return $entity + } + } + + Class create ClassToken -superclass ObjToken { + :method as {partof:object,type=::nx::doc::ContainerEntity} \ + -returns object,type=::nx::doc::Entity { + return [@class new -name [:name]] + } + :public method emit {entity:object,type=::nx::doc::Entity} \ + -returns object,type=::nx::doc::Entity { + set entity [next] + foreach iproc [:instprocList] { + $iproc emit class $entity + } + return $entity + } + } + + Class create MetaClassToken -superclass ClassToken + + namespace export MetadataToken FileToken MethodToken ProcToken \ + InstprocToken ObjToken ClassToken MetaClassToken +} + + # # 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 { @@ -3101,13 +3275,78 @@ } return $project } - + + :protected class-object method process=@package {project pkgs} { + set box [$project sandbox] + $box permissive_pkgs [string tolower $pkgs] + set 1pass "" + foreach pkg $pkgs { + if {[catch {package req $pkg} _]} { + error "Tcl package '$pkg' cannot be found." + } + append 1pass "package req $pkg\n" + } + + # + # 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}]} { + # + # Note: Expects the XOTcl2 utilities to be in place and + # accessible by the [package req] mechanism, use e.g.: + # export TCLLIBPATH=". ./library/xotcl/library/lib" + # + package req xotcl::xodoc + + set docdb [XODoc new] + ::xotcl::@ set analyzerObj $docdb + foreach {pkg src} [$box eval {set :source}] { + $docdb analyzeFile $src + } + + foreach m [namespace eval ::nx::doc::xodoc {namespace export}] { + if {[::xotcl::Class info instances -closure ::xotcl::metadataAnalyzer::$m] ne ""} { + ::xotcl::metadataAnalyzer::$m instmixin add ::nx::doc::xodoc::$m + } + } + + ::nx::doc::xodoc::MetadataToken eval [list set :analyzer $docdb] + set provided_entites [list] + # + # as we analyze file by file, there is only one FileToken to + # be molded into an @package + # + set ft [::xotcl::metadataAnalyzer::FileToken allinstances] + if {[llength $ft] > 1} { + error "Too many xodoc file tokes processed. Expecting just one!" + } + + set partof $project + if {$ft ne ""} { + set pkg [$ft emit $project] + lappend provided_entities $pkg + set partof $pkg + } + foreach token [::xotcl::metadataAnalyzer::ObjToken allinstances] { + lappend provided_entities [$token emit $partof] + } + return $provided_entities + } + } + :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} _]} { + if {[catch {package req $pkg} _]} { error "Tcl package '$pkg' cannot be found." } append 1pass "package req $pkg\n" @@ -3144,12 +3383,6 @@ 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" } :protected class-object method process=source {project filepath} {;} Index: library/xotcl/doc/langRef.xotcl =================================================================== diff -u -rcfd13f351499bb4b1b1debd55f209419edf1af14 -r84921e055921d2ee9adf2853048cf05b3bf62643 --- library/xotcl/doc/langRef.xotcl (.../langRef.xotcl) (revision cfd13f351499bb4b1b1debd55f209419edf1af14) +++ library/xotcl/doc/langRef.xotcl (.../langRef.xotcl) (revision 84921e055921d2ee9adf2853048cf05b3bf62643) @@ -2,6 +2,9 @@ package provide XOTcl-langRef 1.6.4 package require XOTcl +namespace eval ::xotcl {} +namespace import -force ::xotcl::@ + @ @File { description { XOTcl language reference. Describes predefined objects and classes. Index: tests/doc.test =================================================================== diff -u -rbb292ab3dff4b1d3a65e0a532b691e8a6dcd688c -r84921e055921d2ee9adf2853048cf05b3bf62643 --- tests/doc.test (.../doc.test) (revision bb292ab3dff4b1d3a65e0a532b691e8a6dcd688c) +++ tests/doc.test (.../doc.test) (revision 84921e055921d2ee9adf2853048cf05b3bf62643) @@ -1064,7 +1064,8 @@ puts stderr ================================================= foreach path [list [file join [::nsf::tmpdir] NextScriptingFramework] \ - [file join [::nsf::tmpdir] NextScriptingLanguage]] { + [file join [::nsf::tmpdir] NextScriptingLanguage] \ + [file join [::nsf::tmpdir] XOTcl2]] { if {[file exists $path]} { file delete -force $path } @@ -1156,6 +1157,24 @@ puts stderr ">>>>> gross timing for $project $_" +set project [::nx::doc::@project new \ + -name XOTcl2 \ + -url http://www.xotcl.org/ \ + -version 2.0.0 \ + -@namespace "::xotcl" \ + -sources { + @package XOTcl-langRef + }] + +processor process \ + -sandboxed \ + $project + +::nx::doc::make doc \ + -renderer ::nx::doc::NxDocRenderer \ + -project $project \ + -outdir [::nsf::tmpdir] + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #