namespace NemerleDoc { using System; using Nemerle.Collections; using System.Reflection; using System.Text.RegularExpressions; /// /// Contains common html headers and footers, generates and writes html to a file. /// internal module HtmlGenerator { internal debug (str : string, params arg : array [ object ]) : void { when (Nemerledoc.debug) Console.WriteLine(str, arg); } regExFunVoidNs : Regex = Regex( @"(?.*)Nemerle\.Builtins\.FunctionVoid`(?\d+)\[(?.*)\](?.*)", RegexOptions.Compiled); regExFunVoid : Regex = Regex( @"(?.*)FunctionVoid`(?\d+)\[(?.*)\](?.*)", RegexOptions.Compiled); regExFunNs : Regex = Regex( @"(?.*)Nemerle\.Builtins\.Function`(?\d+)\[[(?.*),](?[^,]+)\](?.*)", RegexOptions.Compiled); regExFun : Regex = Regex( @"(?.*)Function`(?\d+)\[(?.*)\](?.*)", RegexOptions.Compiled); regExTupleNs : Regex = Regex( @"(?.*)Nemerle.Builtins.Tuple`(?\d+)\[(?.*)\](?.*)", RegexOptions.Compiled); regExTuple : Regex = Regex( @"(?.*)Tuple`(?\d+)\[(?.*)\](?.*)", RegexOptions.Compiled); _reg_debug(co : string, text : string, m : Match) : void { debug("*** " + co + " *** {0}\n--> {1}\n--> {2}\n--> {3}", text, m.Result("${pref}"), m.Result("${arg}"), m.Result("${post}")) } /// /// Replaces some complicated functions to simpler ones. /// internal replace (text : string) : string { mutable res = text; res = res.Replace("System.String", "string"); res = res.Replace("System.Int32", "int"); res = res.Replace("System.Object", "object"); res = res.Replace("System.Boolean", "bool"); // first deal with FunctionVoid if (res.IndexOf("FunctionVoid") > -1) { // FunctionVoid with namespace (e.g. as argument) if (regExFunVoidNs.IsMatch(res)) { def resMatch = regExFunVoidNs.Match(res); def arg = replace(resMatch.Result("${arg}")); res = resMatch.Result("${pref}") + "(" + arg + ") -> void" + resMatch.Result("${post}"); } // FunctionVoid without namespace (e.g. as argument) else when (regExFunVoid.IsMatch(res)) { def resMatch = regExFunVoid.Match(res); def arg = replace(resMatch.Result("${arg}")); res = resMatch.Result("${pref}") + "(" + arg + ") -> void" + resMatch.Result("${post}"); } } // Function'... else if (res.IndexOf("Function") > -1) { // FunctionVoid with namespace (e.g. as argument) when (regExFunNs.IsMatch(res)) { def resMatch = regExFunNs.Match(res); def arg = replace(resMatch.Result("${arg}")); res = resMatch.Result("${pref}") + "(" + arg + ") -> void" + resMatch.Result("${post}"); } // Function without namespace (e.g. as argument) when (regExFun.IsMatch(res)) { def resMatch = regExFun.Match(res); def arg_list = replace(resMatch.Result("${arg}")); // last argument is a return type def commaPos = arg_list.LastIndexOf(','); mutable arg = ""; mutable ret = ""; if (commaPos > -1) { arg = arg_list.Substring(0, commaPos).Trim(); ret = arg_list.Substring(commaPos + 1); } else ret = arg_list; if (arg.Length == 0) arg = "void" else arg = "(" + arg + ")"; res = resMatch.Result("${pref}") + arg + " -> " + ret + " " + resMatch.Result("${post}"); } } // Tuple else when (res.IndexOf("Tuple") > -1) { // second deal with Nemerle.Builtins.Tuples* if (regExTupleNs.IsMatch(res)) { def resMatch = regExTupleNs.Match(res); def arg = resMatch.Result("${arg}"); def pref = resMatch.Result("${pref}"); def post = resMatch.Result("${post}"); res = pref + "(" + arg + ")" + post; } else when (regExTuple.IsMatch(res)) { def resMatch = regExTuple.Match(res); def arg = resMatch.Result("${arg}"); def pref = resMatch.Result("${pref}"); def post = resMatch.Result("${post}"); res = pref + "(" + arg + ")" + post; } } if (Nemerledoc.simplify) res else text } // replace /// /// Writes a html file. f is a function returns a body string. /// public Page (f : void -> string, fname : string) : void { def body = f(); def buf = System.Text.StringBuilder(); _ = buf.Append("\n"); _ = buf.Append("\n"); _ = buf.Append("\n"); _ = buf.Append("\n"); _ = buf.Append("" + Nemerledoc.title + "\n"); _ = buf.Append("\n"); _ = buf.Append("\n"); _ = buf.Append("\n"); _ = buf.Append("\n"); _ = buf.Append(body); _ = buf.Append("
Nemerle Documentation Project
"); _ = buf.Append("\n"); _ = buf.Append("\n"); // some refinements // replace(buf); _ = buf.Replace("&", "&"); def outf = IO.StreamWriter(Nemerledoc.destDir + fname); outf.Write(buf); outf.Close(); // Console.WriteLine("---> zapis do {0}", fname); } /// /// Generates a header of a page. /// public Title (subtitle : string) : string { mutable content = ""; content += "
"; content += "" + Nemerledoc.title + "
"; content += ""; content += subtitle; content += ""; content += "
\n\n"; content; } // the most common prefix, but without a digit mcp(a : string, b : string) : string { mutable p = 0; while (p < a.Length && p < b.Length && a[p] == b[p] && !Char.IsDigit(a[p])) ++p; a.Substring(0, p) } internal filteredIter (l : list [ Node ], cond : Node -> bool, iter : Node -> string) : string { // ctors to the beginning! def sort = fun (a : Node, b : Node) { // ctor(System.String)s are compared incorrectly, so use the prefix assert(a.true_name != null, "a.true_name must be not null"); assert(b.true_name != null, "b.true_name must be not null"); def comp_a = if (a.true_name.StartsWith(".ctor")) ".ctor" else if (a.true_name.StartsWith("ctor")) "ctor" else if (a.true_name.StartsWith("cctor")) "cctor" else a.true_name; def comp_b = if (b.true_name.StartsWith(".ctor")) ".ctor" else if (b.true_name.StartsWith("ctor")) "ctor" else if (b.true_name.StartsWith("cctor")) "cctor" else b.true_name; def r = match ((comp_a, comp_b)) { | (".ctor", "ctor") => -1 | ("ctor", ".ctor") => 1 | (".ctor", "cctor") => -1 | ("cctor", ".ctor") => 1 | ("ctor", "cctor") => -1 | ("cctor", "ctor") => 1 | (".ctor", _) => -1 | (_, ".ctor") => 1 | ("ctor", _) => -1 | (_, "ctor") => 1 | ("cctor", _) => -1 | (_, "cctor") => 1 | _ => def pref = mcp(a.true_name, b.true_name); def pref_l = pref.Length; mutable res = String.Compare(a.true_name, b.true_name); when (pref_l > 0 && a.true_name.Length > pref_l && b.true_name.Length > pref_l && Char.IsDigit(a.true_name[pref_l]) && Char.IsDigit(b.true_name[pref_l])) { // comp 't2' with 't11' def red_a = a.true_name.Substring(pref_l); def red_b = b.true_name.Substring(pref_l); // Console.WriteLine("***\n\t{0}\n\t{1}", red_a, red_b); def regEx = @"(?\d+)(?.*)"; def rePref = Regex(regEx, RegexOptions.Compiled); def a_match = rePref.Match(red_a); def b_match = rePref.Match(red_b); when (a_match != null && b_match != null) { def a_num = Int32.Parse(a_match.Result("${num}")); def b_num = Int32.Parse(b_match.Result("${num}")); when (a_num != b_num) res = a_num - b_num; } } res } r; }; // first sort the list def l1 = Nemerle.Collections.List.Sort(l, sort); // foreach (x in l1) Console.WriteLine(x.name); mutable res = ""; foreach (e in l1) when (cond(e)) res += iter(e); res; } } // module htmlgenerator /// /// Type of an element, set by XML parser (see: T:, M:, F: elements) /// public variant ElementType { | Unknown | Property | Method | Field | Event | Type } /// /// Records attributes dragged from assemblies by reflection /// [Record] sealed class ReflAttribs { internal is_interface : bool; internal is_abstract : bool; internal is_class : bool; internal is_array : bool; internal attr : System.Reflection.TypeAttributes; internal Private : bool { // get { (attr & TypeAttributes.NotPublic != 0) || (attr & TypeAttributes.NestedPrivate != 0) } get { (attr & TypeAttributes.Public == 0) } } } // Atributes /// /// Top node of a tree. It must be always a namespace, it is a root namespace. /// public class TopNode { // it is a list of elements internal mutable elements : list [ Node ] = []; /// An anchor ref, used in html generation public virtual href () : string { this.ToString() + this.GetHashCode().ToString() } /// Returns the name of a html file which includes a description of the current element internal virtual html_file() : string { "index.html" } internal mutable attribute : ReflAttribs; internal mutable Superclass : System.Type; internal mutable Interfaces : array [ System.Type ]; // attributes dragged out from XML file internal mutable comment : string = ""; internal mutable remark : string = ""; internal mutable return : string = ""; internal mutable param : string = ""; internal mutable example : string = ""; internal mutable exception : string = ""; internal mutable permission : string = ""; /// /// Given list of elements, it creates a div block in the form of a table of content. /// /// Used in index.html internal listOfContent (elements : list [ Node ], ns : string, publicOnly : bool) : string { mutable res = ""; res += "
\n"; res += "" + (if (ns.Length == 0) "Root namespace" else "Namespace " + ns) +"\n"; def iter = fun (e : Node) { def ahref = match (e.XMLattrib) { | Unknown => "#" + e.href() | _ => e.html_file() + "#" + e.href() }; mutable r = ""; r += "
"; r += match (e.XMLattrib) { | Type => "class" | Unknown => "namespace" | _ => e.XMLattrib.ToString() }; r += " "; r += "" + e.Name + ""; r += if (comment.Length > 0) "
Comment: " + comment + "
" else ""; r += if (remark.Length > 0) "
Remark: " + remark + "
" else ""; r += "
\n"; r } // do TOC in the following order: first ordered namespaces, then ordered classes // def sort = fun (x, y) { String.Compare(x.true_name, y.true_name) }; def cond = fun (n : Node) { (!publicOnly || (n.attribute == null || !n.attribute.Private)) && (n.XMLattrib.Equals(ElementType.Type()) || n.XMLattrib.Equals(ElementType.Unknown())) } def class_cond = fun (n : Node) { n.XMLattrib.Equals(ElementType.Type()) && cond(n) } def ns_cond = fun (n : Node) { n.XMLattrib.Equals(ElementType.Unknown()) && cond(n) } // def class_list = List.Sort(List.RevFilter(elements, fun (cl) { cl.XMLattrib.Equals(ElementType.Type() ) }), sort); def class_part = HtmlGenerator.filteredIter(elements, class_cond, iter); def ns_part = HtmlGenerator.filteredIter(elements, ns_cond, iter); res += ns_part + class_part + "
\n"; res } /// Creates body of TOC for the current namespace. The current node is /// always a namespace. /// Used in index.html internal virtual ToIndex (publicOnly : bool) : string { // first group types in the root namespace mutable content = ""; mutable is_root_ns = false; foreach (e in elements) when (e.XMLattrib.Equals(ElementType.Type())) is_root_ns = true; // add elements in root when (is_root_ns) { content += listOfContent(this.elements, "", publicOnly); def filter = fun (e) { !e.XMLattrib.Equals(ElementType.Unknown()) && (!publicOnly || (e.attribute == null || !e.attribute.Private)) }; content += HtmlGenerator.filteredIter(this.elements, filter, fun (e) { e.ToHtml() }); } // create toc for nested namespaces recursively def filter = fun (e : Node) { e.XMLattrib.Equals(ElementType.Unknown()) } content += HtmlGenerator.filteredIter(this.elements, filter, fun(e : Node) { e.ToIndex(publicOnly) }); // foreach (e in elements) when () content } /// /// This method is called for each 'namespace' element of the tree, what results in /// in a html file for each namespace. /// public virtual createPages (publicOnly : bool) : void { foreach (e in elements) when (e.XMLattrib.Equals(ElementType.Unknown())) e.createPages(publicOnly); } /// Add comment to the current element public Comment(str : string) : void { this.comment += str; } /// Add remark to the current element public Remark(str : string) : void { this.remark += str; } /// Add return info to the current element public Return(str : string) : void { this.return += str; } /// Add param info to the current element public Param(str : string) : void { this.param += str; } /// Add example to the current element public Example(str : string) : void { this.example += str; } /// Add exception description to the current element public Exception(str : string) : void { this.exception += str; } /// Add permission description to the current element public Permission(str : string) : void { this.permission += str; } mutable internal seealso : string; internal SeeAlso(name : string) : void { this.seealso = name; } internal postAnalysis () : void { foreach (elem in elements) elem.postAnalysis() } internal mutable datatree : DataTree; internal this (dt : DataTree) { this.datatree = dt; } internal this () {} } // class TopNode /// /// Represents a 'concrete' (i.e. classes, fields, methods etc.) elements. /// public class Node : TopNode { internal mutable parent : TopNode; /// A type of of a node. /// This field is set by XML analyzer public mutable XMLattrib : ElementType = ElementType.Unknown(); /// prefix (i.e. namespaces.classes.etc) mutable prefix : string = ""; /// True (e.g. monster name with Tuple20) of the element mutable public true_name : string; /// Full name of the element (with namespace path) public full_name : string { get { (if (this.prefix.Length > 0) this.prefix + "." else "") + this.true_name }}; // after some face_lifting mutable lifted_name : string; public Name : string { get { when (lifted_name == null) lifted_name = HtmlGenerator.replace(true_name) ; lifted_name } } /// An anchor ref, used in html generation public override href () : string { def res = if (XMLattrib.Equals(ElementType.Unknown())) this.ToString() + this.GetHashCode().ToString() else "id" + this.GetHashCode().ToString(); // Console.WriteLine("Element {0}, hash-id={1}", true_name, res); res } /// Returns the name of a file including description of the current node internal override html_file (): string { if (this.XMLattrib.Equals(ElementType.Unknown())) this.full_name + ".html" else this.parent.html_file() } /// If the current node is a namespace, it creates a table of content. /// Used in index.html internal override ToIndex (publicOnly : bool) : string { mutable content = ""; when (this.XMLattrib.Equals(ElementType.Unknown())) { // self-explanation content += listOfContent(this.elements, this.full_name, publicOnly); def filter = fun (e : Node) { e.XMLattrib.Equals(ElementType.Unknown()) } content += HtmlGenerator.filteredIter(elements, filter, fun(e : Node) { e.ToIndex(publicOnly) }); } content; } /// Creates a html page for the current namespace public override createPages (publicOnly : bool) : void { // Console.WriteLine("Zapis pliku {0}", this); // crreates a html page for the current namespace when (this.XMLattrib.Equals(ElementType.Unknown())) { def fname = this.full_name; mutable content = ""; content += HtmlGenerator.Title("Namespace " + fname); def filter (e) { mutable priv = false; when (e.attribute != null) priv = e.attribute.Private; !publicOnly || !priv } content += HtmlGenerator.filteredIter(this.elements, filter, fun (e) { e.ToHtml() }); HtmlGenerator.Page ( fun () { content }, this.html_file ()); } // creates a html page for each sub namespace foreach (e in elements) when (e.XMLattrib.Equals(ElementType.Unknown())) e.createPages(publicOnly); } internal new postAnalysis () : void { // first, fix the following problem: there exist references, e.g. Nemerle.Builtins.Function.apply, // where Nemerle.Builtins is a namespace, Function - class, and apply - method. // but there is no class declaration. It makes then problems. when (this.XMLattrib.Equals(ElementType.Unknown())) foreach (elem in this.elements) when (elem.XMLattrib.Equals(ElementType.Method())) { // this must be a type this.XMLattrib = ElementType.Type(); // Console.WriteLine("Fixed {0}, assigned for {1}", elem.full_name, this.full_name); // Console.WriteLine((next.parent :> Node).XMLattrib); } // now find reference for seealso tag when (this.datatree.seealsoDict != null) { // find a reference mutable key = null; foreach (kV in this.datatree.seealsoDict) when (this.true_name.StartsWith(kV.Key)) key = kV.Key; when (key != null) { // Console.WriteLine("Dodanie do klucza" + key); this.datatree.seealsoDict[key] = this; } } foreach (elem in elements) elem.postAnalysis() } public this(name : string, prefiks : string, parent : TopNode) { assert (name != null, "nazwa elementu nie może być 'null'"); assert (name.Trim().Length > 0, "nazwa elementu powinna być niepusta"); assert (prefiks != null, "prefiks nie może być 'null'"); assert (parent != null, "parent nie może być 'null'"); this.true_name = name; this.prefix = prefiks; this.parent = parent; this.datatree = parent.datatree; } /// Create a full html description of the current node. public ToHtml () : string { // Console.WriteLine("true_name {0}, name {1}, prefix {2}", true_name, this.Name, this.prefix ); mutable res = ""; mutable com = if (comment.Length > 0) "
" + comment + "
\n" else ""; com += if (remark.Length > 0) "
Remark: " + remark + "
\n" else ""; com += if (return.Length > 0) "
Return: " + return + "
\n" else ""; com += if (param.Length > 0) "
Parameter: " + param + "
\n" else ""; com += if (example.Length > 0) "
Example:
" + example + "
\n" else ""; com += if (exception.Length > 0) "
Exception:
" + exception + "
\n" else ""; com += if (permission.Length > 0) "
Permission:
" + permission + "
\n" else ""; // resolve 'seealso' when (this.seealso != null && this.seealso.Length > 0) { com += "
See also "; def refTo = this.datatree.seealsoDict[this.seealso]; if (this.datatree.seealsoDict.Contains(this.seealso) && refTo != null) { def ahref = (if (this.html_file().Equals(refTo.html_file())) "" else refTo.html_file()) + "#" + refTo.href (); com += "" + this.seealso + "" } else { com += this.seealso; Console.WriteLine("*** Warning: 'seealso' reference '{0}' cannot be resolved", this.seealso); } com += "
\n"; } mutable att = ""; when (attribute != null) { when ( (attribute.attr & TypeAttributes.NotPublic) != 0) att += " notpublic "; when ( (attribute.attr & TypeAttributes.Sealed) != 0) att += " sealed "; // when ( attribute.Private) att += " PRIVATE "; when (attribute.is_abstract) att += " abstract "; when ( (attribute.attr & TypeAttributes.NestedPublic) != 0) att += " nested public class "; when (attribute.is_class && att.IndexOf("class") == -1) att += " class "; when ( (attribute.attr & TypeAttributes.Public) != 0 && att.IndexOf("public") == -1) att += " public "; when (attribute.is_array) att += " array "; when (attribute.is_interface) att += " interface "; // last chance when (att.Length == 0) att = attribute.attr.ToString(); } when (this.XMLattrib != null && this.XMLattrib.Equals(ElementType.Type()) && att.IndexOf("class") == -1) att += " class "; mutable superclass = ""; when (this.Superclass != null) superclass = " : " + String.Format("{1}", this.Superclass.ToString(), this.Superclass.Name); mutable interfaces = " "; when (this.Interfaces != null) { foreach (interf in this.Interfaces) interfaces += interf.ToString() + " "; } match (XMLattrib) { | Unknown => res += "
Unknown element " + this.full_name + "
"; | Property => res += "" + att + this.Name + "" + com; | Method => res += "" + att + this.Name + "" + com; | Field => res += att + this.Name + com; | Event => res += att + this.Name + com; | Type => res += "
" + att; res += "" + this.Name + "" + superclass + "\n"; when (interfaces.Trim().Length > 0) res += " implements " + interfaces + "\n"; res += com; def mk_element = fun (e) { "
" + e.ToHtml() + "
\n"}; def mk_type = fun (e) { "
" + e.ToHtml() + "
\n"}; def methods = HtmlGenerator.filteredIter(elements, fun (e) { e.XMLattrib.Equals(ElementType.Method()) }, mk_element ); when (methods.Length > 0) res += "
Methods:" + methods + "
"; def events = HtmlGenerator.filteredIter(elements, fun (e) { e.XMLattrib.Equals(ElementType.Event()) }, mk_element ); when (events.Length > 0) res += "
Events:" + events + "
"; def props = HtmlGenerator.filteredIter(elements, fun (e) { e.XMLattrib.Equals(ElementType.Property()) }, mk_element); when (props.Length > 0) res += "
Properties:" + props + "
"; def fields = HtmlGenerator.filteredIter(elements, fun (e) { e.XMLattrib.Equals(ElementType.Field()) }, mk_element); when (fields.Length > 0) res += "
Fields:" + fields + "
"; def types = HtmlGenerator.filteredIter(elements, fun (e) { e.XMLattrib.Equals(ElementType.Type()) }, mk_type); when (types.Length > 0) res += "
Types:" + types + "
"; res += "
\n"; } res } // method ToHtml } // class Node /// /// The class DataTree is a front-end for other modules which analyse input files. /// class DataTree { split (str : string) : char*string { (str[0], str.Substring(2)) } // top node of the tree mutable tree : TopNode; // recently added or processed node. mutable currentNode : Node; // list of the sources mutable sources : list [ string ] = []; public this () { this.tree = TopNode(this); } ///Creates a string (html) representation of the sources of the program public sourcesToString () : string { mutable res = ""; res += match (sources.Length) { | 0 => "No sources?" | 1 => "Source: " | _ => "Sources: " } when (sources.Length > 0) { res += List.Head(sources); def r = List.Tail(sources); foreach (e in r) res += ", " + e; } res } /// Adds info about a file name being the current input public AddSource(src : string) : void { sources += [ src ] } smart_strip1(path : string) : list [ string ] { smart_strip(path, '(') } /// Strip, but avoid stripping '[' char smart_strip2(path : string) : list [ string ] { smart_strip(path, '[') } smart_strip(path : string, sep : char) : list [ string ] { // first split into name and parameters def par_pos = path.IndexOf(sep); def path_name = if (par_pos != -1) path.Substring(0, par_pos) else path; def param = if (par_pos != -1) path.Substring(par_pos) else ""; // Console.WriteLine("{0} = ({1},{2})", path, path_name, param); mutable token_list = Nemerle.Collections.List.FromArray(path_name.Split(array ['.', '+'])); mutable res = []; // analyze name while (token_list.Length > 1) { mutable r = List.Hd(token_list); // when not .., i.e. ctor when (r.Length != 0) { res += [ r ]; // Console.WriteLine("<-- " + r); } when (token_list.Length > 0) token_list = List.Tl(token_list) } // while () def last = List.Hd(token_list); def last_token = if (par_pos > -1) (last + param) else last; res += [ last_token ]; res } // From XML, names are with arguments, but from assembly without, so // we have to compare private equal_names(x : string, y : string) : bool { mutable res = x.Equals(y); when (!res && x.Length != y.Length) { def patt = ['(', '[']; when (x.StartsWith(y) && patt.Contains(x[y.Length])) res = true; when (y.StartsWith(x) && patt.Contains(y[x.Length])) res = true; // when (!res && (x.StartsWith(y) || y.StartsWith(x))) Console.WriteLine("Not equals {0}<>{1}", x, y); } // when (res && x.Length != y.Length) Console.WriteLine("Considered equal names: {0}={1}", x, y); res; } memb (set : TopNode, name : string) : Node { mutable res = null; foreach (e in set.elements) // when (name.Equals(e.name)) res = e; when (equal_names(e.true_name, name)){ res = e; when (name.Length > e.true_name.Length) e.true_name = name; } res; } /// /// Adds a new element (typically a class) to the tree. Used by assembly analyzer. /// public AddItem(str : string, ty : ElementType, attr : ReflAttribs, superclass : System.Type, interfaces : array [ System.Type ]) : void { def path = smart_strip2(str); // Console.WriteLine("Ścieżka {0}", str); // foreach (x in path) Console.WriteLine("--> {0}", x); mutable pointer = tree; mutable next; foreach (edge in path) { // Console.WriteLine("--> podścieżka " + edge); next = memb(pointer, edge); // if there are two 'equal' names, e.g. Main and Main(srting[]) // when (next != null && edge.Length > next.name.Length) next.name = edge; when (next == null) { def pref = if (pointer is Node) ((pointer :> Node).full_name) else ""; next = Node(edge, pref, pointer); pointer.elements = pointer.elements + [ next ]; } pointer = next; } pointer.attribute = attr; next.XMLattrib = ty; pointer.Superclass = superclass; pointer.Interfaces = interfaces; } // AddItem /// /// Adds a new element (a member of a class) to the tree. Used by assembly analyzer. /// public AddItem(ns_path : string, typename : string, ty : ElementType) : void { def path = smart_strip2(ns_path) + [ typename ]; // Console.WriteLine("Ścieżka {0}, typename {1}, type: {2}", ns_path, typename, ty); // foreach (x in path) Console.WriteLine("*** " + x); mutable pointer = tree; mutable next; foreach (edge in path) { // Console.WriteLine("--> podścieżka " + edge); next = memb(pointer, edge); when (next == null) { def prefix = if (pointer is Node) ((pointer :> Node).full_name ) else ""; next = Node(edge, prefix, pointer); pointer.elements = pointer.elements + [ next ]; } pointer = next; } next.XMLattrib = ty; } /// /// Add a new element to the tree. An argument is a string consisting of /// a stringified declaration of an element. Used by the XML analyzer. /// public AddItem (str : string) : void { // System.Console.WriteLine("---> " + str); def (tySy, path) = split(str); // System.Console.WriteLine("---> split({0}) = ({1}, {2})", str, tySy, path); def ty = match (tySy) { | 'T' => ElementType.Type(); | 'F' => ElementType.Field(); | 'M' => ElementType.Method(); | 'P' => ElementType.Property() | 'E' => ElementType.Event() | _ => Console.WriteLine("*** Warning: the value '{0}' of the attribute 'name' is not supported", tySy); ElementType.Unknown() } def pathList = smart_strip1(path); // Console.WriteLine("Path to strip: {0}", path); // foreach (n in pathList) Console.WriteLine("--> {0}", n); mutable pointer = tree; mutable next; foreach (edge in pathList) { next = memb(pointer, edge); when (next == null) { def pref = if (pointer is Node) ((pointer :> Node).full_name) else ""; next = Node(edge, pref, pointer); pointer.elements = pointer.elements + [ next ]; } pointer = next; } currentNode = next; currentNode.XMLattrib = ty; // Console.WriteLine("Added {0} {1}", tree.current.full_name, tree.current.elemType); } public AddComment (str : string) : void { currentNode.Comment(str); } public AddRemark (str : string) : void { currentNode.Remark(str); } public AddReturn (str : string) : void { currentNode.Return(str); } public AddParam (str : string) : void { currentNode.Param(str); } public AddExample (str : string) : void { currentNode.Example(str); } public AddException (str : string) : void { currentNode.Exception(str); } public AddPermission (str : string) : void { currentNode.Permission(str); } // neccessary for 'seealso' mutable internal seealsoDict : Nemerle.Collections.Hashtable[string, TopNode]; public AddSeeAlso(name : string) : void { when (seealsoDict == null) seealsoDict = Nemerle.Collections.Hashtable(); seealsoDict[name] = null; currentNode.SeeAlso(name); } // creates a TOC index_content (publicOnly : bool) : string { mutable content = ""; content += HtmlGenerator.Title(this.sourcesToString()); // teraz zawartość content += tree.ToIndex(publicOnly); content; } /// public ToHtml (publicOnly : bool) : void { tree.postAnalysis(); // foreach ((k,v) in seealsoDict.KeyValuePairs) Console.WriteLine("({0}, {1}", k, v); HtmlGenerator.Page(fun () { index_content(publicOnly) }, "index.html"); tree.createPages(publicOnly); } } // class DataTree } // namespace NemerleDoc