Module: environment-reports Author: Andy Armstrong, Jason Trenouth Synopsis: Library report generator Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc. All rights reserved. License: Functional Objects Library Public License Version 1.0 Dual-license: GNU Lesser General Public License Warranty: Distributed WITHOUT WARRANTY OF ANY KIND /// ---*** consider merging report-streams and reports /// ---*** maybe headers and footers and bodies could be done as specializers /// ---*** could use indentation support /// Namespace, Library, and Module reports define constant $default-dtd = "./refman.dtd"; define constant $default-organization = "Functional Objects, Inc."; define constant $default-copyright = "Copyright (c) 1999 Functional Objects, Inc. All rights reserved."; define constant $default-version = "1.0"; define class (, ) slot report-multi-file? :: = #f, init-keyword: multi-file?:; end class ; define class () constant slot report-dtd :: = $default-dtd, init-keyword: dtd:; constant slot report-organization :: = $default-organization, init-keyword: organization:; constant slot report-copyright :: = $default-copyright, init-keyword: copyright:; constant slot report-version :: = $default-version, init-keyword: version:; slot report-children :: = make(); slot report-contents-file :: false-or() = #f; constant slot report-object-filenames :: = make(); slot report-anonymous-count :: = 0; end class ; install-report(#"interface-reference", "Library interface reference", , edition: #"internal", formats: #[#"text", #"html", #"xml"], multi-file?: #t); define class () sealed constant slot report-namespace :: , required-init-keyword: namespace:; sealed constant slot report-parent :: , required-init-keyword: parent:; end class ; define method report-namespace (report :: ) report.report-project.project-library end method report-namespace; define method write-report-as (stream :: , report :: , format :: ) => () write-library-report(stream, report) end method write-report-as; define method create-multi-file-report-as (report :: , directory :: , format :: ) => (filename :: ) report-directory(report) := directory; report-multi-file?(report) := #t; write-library-report(directory, report); report-contents-file(report); end method create-multi-file-report-as; define method write-library-report (stream :: , report :: ) => () if (report.report-multi-file? & (report.report-format ~= #"html")) error(make()) // ---*** we only support multi-file reports for HTML at the moment end if; let library = report.report-project.project-library; let stream = make(stream-class-for-report(report.report-format), inner-stream: stream); write-definition-report(stream, report, library); end method write-library-report; define method write-library-report (file :: , report :: ) => () report-contents-file(report) := compute-contents-file(report, file); with-open-file (stream = report-contents-file(report), direction: #"output") write-library-report(stream, report) end with-open-file; end method write-library-report; define method compute-contents-file (report :: , file :: ) => (contents :: ) if (report-multi-file?(report)) let project = report.report-project; let library = project.project-library; let library-name = environment-object-primitive-name(project, library); let name = format-to-string("%s-library-reference.htm", library-name); merge-locators(as(, name), as(, file)); else file end if; end method compute-contents-file; /// Protocols define class () end class ; define constant = one-of(#"input", #"input-rest", #"input-keyword", #"output", #"output-rest"); define generic write-definition-report (stream :: , report :: , object :: false-or()) => (); define generic write-definition-header (stream :: , report :: , definition :: ) => (); define generic write-definition-body (stream :: , report :: , definition :: ) => (); define generic write-definition-footer (stream :: , report :: , definition :: ) => (); define generic write-definition-separator (stream :: , report :: , definition :: ) => (); define generic write-definition-name (stream :: , report :: , definition :: ) => (); define generic write-variable-type (stream :: , report :: , variable :: ) => (); define generic write-variable-value (stream :: , report :: , variable :: ) => (); define generic write-class-superclasses (stream :: , report :: , class :: ) => (); define generic write-superclasses-header (stream :: , report :: , class :: ) => (); define generic write-superclass (stream :: , report :: , superclass :: , #key last? :: = #f, first? :: = #f) => (); define generic write-superclasses-footer (stream :: , report :: , class :: ) => (); define generic write-class-init-keywords (stream :: , report :: , class :: ) => (); define generic write-init-keywords-header (stream :: , report :: , class :: ) => (); define generic write-init-keyword (stream :: , report :: , keyword :: , type :: false-or()) => (); define generic write-init-keywords-footer (stream :: , report :: , class :: ) => (); define generic write-operations (stream :: , report :: , class :: ) => (); define generic write-function-signature (stream :: , report :: , function :: ) => (); define generic write-function-arguments (stream :: , report :: , function :: ) => (); define generic write-function-values (stream :: , report :: , function :: ) => (); define generic write-function-parameter (stream :: , report :: , function :: , #key kind :: = #"input") => (); define generic write-function-parameters-header (stream :: , report :: , function :: , #key kind :: = #"input") => (); define generic write-function-parameters-footer (stream :: , report :: , function :: , #key kind :: = #"input") => (); define generic write-see-also (stream :: , report :: , definition :: ) => (); /// Default Methods define method write-definition-report (stream :: , report :: , definition :: ) => () write-definition-separator(stream, report, definition); write-definition-header(stream, report, definition); write-definition-body(stream, report, definition); write-definition-footer(stream, report, definition); end method write-definition-report; define method write-definition-report (stream :: , report :: , object == #f) => () // NB ignore non s end method write-definition-report; define method write-definition-header (stream :: , report :: , definition :: ) => () write-definition-name(stream, report, definition); write-definition-contents(stream, report, definition); end method write-definition-header; define method write-definition-separator (stream :: , report :: , definition :: ) => () end method write-definition-separator; define method write-definition-name (stream :: , report :: , definition :: ) => () end method write-definition-name; define method write-definition-contents (stream :: , report :: , definition :: ) => () end method write-definition-contents; define method write-definition-body (stream :: , report :: , definition :: ) => () end method write-definition-body; define method write-definition-footer (stream :: , report :: , definition :: ) => () write-description(stream, report, definition); write-see-also(stream, report, definition) end method write-definition-footer; define method write-description (stream :: , report :: , definition :: ) => () end method write-description; define method write-see-also (stream :: , report :: , definition :: ) => () end method write-see-also; define method write-definition-contents (stream :: , report :: , library :: ) => () let project = report.report-project; let names = namespace-sorted-names(project, library); for (name :: in names) let module = name-value(project, name); report.report-children := add!(report.report-children, make(, format: report.report-format, multi-file?: report.report-multi-file?, project: project, parent: report, namespace: module)); end for; end method write-definition-contents; define method write-definition-body (stream :: , report :: , library :: ) => () for (subreport in report.report-children) let module = subreport.report-namespace; if (subreport.report-multi-file?) let filename = report-object-filename(subreport, module); with-open-file (stream = filename, direction: #"output") let stream = make(stream-class-for-report(report.report-format), inner-stream: stream); with-html-rubric (istream = stream.inner-stream, // ---*** push this down into HTML method format-to-string("%s %s", definition-name(subreport, module), definition-kind(module))) write-definition-report(stream, subreport, module) end with-html-rubric; end with-open-file; else write-definition-report(stream, subreport, module) end if; end for; end method write-definition-body; define method write-definition-body (stream :: , report :: , module :: ) => () let project = report.report-project; let names = namespace-sorted-names(project, module); for (name :: in names) let definition = name-value(project, name); if (instance?(definition, )) if (report.report-multi-file?) let filename = report-object-filename(report, definition); with-open-file (stream = filename, direction: #"output") let stream = make(stream-class-for-report(report.report-format), inner-stream: stream); with-html-rubric (istream = stream.inner-stream, // ---*** push this down into HTML method format-to-string("%s %s", definition-name(report, definition), definition-kind(definition))) write-definition-report(stream, report, definition) end with-html-rubric; end with-open-file; else write-definition-report(stream, report, definition); end if; end if; end for; end method write-definition-body; define method write-definition-body (stream :: , report :: , variable :: type-union(, )) => () write-variable-type(stream, report, variable); write-variable-value(stream, report, variable); end method write-definition-body; define method write-definition-body (stream :: , report :: , class :: ) => () write-class-superclasses(stream, report, class); write-class-init-keywords(stream, report, class); write-operations(stream, report, class); end method write-definition-body; define method write-definition-body (stream :: , report :: , function :: ) => () write-function-signature(stream, report, function); write-function-arguments(stream, report, function); write-function-values(stream, report, function); end method write-definition-body; define method write-definition-body (stream :: , report :: , _macro :: ) => () // ---*** what to do? end method write-definition-body; define method write-variable-type (stream :: , report :: , variable :: ) => () end method write-variable-type; define method write-variable-value (stream :: , report :: , variable :: ) => () end method write-variable-value; define method write-class-superclasses (stream :: , report :: , class :: ) => () let project = report.report-project; let module = report.report-namespace; write-superclasses-header(stream, report, class); let superclasses = class-direct-superclasses(project, class); let length = size(superclasses); for (superclass in superclasses, i from 0 below length, first? = #t then #f) let last? = (i = (length - 1)); write-superclass(stream, report, superclass, first?: first?, last?: last?); end; write-superclasses-footer(stream, report, class); end method write-class-superclasses; define method write-superclasses-header (stream :: , report :: , class :: ) => () end method write-superclasses-header; define method write-superclass (stream :: , report :: , superclass :: , #key last? :: = #f, first? :: = #f) => () end method write-superclass; define method write-superclasses-footer (stream :: , report :: , superclass :: ) => () end method write-superclasses-footer; define method write-class-init-keywords (stream :: , report :: , class :: ) => () let project = report.report-project; let module = report.report-namespace; write-init-keywords-header(stream, report, class); let types = make(); do-init-keywords (method (definition :: , keyword :: , type :: false-or(), required? :: , inherited? :: ) unless (element(types, keyword, default: #f)) types[keyword] := type end unless; end, project, class, inherited?: #f); for (keyword in sort!(key-sequence(types))) write-init-keyword(stream, report, keyword, types[keyword]) end; write-init-keywords-footer(stream, report, class); end method write-class-init-keywords; define method write-init-keywords-header (stream :: , report :: , class :: ) => () end method write-init-keywords-header; define method write-init-keyword (stream :: , report :: , keyword :: , type :: false-or()) => () end method write-init-keyword; define method write-init-keywords-footer (stream :: , report :: , class :: ) => () end method write-init-keywords-footer; define method write-operations (stream :: , report :: , class :: ) => () end method write-operations; define method write-function-signature (stream :: , report :: , function :: ) => () let project = report.report-project; let module = report.report-namespace; let (required, rest, key, all-keys?, next, required-values, rest-value) = function-parameters(project, function); write-function-name(stream, report, function); format(stream, " ("); local method do-parameter (parameter :: ) => () format(stream, "%s", if (instance?(parameter, )) parameter.parameter-keyword end | parameter.parameter-name) end method do-parameter; local method do-parameters (parameters :: ) => () for (parameter :: in parameters, separator = "" then " ") format(stream, separator); do-parameter(parameter) end for; end method do-parameters; do-parameters(required); let printed-something = size(required) > 0; local method print-separator () => () if (printed-something) format(stream, " "); else printed-something := #t; end; end method print-separator; if (next) print-separator(); format(stream, "#next "); do-parameter(next); end; if (rest) print-separator(); format(stream, "#rest "); do-parameter(rest); end; case key & size(key) > 0 => print-separator(); format(stream, "#key "); do-parameters(key); if (all-keys?) format(stream, " #all-keys") end; all-keys? => print-separator(); format(stream, "#key #all-keys"); otherwise => #f; end; format(stream, ") => ("); do-parameters(required-values); if (rest-value) if (size(required-values) > 0) format(stream, ", "); end; format(stream, "#rest "); do-parameter(rest-value) end; format(stream, ")"); new-line(stream); end method write-function-signature; define method write-function-arguments (stream :: , report :: , function :: ) => () let project = report.report-project; let module = report.report-namespace; let (required, rest, key, all-keys?, next, required-values, rest-value) = function-parameters(project, function); local method do-parameter (parameter :: ) => () write-function-parameter(stream, report, parameter) end method do-parameter; local method do-parameters (parameters :: ) => () do(do-parameter, parameters) end method do-parameters; write-function-parameters-header(stream, report, function); do-parameters(required); rest & do-parameter(rest); if (key & size(key) > 0) do-parameters(key) end; write-function-parameters-footer(stream, report, function); end method write-function-arguments; define method write-function-values (stream :: , report :: , function :: ) => () let project = report.report-project; let module = report.report-namespace; let (required, rest, key, all-keys?, next, required-values, rest-value) = function-parameters(project, function); local method do-parameter (parameter :: ) => () write-function-parameter(stream, report, parameter, kind: #"output"); end method do-parameter; local method do-parameters (parameters :: ) => () do(do-parameter, parameters) end method do-parameters; write-function-parameters-header(stream, report, function, kind: #"output"); do-parameters(required-values); rest-value & do-parameter(rest-value); write-function-parameters-footer(stream, report, function, kind: #"output"); end method write-function-values; define method write-function-parameter (stream :: , report :: , function :: , #key kind :: = #"input") => () end method write-function-parameter; define method write-function-parameters-header (stream :: , report :: , function :: , #key kind :: = #"input") => () end method write-function-parameters-header; define method write-function-parameters-footer (stream :: , report :: , function :: , #key kind :: = #"input") => () end method write-function-parameters-footer; /// methods define class () end class ; define method stream-class-for-report (_format == #"text") => (class :: subclass()) end method stream-class-for-report; define method write-definition-separator (stream :: , report :: , definition :: ) => () format(stream, "%s\n", $report-separator); end method write-definition-separator; define method write-definition-name (stream :: , report :: , namespace :: ) => () format(stream, "%s %s\n\n", definition-kind(namespace), environment-object-primitive-name(report.report-project, namespace)); end method write-definition-name; define method write-definition-name (stream :: , report :: , definition :: ) => () let project = report.report-project; let title = definition-name(report, definition); let type = definition-type-description(project, definition); let padding = max(6, $report-width - title.size - type.size); format(stream, "%s%s%s\n", title, make(, fill: ' ', size: padding), type) end method write-definition-name; define method write-superclasses-header (stream :: , report :: , class :: ) => () format(stream, "\nSuperclasses:\n\n"); end method write-superclasses-header; define method write-superclass (stream :: , report :: , superclass :: , #key last? :: = #f, first? :: = #f) => () format(stream, "%s\n", definition-name(report, superclass)) end method write-superclass; define method write-init-keywords-header (stream :: , report :: , class :: ) => () format(stream, "\nInit-keywords:\n\n"); end method write-init-keywords-header; define method write-init-keyword (stream :: , report :: , keyword :: , type :: false-or()) => () format(stream, " %s:\n", as(, keyword)) end method write-init-keyword; define method write-function-name (stream :: , report :: , function :: ) => () format(stream, "\n%s ", definition-name(report, function)); end method write-function-name; define method write-function-parameter (stream :: , report :: , parameter :: , #key kind :: = #"input") => () let project = report.report-project; let module = report.report-namespace; let type = parameter.parameter-type; format(stream, "%s :: %s", if (instance?(parameter, )) parameter.parameter-keyword end | parameter.parameter-name, definition-name(report, type)); new-line(stream); end method write-function-parameter; /// HTML implementation /// ---------------------------------------------------------------------- /// HTML define class () end class ; define method initialize (stream :: , #key inner-stream) next-method(); stream.inner-stream := ensure-html-stream(inner-stream); end method initialize; define method ensure-html-stream (stream :: ) => (html-stream :: ) make(, inner-stream: stream) end method ensure-html-stream; define method ensure-html-stream (stream :: ) => (html-stream :: ) stream end method ensure-html-stream; define method write-html (stream :: , #rest sequence) => () apply(write-html, stream.inner-stream, sequence) end method write-html; define method stream-class-for-report (_format == #"html") => (class :: subclass()) end method stream-class-for-report; define method write-definition-separator (stream :: , report :: , definition :: ) => () write-html(stream, #"hr", '\n'); end method write-definition-separator; define method write-definition-name (stream :: , report :: , definition :: ) => () let title = definition-name(report, definition); write-html(stream, #"h3", make(, name: title), title, #"/h3", '\n'); end method write-definition-name; /// HTML section generation define method write-superclasses-header (stream :: , report :: , class :: ) => () write-html(stream, #"p", "Superclasses: "); end method write-superclasses-header; define method write-superclass (stream :: , report :: , superclass :: , #key last? :: = #f, first? :: = #f) => () write-object-reference(stream, report, superclass) end method write-superclass; define method write-superclasses-footer (stream :: , report :: , superclass :: ) => () new-line(stream) end method write-superclasses-footer; define method write-init-keywords-header (stream :: , report :: , class :: ) => () write-html(stream, #"p", "Init-keywords:", '\n', '\n'); write-html(stream, #"ul", '\n'); end method write-init-keywords-header; define method write-init-keyword (stream :: , report :: , keyword :: , type :: false-or()) => () write-html(stream, #"li", as(, keyword), ':'); new-line(stream); end method write-init-keyword; define method write-init-keywords-footer (stream :: , report :: , class :: ) => () write-html(stream, #"/ul", '\n'); new-line(stream) end method write-init-keywords-footer; define method write-function-name (stream :: , report :: , function :: ) => () format(stream, "%s ", definition-name(report, function)); end method write-function-name; define method write-function-parameter (stream :: , report :: , parameter :: , #key kind :: = #"input") => () let project = report.report-project; let module = report.report-namespace; let type = parameter.parameter-type; write-html(stream, #"li", if (instance?(parameter, )) parameter.parameter-keyword end | parameter.parameter-name, " :: "); print-environment-object-name (stream, project, type, namespace: module); write-html(stream, #"/li", '\n') end method write-function-parameter; define method write-function-parameters-header (stream :: , report :: , function :: , #key kind :: = #"input") => () write-html(stream, #"ul", '\n'); end method write-function-parameters-header; define method write-function-parameters-footer (stream :: , report :: , function :: , #key kind :: = #"input") => () write-html(stream, #"/ul", '\n') end method write-function-parameters-footer; define method write-definition-contents (stream :: , report :: , library :: ) => () next-method(); if (report-multi-file?(report)) let project = report.report-project; let library = project.project-library; let library-name = environment-object-primitive-name(project, library); with-html-output (stream = stream.inner-stream, format-to-string("%s Library", library-name)) write-html(stream, #"ul", '\n'); for (report in report.report-children) let module = report.report-namespace; let filename = report-object-filename(report, module); write-html(stream, #"li", make(, name: filename), environment-object-primitive-name(project, module), " Module", #"/a"); end for; end with-html-output; end if; end method write-definition-contents; define method write-definition-contents (stream :: , report :: , module :: ) => () if (report-multi-file?(report)) let project = report.report-project; let module-name = environment-object-primitive-name(project, module); let filename = report-object-filename(report, module); let names = namespace-sorted-names(project, module); write-html(stream, #"ul", '\n'); for (name :: in names) let definition = name-value(project, name); if (instance?(definition, )) let title = definition-name(report, definition); let filename = report-object-filename(report, definition); write-html(stream, #"li", make(, name: format-to-string("%s#%s", filename, title)), title, #"/a", '\n'); end if; end for; end if; end method write-definition-contents; /// methods define class () end class ; define method stream-class-for-report (_format == #"xml") => (class :: subclass()) end method stream-class-for-report; define method write-definition-header (stream :: , report :: , definition :: ) => () format(stream, "\n" "\n" "\n" "\n" "\n" "Functional Developer %s Reference Manual\n" "%s\n" "%s\n" "%s\n" "\n" "\n", report.report-dtd, definition-name(report, report.report-namespace), report.report-organization, report.report-copyright, report.report-version); next-method(); end method write-definition-header; define method write-definition-header (stream :: , report :: , definition :: ) => () format(stream, "<%s>\n", as-lowercase(definition-kind(definition))); write-definition-name(stream, report, definition); write-definition-contents(stream, report, definition); end method write-definition-header; define method write-definition-footer (stream :: , report :: , definition :: ) => () format(stream, "\n", as-lowercase(definition-kind(definition))); end method write-definition-footer; define method write-definition-footer (stream :: , report :: , definition :: ) => () next-method(); format(stream, "\n"); end method write-definition-footer; define method write-definition-header (stream :: , report :: , definition :: ) => () let project = report.report-project; format(stream, "\n"); next-method(); format(stream, " <%sdef>\n", as-lowercase(definition-kind(definition))); end method write-definition-header; define method write-definition-header (stream :: , report :: , class :: ) => () next-method(); format(stream, " %s\n", class-modifiers(report.report-project, class)); end method write-definition-header; define method write-definition-header (stream :: , report :: , function :: ) => () next-method(); format(stream, " %s\n", generic-function-modifiers(report.report-project, function)); end method write-definition-header; define method write-definition-footer (stream :: , report :: , definition :: ) => () let project = report.report-project; format(stream, " \n", as-lowercase(definition-kind(definition))); next-method(); format(stream, "\n"); end method write-definition-footer; define method write-definition-separator (stream :: , report :: , definition :: ) => () new-line(stream) end method write-definition-separator; define method write-definition-separator (stream :: , report :: , definition :: ) => () end method write-definition-separator; define method write-definition-name (stream :: , report :: , library :: ) => () format(stream, " %s\n\n", environment-object-primitive-name(report.report-project, library)); end method write-definition-name; define method write-definition-name (stream :: , report :: , definition :: ) => () let name = definition-name(report, definition); format(stream, " \n", name); end method write-definition-name; define method write-variable-type (stream :: , report :: , variable :: ) => () let type = variable-type(report.report-project, variable); let name = type & definition-name(report, type); format(stream, " \n", name | ""); end method write-variable-type; define method write-variable-value (stream :: , report :: , variable :: ) => () let value = variable-value(report.report-project, variable); let name = value & definition-name(report, value); format(stream, " \n", name | "#f"); end method write-variable-value; define method write-superclasses-header (stream :: , report :: , class :: ) => () format(stream, " \n"); end method write-superclasses-header; define method write-superclass (stream :: , report :: , superclass :: , #key last? :: = #f, first? :: = #f) => () format(stream, " \n", definition-name(report, superclass)) end method write-superclass; define method write-superclasses-footer (stream :: , report :: , class :: ) => () format(stream, " \n"); end method write-superclasses-footer; define method write-init-keywords-header (stream :: , report :: , class :: ) => () format(stream, " \n"); end method write-init-keywords-header; define method write-init-keyword (stream :: , report :: , keyword :: , type :: false-or()) => () format(stream, " \n" " %s:\n" " \n" " \n" " \n", as(, keyword), if (type) definition-name(report, type) else "" end if); end method write-init-keyword; define method write-init-keywords-footer (stream :: , report :: , class :: ) => () format(stream, " \n"); end method write-init-keywords-footer; define method write-function-signature (stream :: , report :: , function :: ) => () end method write-function-signature; define method write-function-arguments (stream :: , report :: , function :: ) => () let project = report.report-project; let module = report.report-namespace; let (required, rest, key, all-keys?, next, required-values, rest-value) = function-parameters(project, function); local method do-parameter (parameter :: , kind :: ) => () write-function-parameter(stream, report, parameter, kind: kind) end method do-parameter; local method do-parameters (parameters :: , kind :: ) => () do(rcurry(do-parameter, kind), parameters) end method do-parameters; write-function-parameters-header(stream, report, function); do-parameters(required, #"input"); rest & do-parameter(rest, #"input-rest"); if (key & size(key) > 0) do-parameters(key, #"input-keyword") end; if(all-keys?) format(stream, " \n") end; write-function-parameters-footer(stream, report, function); end method write-function-arguments; define method write-function-values (stream :: , report :: , function :: ) => () let project = report.report-project; let module = report.report-namespace; let (required, rest, key, all-keys?, next, required-values, rest-value) = function-parameters(project, function); local method do-parameter (parameter :: , kind :: ) => (); write-function-parameter(stream, report, parameter, kind: kind); end method do-parameter; local method do-parameters (parameters :: , kind :: ) => () do(rcurry(do-parameter, kind), parameters) end method do-parameters; write-function-parameters-header(stream, report, function, kind: #"output"); do-parameters(required-values, #"output"); rest-value & do-parameter(rest-value, #"output-rest"); write-function-parameters-footer(stream, report, function, kind: #"output"); end method write-function-values; define method write-function-parameters-header (stream :: , report :: , function :: , #key kind :: = #"input") => () select (kind) #"input" => format(stream, " \n"); #"output" => format(stream, " \n"); end select; end method write-function-parameters-header; define method write-function-parameters-footer (stream :: , report :: , function :: , #key kind :: = #"input") => () select (kind) #"input" => format(stream, " \n"); #"output" => format(stream, " \n"); end select; end method write-function-parameters-footer; define method write-function-parameter (stream :: , report :: , parameter :: , #key kind :: = #"input") => () let project = report.report-project; let module = report.report-namespace; let type = parameter.parameter-type; let tag = select(kind) #"input" => "in"; #"input-rest" => "rest-in"; #"input-keyword" => "keyword-in"; #"output" => "out"; #"output-rest" => "rest-out" end select; format(stream, " <%s>\n" " %s\n" " \n" " \n" " \n", tag, (if (instance?(parameter, )) parameter.parameter-keyword end | parameter.parameter-name), definition-name(report, type), tag); end method write-function-parameter; define method write-description (stream :: , report :: , definition :: ) => () format(stream, " \n"); end method write-description; define method write-see-also (stream :: , report :: , definition :: ) => () format(stream, " \n"); end method write-see-also; /// Utilities define method report-object-filename (report :: , object :: ) => (filename :: ) let parent = report.report-parent; let table = parent.report-object-filenames; element(table, object, default: #f) | begin let directory = parent.report-directory; let file = select (object by instance?) => let name = mangle-for-filename(definition-name(report, object)); format-to-string("%s-reference.htm", name); otherwise => let next-count = parent.report-anonymous-count + 1; parent.report-anonymous-count := next-count; format-to-string("anonymous-%d.htm", next-count); end; as(, merge-locators(as(, file), as(, directory))) end end method report-object-filename; define method mangle-for-filename (filename :: ) => (mangled :: ) let chars = make(); for (c in filename) let next = select (c) '<' => "lt"; '>' => "gt"; '?' => "qm"; '$' => "dl"; otherwise => c; end select; select (next by instance?) => for (n in next) chars := add!(chars, n) end for; => chars := add!(chars, next); end end; as(, chars) end method mangle-for-filename; define method write-object-reference (stream :: , report :: , object :: ) => () let reference = html-object-reference(report, object); write-html(stream, make(, name: reference), definition-name(report, object), #"/a") end method write-object-reference; define method html-object-reference (report :: , object :: ) => () let parent = report.report-parent; let title = definition-name(report, object); if (parent.report-directory) let filename = report-object-filename(report, object); format-to-string("%s#%s", filename, title) else format-to-string("#%s", title) end end method html-object-reference; define function namespace-sorted-names (project :: , namespace :: , #key internal?) => (sorted-names :: ) let names :: = make(); do-namespace-names (method (name :: ) if (internal? | name-exported?(project, name)) add!(names, name) end end, project, namespace); sort(names, test: method (name1 :: , name2 :: ) let p1 = environment-object-primitive-name(project, name1); let p2 = environment-object-primitive-name(project, name2); p1 < p2 end) end function namespace-sorted-names; define method definition-name (report :: , definition :: ) => (name :: ) let project = report.report-project; let namespace = report.report-namespace; let name = environment-object-name(project, definition, namespace); if (name) environment-object-primitive-name(project, name) else environment-object-display-name(project, definition, namespace) end end method definition-name; define method definition-type-description (project :: , class :: ) => (description :: ) definition-kind(class) end method definition-type-description; define method definition-kind (object :: ) => (kind :: ) "Constant" end method definition-kind; define method definition-kind (object :: ) => (description :: ) "Variable" end method definition-kind; define method definition-kind (object :: ) => (description :: ) "Macro" end method definition-kind; define method definition-kind (object :: ) => (description :: ) "Function" end method definition-kind; define method definition-kind (object :: ) => (description :: ) "Generic" end method definition-kind; define method definition-kind (object :: ) => (description :: ) "Class" end method definition-kind; define method definition-kind (object :: ) => (description :: ) "Library" end method definition-kind; define method definition-kind (object :: ) => (description :: ) "Module" end method definition-kind; define method definition-type-description (project :: , function :: ) => (description :: ) concatenate(generic-function-modifiers(project, function), definition-kind(function)) end method definition-type-description; define method definition-type-description (project :: , class :: ) => (description :: ) concatenate(class-modifiers(project, class), definition-kind(class)) end method definition-type-description; define method class-modifiers (project :: , class :: ) => (modifiers :: ) let modifiers = definition-modifiers(project, class); let open? = member?(#"open", modifiers); let abstract? = member?(#"abstract", modifiers); let primary? = member?(#"primary", modifiers); let instantiable? = #f; // How can we get this? with-output-to-string (stream) open? & write(stream, "Open "); abstract? & write(stream, "Abstract "); primary? & write(stream, "Primary "); instantiable? & write(stream, "Instantiable "); end end method class-modifiers; define method generic-function-modifiers (project :: , function :: ) => (modifiers :: ) let modifiers = definition-modifiers(project, function); let open? = member?(#"open", modifiers); let dynamic? = member?(#"dynamic", modifiers); with-output-to-string (stream) open? & write(stream, "Open "); dynamic? & write(stream, "Dynamic "); end end method generic-function-modifiers;