sync
authorAlan Knowles <alan@akbkhome.com>
Thu, 22 Jul 2010 08:59:35 +0000 (16:59 +0800)
committerAlan Knowles <alan@akbkhome.com>
Thu, 22 Jul 2010 08:59:35 +0000 (16:59 +0800)
JSDOC/DocComment.js [new file with mode: 0644]
JSDOC/DocTag.js [new file with mode: 0644]
JSDOC/Parser.js [new file with mode: 0644]
JSDOC/Symbol.js [new file with mode: 0644]
JSDOC/SymbolSet.js [new file with mode: 0644]
JSDOC/Walker2.js [new file with mode: 0644]

diff --git a/JSDOC/DocComment.js b/JSDOC/DocComment.js
new file mode 100644 (file)
index 0000000..452ce3c
--- /dev/null
@@ -0,0 +1,232 @@
+//<Script type="text/javascript">
+
+XObject = imports.XObject.XObject;
+
+DocTag = imports.DocTag.DocTag;
+
+/**
+ * Create a new DocComment. This takes a raw documentation comment,
+ * and wraps it in useful accessors.
+ * @class Represents a documentation comment object.
+ * 
+ */ 
+
+DocComment = XObject.define(
+
+    function(/**String*/comment) {
+        this.isUserComment = true;
+        this.src           = "";
+        this.meta          = "";
+        this.tagTexts      = [];
+        this.tags          = []; // array of doctags..
+        if (typeof comment != "undefined") {
+            this.parse(comment);
+        }
+    }, 
+    Object, // extends
+    {
+        isUserComment : true,
+        src           : "",
+        meta          : "",
+        tagTexts      : [],
+        tags          : [],     
+    
+        /**
+         * serialize..
+         */
+        toJSON :function(t)
+        {
+            
+            var ret = { '*object' : 'DocComment' };
+            
+            var _this = this;
+            ['isUserComment','src', 'meta',  'tags'].forEach(function(k) {
+                ret[k] = _this[k];
+            })
+            
+            return ret;
+        },    
+        /**
+        * @requires JSDOC.DocTag
+        */
+        parse : function(/**String*/comment) {
+            if (comment == "") {
+                comment = "/** @desc */";
+                this.isUserComment = false;
+                
+            }
+            
+            this.src = DocComment.unwrapComment(comment);
+            
+            //println(this.src);
+            
+            
+            this.meta = "";
+            if (this.src.indexOf("#") == 0) {
+                this.src.match(/#(.+[+-])([\s\S]*)$/);
+                if (RegExp.$1) this.meta = RegExp.$1;
+                if (RegExp.$2) this.src = RegExp.$2;
+            }
+            this.hasTags = true;
+            if (!/^\s*@\s*\S+/m.test(this.src)) {
+                this.isUserComment = false;
+                this.hasTags = false;
+                
+                //return;
+            }
+            this.fixDesc();
+            
+            //if (typeof JSDOC.PluginManager != "undefined") {
+            //    JSDOC.PluginManager.run("onDocCommentSrc", this);
+            //}
+            
+            this.src = DocComment.shared+"\n"+this.src;
+            this.tags = [];
+            this.tagTexts = [];
+            
+            
+           
+            this.tagTexts = 
+                this.src
+                .split(/(^|[\r\n])\s*@/)
+                .filter(function($){return $.match(/\S/)});
+            
+            //println(this.tagTexts.toSource());
+            // fix tagText
+            
+            
+            
+            /**
+                The tags found in the comment.
+                @type JSDOC.DocTag[]
+             */
+             
+            this.tags = this.tagTexts.map(function($){return new DocTag($)});
+            
+            //println(this.tags.toSource());
+            this.tagTexts = []; // we dont need to store this..
+            
+            
+            //if (typeof JSDOC.PluginManager != "undefined") {
+            //     JSDOC.PluginManager.run("onDocCommentTags", this);
+            //}
+        },
+         
+
+        /**
+            If no @desc tag is provided, this function will add it.
+         */
+        fixDesc : function() {
+            if (this.meta && this.meta != "@+") return;
+            
+            
+            
+            // does not have any @ lines..
+            // -- skip comments without @!!
+            if (!/^\s*@\s*\S+/.test(this.src)) {
+                this.src = "@desc "+this.src;
+                // TAGS that are not \n prefixed!! ...
+                this.src = this.src.replace(/@\s*type/g, '\n@type'); 
+            
+                return;
+            }
+            // kdludge for stuff...
+            //this.src = this.src.replace(/@\s*type/g, '\n@type'); 
+            
+            // only apply @desc fix to classes..
+            if (!/\s*@(class|event|property)/m.test(this.src) ) {
+                return;
+            }
+            // if no desc - add it on the first line that is not a @
+            var lines = this.src.split("\n");
+            var nsrc = '';
+            var gotf = false;
+            
+            for(var i =0; i < lines.length;i++) {
+                var line = lines[i];
+                if (gotf) {
+                    nsrc += line + "\n";
+                    continue;
+                }
+                if (/^\s*[@\s]/.test(line)) { // line with @
+                    nsrc += line + "\n";
+                    continue;
+                }
+                gotf = true;
+                nsrc += '@desc ' + line + "\n";
+                
+            }
+             
+            this.src = nsrc;
+            
+            
+            
+        },
+      
+    /**
+        Provides a printable version of the comment.
+        @type String
+     */
+        toString : function() {
+            return this.src;
+        },
+
+    /*~t
+        assert("testing JSDOC.DocComment#fixDesc");
+        var com = new JSDOC.DocComment();
+        com.src = "foo";
+        assertEqual(""+com, "foo", "stringifying a comment returns the unwrapped src.");
+    */
+
+    /**
+        Given the title of a tag, returns all tags that have that title.
+        @type JSDOC.DocTag[]
+     */
+     /*
+     
+        toQDump : function(t)
+        {
+            //println(t.toSource());
+            var r =  JSDOC.toQDump(t, 'JSDOC.DocComment.fromDump({', '})', {}); // send it an empty object..
+            //println(r);
+            return r;
+        } ,
+        */
+     
+        getTag : function(/**String*/tagTitle) {
+            return this.tags.filter(function($){return (typeof($['title']) != 'undefined') && ($.title == tagTitle)});
+        }
+        
+});
+
+
+/// static methods..
+
+XObject.extend(DocComment, 
+    {
+        
+        /**
+         * Used to store the currently shared tag text.
+         */
+        shared : "",
+        
+        /**
+         * Remove slash-star comment wrapper from a raw comment string.
+         *  @type String
+         */
+        unwrapComment : function(/**String*/comment) {
+            if (!comment) return "";
+            var unwrapped = comment.replace(/(^\/\*\*|\*\/$)/g, "").replace(/^\s*\* ?/gm, "");
+            return unwrapped;
+        },
+
+        fromDump : function(t)
+        {
+            var ns = new DocComment();
+            for (var i in t) {
+                ns[i] = t[i];
+            }
+            return ns;
+        }
+});
\ No newline at end of file
diff --git a/JSDOC/DocTag.js b/JSDOC/DocTag.js
new file mode 100644 (file)
index 0000000..692d1f4
--- /dev/null
@@ -0,0 +1,228 @@
+//<script  type="text/javascript">
+XObject = imports.XObject.XObject;
+
+Options = imports.Options.Options;
+
+/**
+ * DocTag - represents a single A=b tag.
+ * @class DocTag
+ */
+DocTag = XObject.define(
+
+/**
+ * @constructor
+ * @arg {String} src
+ */
+
+    function(src) {
+        this.title        = "";
+        this.type         = "";
+        this.name         = "";
+        this.isOptional   = false;
+        this.defaultValue = "";
+        this.desc         = "";
+        if (typeof src != "undefined") {
+            this.parse(src);
+        }
+    }, 
+    Object,
+    {
+        
+        title: '',
+        type: '',
+        name : '',
+        isOptional : false,
+        defaultValue : '',
+        desc : '',
+        /**
+         * serialize..
+         */
+        toJSON :function(t)
+        {
+            var ret = { '*object' : 'DocTag' };
+            
+            for (var i in this) {
+                switch (typeof(this[i])) {
+                    case 'function':
+                       continue;
+                       continue;
+                        
+                    case 'string':
+                    case 'number':
+                    case 'boolean':                    
+                        ret[i] = this[i]; continue;
+                    default:
+                        print("unknown type:" + typeof(this[i]));
+                        Seed.quit();
+                   }
+            }
+            return ret;
+        },
+        
+
+
+        /**
+            Populate the properties of this from the given tag src.
+            @param {string} src
+         */
+        parse : function(src) {
+            if (typeof src != "string") throw "src must be a string not "+(typeof src);
+
+            try {
+                src = this.nibbleTitle(src);
+                //if (JSDOC.PluginManager) {
+                //    JSDOC.PluginManager.run("onDocTagSynonym", this);
+               // }
+                
+                src = this.nibbleType(src);
+                
+                // only some tags are allowed to have names.
+                if (this.title == "param" || this.title == "property" || this.title == "cfg") { // @config is deprecated
+                    src = this.nibbleName(src);
+                }
+            }
+            catch(e) {
+                if (Options.LOG) Options.LOG.warn(e);
+                else throw e;
+            }
+            this.desc = src; // whatever is left
+            
+            // example tags need to have whitespace preserved
+            if (this.title != "example") this.desc = this.desc.trim();
+            
+            //if (JSDOC.PluginManager) {
+            //    JSDOC.PluginManager.run("onDocTag", this);
+            //}
+        },
+
+        /**
+            Automatically called when this is stringified.
+         */
+        toString : function() {
+            return this.desc;
+        },
+         
+
+        /**
+            Find and shift off the title of a tag.
+            @param {string} src
+            @return src
+         */
+        nibbleTitle : function(src) {
+            if (typeof src != "string") throw "src must be a string not "+(typeof src);
+            
+            var parts = src.match(/^\s*(\S+)(?:\s([\s\S]*))?$/);
+
+            if (parts && parts[1]) this.title = parts[1];
+            if (parts && parts[2]) src = parts[2];
+            else src = "";
+            
+            return src;
+        },
+         
+        /**
+            Find and shift off the type of a tag.
+            @requires frame/String.js
+            @param {string} src
+            @return src
+         */
+        nibbleType : function(src) 
+        {
+            if (typeof src != "string") throw "src must be a string not "+(typeof src);
+            
+            if (src.match(/^\s*\{/)) {
+                var typeRange = this.balance(src,"{", "}");
+                if (typeRange[1] == -1) {
+                    throw "Malformed comment tag ignored. Tag type requires an opening { and a closing }: "+src;
+                }
+                this.type = src.substring(typeRange[0]+1, typeRange[1]).trim();
+                this.type = this.type.replace(/\s*,\s*/g, "|"); // multiples can be separated by , or |
+                src = src.substring(typeRange[1]+1);
+            }
+            
+            return src;
+        },
+         
+
+        /**
+            Find and shift off the name of a tag.
+            @requires frame/String.js
+            @param {string} src
+            @return src
+         */
+        nibbleName : function(src) {
+            if (typeof src != "string") throw "src must be a string not "+(typeof src);
+            
+            src = src.trim();
+            
+            // is optional?
+            if (src.charAt(0) == "[") {
+                var nameRange = this.balance(src,"[", "]");
+                if (nameRange[1] == -1) {
+                    throw "Malformed comment tag ignored. Tag optional name requires an opening [ and a closing ]: "+src;
+                }
+                this.name = src.substring(nameRange[0]+1, nameRange[1]).trim();
+                this.isOptional = true;
+                
+                src = src.substring(nameRange[1]+1);
+                
+                // has default value?
+                var nameAndValue = this.name.split("=");
+                if (nameAndValue.length) {
+                    this.name = nameAndValue.shift().trim();
+                    this.defaultValue = nameAndValue.join("=");
+                }
+            }
+            else {
+                var parts = src.match(/^(\S+)(?:\s([\s\S]*))?$/);
+                if (parts) {
+                    if (parts[1]) this.name = parts[1];
+                    if (parts[2]) src = parts[2].trim();
+                    else src = "";
+                }
+            }  
+
+            return src;
+        },
+        
+        balance : function(str, open, close) {
+            var i = 0;
+            while (str.charAt(i) != open) {
+                if (i == str.length) return [-1, -1];
+                i++;
+            }
+            
+            var j = i+1;
+            var balance = 1;
+            while (j < str.length) {
+                if (str.charAt(j) == open) balance++;
+                if (str.charAt(j) == close) balance--;
+                if (balance == 0) break;
+                j++;
+                if (j == str.length) return [-1, -1];
+            }
+            
+            return [i, j];
+}
+
+        
+        
+});
+
+// cached support?
+DocTag.fromDump = function(t)
+{
+    var ns = new DocTag();
+    for (var i in t) {
+        if (typeof(ns[i]) == "undefined") {
+            println("ERR:no default for DocTag:"+ i);
+        }
+       ns[i] = t[i];
+    }
+    return ns;
+}
diff --git a/JSDOC/Parser.js b/JSDOC/Parser.js
new file mode 100644 (file)
index 0000000..e814263
--- /dev/null
@@ -0,0 +1,208 @@
+//<script type="text/javascript">
+
+Walker2      = imports.Walker2.Walker2;
+Symbol      = imports.Symbol.Symbol;
+SymbolSet      = imports.SymbolSet.SymbolSet;
+DocComment  = imports.DocComment.DocComment;
+Options     = imports.Options.Options;
+/**
+ * Parser is a static  instance..
+ * 
+ * 
+ */
+Parser = {
+       conf: { 
+        loaded: false 
+    },
+    
+    walker : false, // will be JSDOC.Walker()
+    symbols : false, //will be JSDOC.SymbolSet()
+    
+    filesSymbols : { },
+    
+    /** 
+    * global init once 
+    * 
+    */
+         
+    init: function() {
+        if (this.conf.loaded) {
+            return;
+        }
+        //print("init parser conf!?");
+        this.conf = {
+            loaded : true,
+            //ignoreCode:                 Options.n,
+            ignoreAnonymous:           true, // factory: true
+            treatUnderscoredAsPrivate: true, // factory: true
+            explain:                   false // factory: false
+        };
+         
+               this.symbols = new  SymbolSet();
+               //this.walker = new JSDOC.Walker();
+        //JSDOC.Parser.filesSymbols = {};
+       },
+
+
+
+    /**
+     * Parse a token stream.
+     * @param {JSDOC.TokenStream} token stream
+     * @param {String} filename 
+         
+     */
+    
+    
+    parse : function(ts, srcFile) 
+    {
+        this.init();
+        
+        
+        // not a nice way to set stuff...
+        
+        Symbol.srcFile = (srcFile || "");
+        DocComment.shared = ""; // shared comments don't cross file boundaries
+        
+       
+        
+        
+        
+        this.filesSymbols[Symbol.srcFile] = new SymbolSet();
+        
+        //Options.LOG.inform("Parser - run walker");
+        this.walker = new  Walker2(ts);
+        this.walker.buildSymbolTree();
+        
+        
+        
+        //this.walker.walk(ts); // adds to our symbols
+       // throw "done sym tree";
+        //Options.LOG.inform("Parser - checking symbols");
+        // filter symbols by option
+        for (p in this.symbols._index) {
+            var symbol = this.symbols.getSymbol(p);
+            
+           // print(JSON.stringify(symbol, null,4));
+            
+            if (!symbol) continue;
+            
+            if (symbol.isPrivate) {
+                this.symbols.deleteSymbol(symbol.alias);
+                continue;
+            }
+            
+            if (symbol.is("FILE") || symbol.is("GLOBAL")) {
+                continue;
+            }
+            //else if (!Options.a && !symbol.comment.isUserComment) {
+                //print("Deleting Symbols (no a / user comment): " + symbol.alias);
+                //this.symbols.deleteSymbol(symbol.alias);
+                //this.filesSymbols[Symbol.srcFile].deleteSymbol(symbol.alias);
+            //}
+            
+            if (/#$/.test(symbol.alias)) { // we don't document prototypes - this should not happen..
+                // rename the symbol ??
+                /*if (!this.symbols.getSymbol(symbol.alias.substring(0,symbol.alias.length-1))) {
+                    // rename it..
+                    print("Renaming Symbol (got  a #): " + symbol.alias);
+                    var n = '' + symbol.alias;
+                    this.symbols.renameSymbol( n ,n.substring(0,n-1));
+                    this.filesSymbols[Symbol.srcFile].renameSymbol( n ,n.substring(0,n-1));
+                    continue;
+                }
+                */
+                print("Deleting Symbols (got  a #): " + symbol.alias);
+                
+                this.symbols.deleteSymbol(symbol.alias);
+                this.filesSymbols[Symbol.srcFile].deleteSymbol(symbol.alias);
+            
+            }
+        }
+        //print(prettyDump(toQDump(this.filesSymbols[Symbol.srcFile]._index,'{','}')));
+        //print("AfterParse: " + this.symbols.keys().toSource().split(",").join(",\n   "));
+        return this.symbols.toArray();
+    },
+
+       
+       addSymbol: function(symbol) 
+    {
+         //print("PARSER addSYMBOL : " + symbol.alias);
+        
+               // if a symbol alias is documented more than once the last one with the user docs wins
+               if (this.symbols.hasSymbol(symbol.alias)) {
+                       var oldSymbol = this.symbols.getSymbol(symbol.alias);
+            
+                       if (oldSymbol.comment.isUserComment && !oldSymbol.comment.hasTags) {
+                               if (symbol.comment.isUserComment) { // old and new are both documented
+                                       Options.LOG.warn("The symbol '"+symbol.alias+"' is documented more than once.");
+                               }
+                               else { // old is documented but new isn't
+                                       return;
+                               }
+                       }
+               }
+               
+               // we don't document anonymous things
+               if (this.conf.ignoreAnonymous && symbol.name.match(/\$anonymous\b/)) return;
+
+               // uderscored things may be treated as if they were marked private, this cascades
+               if (this.conf.treatUnderscoredAsPrivate && symbol.name.match(/[.#-]_[^.#-]+$/)) {
+                       symbol.isPrivate = true;
+               }
+               
+               // -p flag is required to document private things
+               if ((symbol.isInner || symbol.isPrivate) && !Options.p) return;
+               
+               // ignored things are not documented, this doesn't cascade
+               if (symbol.isIgnored) return;
+        // add it to the file's list... (for dumping later..)
+        if (Symbol.srcFile) {
+            this.filesSymbols[Symbol.srcFile].addSymbol(symbol);
+        }
+               
+               this.symbols.addSymbol(symbol);
+       },
+       
+       addBuiltin: function(name) {
+  
+               var builtin = new Symbol(name, [], "CONSTRUCTOR", new DocComment(""));
+               builtin.isNamespace = false;
+               builtin.srcFile = "";
+               builtin.isPrivate = false;
+        this.addSymbol(builtin);
+               return builtin;
+       },
+       
+               
+       finish: function() {
+               this.symbols.relate();          
+               
+               // make a litle report about what was found
+               if (this.conf.explain) {
+                       var symbols = this.symbols.toArray();
+                       var srcFile = "";
+                       for (var i = 0, l = symbols.length; i < l; i++) {
+                               var symbol = symbols[i];
+                               if (srcFile != symbol.srcFile) {
+                                       srcFile = symbol.srcFile;
+                                       print("\n"+srcFile+"\n-------------------");
+                               }
+                               print(i+":\n  alias => "+symbol.alias + "\n  name => "+symbol.name+ "\n  isa => "+symbol.isa + "\n  memberOf => " + symbol.memberOf + "\n  isStatic => " + symbol.isStatic + ",  isInner => " + symbol.isInner);
+                       }
+                       print("-------------------\n");
+               }
+       },
+    /**
+     * return symbols so they can be serialized.
+     */
+    symbolsToObject : function(srcFile)
+    {
+        //this.filesSymbols[srcFile] is a symbolset..
+        return this.filesSymbols[srcFile];
+        
+            //    Parser.filesSymbols[srcFile]._index
+    }
+
+}
\ No newline at end of file
diff --git a/JSDOC/Symbol.js b/JSDOC/Symbol.js
new file mode 100644 (file)
index 0000000..3620491
--- /dev/null
@@ -0,0 +1,828 @@
+//<script type="text/javascript">
+
+XObject         = imports.XObject.XObject;
+
+SymbolSet       = imports.SymbolSet.SymbolSet;
+//Parser          = imports.Parser.Parser;
+DocComment      = imports.DocComment.DocComment;
+DocTag          = imports.DocTag.DocTag;
+/**
+       Create a new Symbol.
+       @class Represents a symbol in the source code.
+ */
+Symbol = XObject.define(
+    function() {
+        this.init();
+        if (arguments.length) this.populate.apply(this, arguments);
+        
+    },
+    Object,
+    {
+        
+        
+        name : "",
+        defaultValue : "",
+        params : [],
+        $args : [], // original arguments used when constructing.
+        addOn : "",
+        alias : "",
+        augments : [], // Doctag[]
+        author : "",
+        classDesc : "",
+        comment : {},
+        deprecated : "",
+        desc : "",
+        //events : false,
+        example : "",
+        exceptions : [],  // Doctag[]
+        inherits : [],  // Doctag[]
+        //inheritsFrom : [],
+        isa : "OBJECT", // OBJECT//FUNCTION
+        isEvent : false,
+        isConstant : false,
+        isIgnored : false,
+        isInner : false,
+        isNamespace : false,
+        isPrivate : false,
+        isStatic : false,
+        memberOf : "",
+        methods : [], // Symbol[]
+        _name : "",
+        _params : [], //Doctag[]
+        properties : [], //Doctag[]
+        requires : [],  //Doctag[]
+        returns : [], //Doctag[]
+        see : [], //Doctag[]
+        since : "",
+        srcFile : {},
+        type : "",
+        version : "",
+        childClasses : [],
+        cfgs : {},
+        
+        
+            
+        
+        toJSON : function()
+        {
+            
+           
+            var ret = { '*object' : 'Symbol' };
+            for (var i in this) {
+                if (Symbol.hide.indexOf(i) > -1) {
+                    continue;
+                }
+                switch (typeof(this[i])) {
+                    case 'function':
+                        continue;
+                    case 'object':
+                        switch(i) {
+                            //arrays..
+                            case 'params' : 
+                            case 'augments' :                             
+                            case 'exceptions' :  
+                            case 'inherits' :
+                            case 'methods' :
+                            case '_params': 
+                            case 'properties': 
+                            case 'requires':
+                            case 'returns':
+                            case 'see':
+                            case 'cfgs': // key val of doctags..
+                            case 'comment' :
+                                ret[i] = this[i]
+                                continue; 
+                            
+                            //skip
+                            case 'inheritsFrom':
+                            case 'childClasses':
+                                continue;
+            
+                            default:
+                                print("object? :" + i);
+                                Seed.quit();
+                        }
+                        
+                        
+                    case 'string':
+                    case 'number':
+                    case 'boolean':
+                        ret[i] = this[i]; continue;
+                    default:
+                        print("unknown type:" + typeof(this[i]));
+                        Seed.quit();
+                   }
+            }
+            return ret;
+            
+        },
+        
+        init : function() 
+        {
+            // only initialize arrays / objects..
+            this.params = [];
+            this.$args = [];
+            
+            //this.events = [];
+            this.exceptions = [];
+            this.inherits = [];
+            //
+            this.isa = "OBJECT"; // OBJECT//FUNCTION
+            this.methods = [];
+            this._params = [];
+            this.properties = [];
+            this.requires = [];
+            this.returns = [];
+            this.see = [];
+            this.srcFile = {};
+            
+            
+            this.cfgs = {};
+            // derived later?
+            this.inheritsFrom = [];
+            this.childClasses = [];
+            
+            this.comment = new DocComment();
+            this.comment.isUserComment =  false;
+            
+               
+        },
+
+        serialize : function() {
+            var keys = [];
+            for (var p in this) {
+                keys.push (p);
+            }
+            keys = keys.sort();
+            
+            var out = "";
+            for (var i in keys) {
+                if (typeof this[keys[i]] == "function") continue;
+                out += "     " +keys[i]+" => "+
+                    (   
+                        (typeof(this[keys[i]]) != "object") ?  
+                            this[keys[i]] :
+                            "[" +typeof(this[keys[i]])+"]"
+                    ) + 
+                    ",\n";
+            }
+            return "\n{\n" + out + "}\n";
+        },
+
+        clone : function() {
+            var clone = new Symbol();
+            clone.populate.apply(clone, this.$args); // repopulate using the original arguments
+            clone.srcFile = this.srcFile; // not the current srcFile, the one when the original was made
+            return clone;
+        },
+
+
+
+
+        //__defineSetter__("name",
+        setName  : function(n) { 
+                n = n.replace(/^_global_[.#-]/, ""); 
+                n = n.replace(/\.prototype\.?/g, '#'); 
+                 n = n.replace(/#$/g, ''); 
+                this._name = n;
+                this.name = n; // real!
+            },
+        //);
+        //__defineGetter__("name",
+        getName : function() { return this._name; },
+        //);
+        //__defineSetter__("params", 
+        setParams  :function(v) {
+                for (var i = 0, l = v.length; i < l; i++) {
+                    if (v[i].constructor != DocTag) { // may be a generic object parsed from signature, like {type:..., name:...}
+                        var ty = v[i].hasOwnProperty('type') ? v[i].type : '';
+                        this._params[i] = new DocTag(
+                            "param"+((ty)?" {"+ty+"}":"")+" "+v[i].name);
+                    }
+                    else {
+                        this._params[i] = v[i];
+                    }
+                }
+                this.params = this._params;
+            },
+        //);
+
+
+        //__defineGetter__("params",
+        getParams : function() { return this._params; },
+        //);
+
+        populate : function(
+                /** String */ name,
+                /** Object[] */ params,
+                /** String */ isa,
+                /** DocComment */ comment
+        ) {
+            this.$args = arguments;
+            //println("Symbol created: " + isa + ":" + name);
+            this.setName(name);
+            this.alias = this.getName();
+            this.setParams(params);
+            this.isa = (isa == "VIRTUAL")? "OBJECT":isa;
+            this.comment = comment || new DocComment("");
+            this.srcFile = Symbol.srcFile;
+            
+           
+            
+            if (this.is("FILE") && !this.alias) this.alias = this.srcFile;
+
+            this.setTags();
+            
+            //if (typeof PluginManager != "undefined") {
+            //    PluginManager.run("onSymbol", this);
+            //}
+        },
+
+        setTags : function() {
+            // @author
+            var authors = this.comment.getTag("author");
+            if (authors.length) {
+                this.author = authors.map(function($){return $.desc;}).join(", ");
+            }
+            
+            /*~t
+                assert("testing Symbol");
+                
+                requires("../lib/JSDOC/DocComment.js");
+                requires("../frame/String.js");
+                requires("../lib/JSDOC/DocTag.js");
+
+                var sym = new Symbol("foo", [], "OBJECT", new DocComment("/**@author Joe Smith*"+"/"));
+                assertEqual(sym.author, "Joe Smith", "@author tag, author is found.");
+            */
+            // @desc
+            var mth = this.comment.getTag("method");
+            if (mth.length) {
+                this.isa = "FUNCTION";
+            }
+            // @desc
+            var descs = this.comment.getTag("desc");
+            if (descs.length) {
+                this.desc = descs.map(function($){return $.desc;}).join("\n"); // multiple descriptions are concatenated into one
+            }
+            
+            /*~t
+                var sym = new Symbol("foo", [], "OBJECT", new DocComment("/**@desc This is a description.*"+"/"));
+                assertEqual(sym.desc, "This is a description.", "@desc tag, description is found.");
+            */
+            
+            // @overview
+            if (this.is("FILE")) {
+                if (!this.alias) this.alias = this.srcFile;
+                
+                var overviews = this.comment.getTag("overview");
+                if (overviews.length) {
+                    this.desc = [this.desc].concat(overviews.map(function($){return $.desc;})).join("\n");
+                }
+            }
+            
+            /*~t
+                var sym = new Symbol("foo", [], "FILE", new DocComment("/**@overview This is an overview.*"+"/"));
+                assertEqual(sym.desc, "\nThis is an overview.", "@overview tag, description is found.");
+            */
+            
+            // @since
+            var sinces = this.comment.getTag("since");
+            if (sinces.length) {
+                this.since = sinces.map(function($){return $.desc;}).join(", ");
+            }
+            
+            /*~t
+                var sym = new Symbol("foo", [], "FILE", new DocComment("/**@since 1.01*"+"/"));
+                assertEqual(sym.since, "1.01", "@since tag, description is found.");
+            */
+            
+            // @constant
+            if (this.comment.getTag("constant").length) {
+                this.isConstant = true;
+                this.isa = 'OBJECT';
+            }
+            
+            /*~t
+                var sym = new Symbol("foo", [], "FILE", new DocComment("/**@constant*"+"/"));
+                assertEqual(sym.isConstant, true, "@constant tag, isConstant set.");
+            */
+            
+            // @version
+            var versions = this.comment.getTag("version");
+            if (versions.length) {
+                this.version = versions.map(function($){return $.desc;}).join(", ");
+            }
+            
+            /*~t
+                var sym = new Symbol("foo", [], "FILE", new DocComment("/**@version 2.0x*"+"/"));
+                assertEqual(sym.version, "2.0x", "@version tag, version is found.");
+            */
+            
+            // @deprecated
+            var deprecateds = this.comment.getTag("deprecated");
+            if (deprecateds.length) {
+                this.deprecated = deprecateds.map(function($){return $.desc;}).join("\n");
+            }
+            
+            /*~t
+                var sym = new Symbol("foo", [], "FILE", new DocComment("/**@deprecated Use other method.*"+"/"));
+                assertEqual(sym.deprecated, "Use other method.", "@deprecated tag, desc is found.");
+            */
+            
+            // @example
+            var examples = this.comment.getTag("example");
+            if (examples.length) {
+                this.example = examples[0];
+            }
+            
+            /*~t
+                var sym = new Symbol("foo", [], "FILE", new DocComment("/**@example This\n  is an example.*"+"/"));
+                assertEqual(sym.example, "This\n  is an example.", "@deprecated tag, desc is found.");
+            */
+            
+            // @see
+            var sees = this.comment.getTag("see");
+            if (sees.length) {
+                var thisSee = this.see;
+                sees.map(function($){thisSee.push($.desc);});
+            }
+            
+            /*~t
+                var sym = new Symbol("foo", [], "FILE", new DocComment("/**@see The other thing.*"+"/"));
+                assertEqual(sym.see, "The other thing.", "@see tag, desc is found.");
+            */
+            
+            // @class
+            var classes = this.comment.getTag("class");
+            if (classes.length) {
+                this.isa = "CONSTRUCTOR";
+                this.classDesc = classes[0].desc; // desc can't apply to the constructor as there is none.
+                if (!this.classDesc) {
+                    this.classDesc = this.desc;
+                   }
+                
+                
+            }
+            
+            /*~t
+                var sym = new Symbol("foo", [], "OBJECT", new DocComment("/**@class This describes the class.*"+"/"));
+                assertEqual(sym.isa, "CONSTRUCTOR", "@class tag, makes symbol a constructor.");
+                assertEqual(sym.classDesc, "This describes the class.", "@class tag, class description is found.");
+            */
+            
+            // @namespace
+            var namespaces = this.comment.getTag("namespace");
+            if (namespaces.length) {
+                this.classDesc = namespaces[0].desc+"\n"+this.desc; // desc can't apply to the constructor as there is none.
+                this.isNamespace = true;
+            }
+            
+            /*~t
+                var sym = new Symbol("foo", [], "OBJECT", new DocComment("/**@namespace This describes the namespace.*"+"/"));
+                assertEqual(sym.classDesc, "This describes the namespace.\n", "@namespace tag, class description is found.");
+            */
+            
+            // @param
+            var params = this.comment.getTag("param");
+            if (params.length) {
+                // user-defined params overwrite those with same name defined by the parser
+                var thisParams = this.getParams();
+
+                if (thisParams.length == 0) { // none exist yet, so just bung all these user-defined params straight in
+                    this.setParams(params);
+                }
+                else { // need to overlay these user-defined params on to existing parser-defined params
+                    for (var i = 0, l = params.length; i < l; i++) {
+                        if (thisParams[i]) {
+                            if (params[i].type) thisParams[i].type = params[i].type;
+                            thisParams[i].name = params[i].name;
+                            thisParams[i].desc = params[i].desc;
+                            thisParams[i].isOptional = params[i].isOptional;
+                            thisParams[i].defaultValue = params[i].defaultValue;
+                        }
+                        else thisParams[i] = params[i];
+                    }
+                }
+            }
+            
+            /*~t
+                var sym = new Symbol("foo", [{type: "array", name: "pages"}], "FUNCTION", new DocComment("/**Description.*"+"/"));
+                assertEqual(sym.params.length, 1, "parser defined param is found.");
+                
+                sym = new Symbol("foo", [], "FUNCTION", new DocComment("/**Description.\n@param {array} pages*"+"/"));
+                assertEqual(sym.params.length, 1, "user defined param is found.");
+                assertEqual(sym.params[0].type, "array", "user defined param type is found.");
+                assertEqual(sym.params[0].name, "pages", "user defined param name is found.");
+                
+                sym = new Symbol("foo", [{type: "array", name: "pages"}], "FUNCTION", new DocComment("/**Description.\n@param {string} uid*"+"/"));
+                assertEqual(sym.params.length, 1, "user defined param overwrites parser defined param.");
+                assertEqual(sym.params[0].type, "string", "user defined param type overwrites parser defined param type.");
+                assertEqual(sym.params[0].name, "uid", "user defined param name overwrites parser defined param name.");
+            
+                sym = new Symbol("foo", [{type: "array", name: "pages"}, {type: "number", name: "count"}], "FUNCTION", new DocComment("/**Description.\n@param {string} uid*"+"/"));
+                assertEqual(sym.params.length, 2, "user defined params  overlay parser defined params.");
+                assertEqual(sym.params[1].type, "number", "user defined param type overlays parser defined param type.");
+                assertEqual(sym.params[1].name, "count", "user defined param name overlays parser defined param name.");
+
+                sym = new Symbol("foo", [], "FUNCTION", new DocComment("/**Description.\n@param {array} pages The pages description.*"+"/"));
+                assertEqual(sym.params.length, 1, "user defined param with description is found.");
+                assertEqual(sym.params[0].desc, "The pages description.", "user defined param description is found.");
+            */
+            
+            // @constructor
+            if (this.comment.getTag("constructor").length) {
+                this.isa = "CONSTRUCTOR";
+            }
+            
+            /*~t
+                var sym = new Symbol("foo", [], "OBJECT", new DocComment("/**@constructor*"+"/"));
+                assertEqual(sym.isa, "CONSTRUCTOR", "@constructor tag, makes symbol a constructor.");
+            */
+            
+            // @static
+            if (this.comment.getTag("static").length) {
+                this.isStatic = true;
+                if (this.isa == "CONSTRUCTOR") {
+                    this.isNamespace = true;
+                }
+            }
+            
+                // @static
+            if (this.comment.getTag("singleton").length) {
+                this.isStatic = true;
+                //if (this.isa == "CONSTRUCTOR") {
+                //     this.isNamespace = true;
+                //}
+            }
+            
+            
+            
+            /*~t
+                var sym = new Symbol("foo", [], "OBJECT", new DocComment("/**@static\n@constructor*"+"/"));
+                assertEqual(sym.isStatic, true, "@static tag, makes isStatic true.");
+                assertEqual(sym.isNamespace, true, "@static and @constructor tag, makes isNamespace true.");
+            */
+            
+            // @inner
+            if (this.comment.getTag("inner").length) {
+                this.isInner = true;
+                this.isStatic = false;
+            }
+            
+            /*~t
+                var sym = new Symbol("foo", [], "OBJECT", new DocComment("/**@inner*"+"/"));
+                assertEqual(sym.isStatic, false, "@inner tag, makes isStatic false.");
+                assertEqual(sym.isInner, true, "@inner makes isInner true.");
+            */
+            
+            // @field
+            if (this.comment.getTag("field").length) {
+                this.isa = "OBJECT";
+            }
+            
+            /*~t
+                var sym = new Symbol("foo", [], "FUNCTION", new DocComment("/**@field*"+"/"));
+                assertEqual(sym.isa, "OBJECT", "@field tag, makes symbol an object.");
+            */
+            
+            // @function
+            if (this.comment.getTag("function").length) {
+                this.isa = "FUNCTION";
+            }
+            
+            // @param
+            if (this.comment.getTag("param").length && this.isa == "OBJECT" ) {
+                // change a property to a function..
+                this.isa = "FUNCTION";
+            }
+            
+            
+            /*~t
+                var sym = new Symbol("foo", [], "OBJECT", new DocComment("/**@function*"+"/"));
+                assertEqual(sym.isa, "FUNCTION", "@function tag, makes symbol a function.");
+            */
+            
+            // @event
+            var events = this.comment.getTag("event");
+            if (events.length) {
+                this.isa = "FUNCTION";
+                this.isEvent = true;
+            }
+            
+            /*~t
+                var sym = new Symbol("foo", [], "OBJECT", new DocComment("/**@event*"+"/"));
+                assertEqual(sym.isa, "FUNCTION", "@event tag, makes symbol a function.");
+                assertEqual(sym.isEvent, true, "@event makes isEvent true.");
+            */
+            
+            // @name
+            var names = this.comment.getTag("name");
+            if (names.length) {
+                this.setName(names[0].desc);
+            }
+            
+            /*~t
+                // todo
+            */
+            
+            // @property
+            var properties = this.comment.getTag("property");
+            if (properties.length) {
+                thisProperties = this.properties;
+                for (var i = 0; i < properties.length; i++) {
+                    var property = new Symbol(this.alias+"#"+properties[i].name, [], "OBJECT", new DocComment("/**"+properties[i].desc+"\n@name "+properties[i].name+"\n@memberOf "+this.alias+"#*/"));
+                    // TODO: shouldn't the following happen in the addProperty method of Symbol?
+                    property.name = properties[i].name;
+                    property.memberOf = this.alias;
+                    if (properties[i].type) property.type = properties[i].type;
+                    if (properties[i].defaultValue) property.defaultValue = properties[i].defaultValue;
+                    this.addProperty(property);
+                    imports.Parser.Parser.addSymbol(property);
+                }
+            }
+            
+            // config..
+            var conf = this.comment.getTag("cfg");
+            if (conf.length) {
+                for (var i = 0; i < conf.length; i++) {
+                    this.addConfig(conf[i]);
+                }
+            }
+            
+            /*~t
+                // todo
+            */
+
+            // @return
+            var returns = this.comment.getTag("return");
+            if (returns.length) { // there can be many return tags in a single doclet
+                this.returns = returns;
+                this.type = returns.map(function($){return $.type}).join(", ");
+            }
+            
+            /*~t
+                // todo
+            */
+            
+            // @exception
+            this.exceptions = this.comment.getTag("throws");
+            
+            /*~t
+                // todo
+            */
+            
+            // @requires
+            var requires = this.comment.getTag("requires");
+            if (requires.length) {
+                this.requires = requires.map(function($){return $.desc});
+            }
+            
+            /*~t
+                // todo
+            */
+            
+            // @type
+            var types = this.comment.getTag("type");
+            if (types.length) {
+                this.type = types[0].desc; //multiple type tags are ignored
+            }
+            
+            /*~t
+                // todo
+            */
+            
+            // @private
+            if (this.comment.getTag("private").length || this.isInner) {
+                this.isPrivate = true;
+            }
+            
+            // @ignore
+            if (this.comment.getTag("ignore").length) {
+                this.isIgnored = true;
+            }
+            
+            /*~t
+                // todo
+            */
+            
+            // @inherits ... as ...
+            var inherits = this.comment.getTag("inherits");
+            if (inherits.length) {
+                for (var i = 0; i < inherits.length; i++) {
+                    if (/^\s*([a-z$0-9_.#-]+)(?:\s+as\s+([a-z$0-9_.#]+))?/i.test(inherits[i].desc)) {
+                        var inAlias = RegExp.$1;
+                        var inAs = RegExp.$2 || inAlias;
+
+                        if (inAlias) inAlias = inAlias.replace(/\.prototype\.?/g, "#");
+                        
+                        if (inAs) {
+                            inAs = inAs.replace(/\.prototype\.?/g, "#");
+                            inAs = inAs.replace(/^this\.?/, "#");
+                        }
+
+                        if (inAs.indexOf(inAlias) != 0) { //not a full namepath
+                            var joiner = ".";
+                            if (this.alias.charAt(this.alias.length-1) == "#" || inAs.charAt(0) == "#") {
+                                joiner = "";
+                            }
+                            inAs = this.alias + joiner + inAs;
+                        }
+                    }
+                    this.inherits.push({alias: inAlias, as: inAs});
+                }
+            }
+            
+            /*~t
+                // todo
+            */
+
+            // @augments
+            this.augments = this.comment.getTag("augments");
+            
+            //@extends - Ext
+            if (this.comment.getTag("extends")) {   
+                this.augments = this.comment.getTag("extends");
+            }
+            
+            
+            // @default
+            var defaults = this.comment.getTag("default");
+            if (defaults.length) {
+                if (this.is("OBJECT")) {
+                    this.defaultValue = defaults[0].desc;
+                }
+            }
+            
+            /*~t
+                // todo
+            */
+            
+            // @memberOf
+            var memberOfs = this.comment.getTag("memberOf");
+            if (memberOfs.length) {
+                this.memberOf = memberOfs[0].desc;
+                this.memberOf = this.memberOf.replace(/\.prototype\.?/g, "#");
+                this.name = this.name.split('.').pop();
+                this.name = this.name.split('#').pop();
+                this.name = this.memberOf + this.name;
+                this._name = this.name
+                this.alias = this.name;
+            }
+
+            /*~t
+                // todo
+            */
+            
+            // @public
+            if (this.comment.getTag("public").length) {
+                this.isPrivate = false;
+            }
+            
+            /*~t
+                // todo
+            */
+        },
+
+        is : function(what) {
+            return this.isa === what;
+        },
+
+        isBuiltin : function() {
+            return SymbolSet.isBuiltin(this.alias);
+        },
+
+        setType : function(/**String*/comment, /**Boolean*/overwrite) {
+            if (!overwrite && this.type) return;
+            var typeComment = DocComment.unwrapComment(comment);
+            this.type = typeComment;
+        },
+
+        inherit : function(symbol) {
+            if (!this.hasMember(symbol.name) && !symbol.isInner) {
+                if (symbol.is("FUNCTION"))
+                    this.methods.push(symbol);
+                else if (symbol.is("OBJECT"))
+                    this.properties.push(symbol);
+            }
+        },
+
+        hasMember : function(name) {
+            return (this.hasMethod(name) || this.hasProperty(name));
+        },
+
+        addMember : function(symbol) {
+            //println("ADDMEMBER: " + this.name +  " ++ " + symbol.name);
+            
+            if (symbol.comment.getTag("cfg").length == 1) { 
+                symbol.comment.getTag("cfg")[0].memberOf = this.alias;
+                this.addConfig(symbol.comment.getTag("cfg")[0]);
+                return;
+            }
+            
+            if (symbol.is("FUNCTION")) { this.addMethod(symbol); }
+            else if (symbol.is("OBJECT")) { this.addProperty(symbol); }
+        },
+
+        hasMethod : function(name) {
+            var thisMethods = this.methods;
+            for (var i = 0, l = thisMethods.length; i < l; i++) {
+                if (thisMethods[i].name == name) return true;
+                if (thisMethods[i].alias == name) return true;
+            }
+            return false;
+        },
+
+        addMethod : function(symbol) {
+            var methodAlias = symbol.alias;
+            var thisMethods = this.methods;
+            for (var i = 0, l = thisMethods.length; i < l; i++) {
+                if (thisMethods[i].alias == methodAlias) {
+                    thisMethods[i] = symbol; // overwriting previous method
+                    return;
+                }
+            }
+            thisMethods.push(symbol); // new method with this alias
+        },
+
+        hasProperty : function(name) {
+            var thisProperties = this.properties;
+            for (var i = 0, l = thisProperties.length; i < l; i++) {
+                if (thisProperties[i].name == name) return true;
+                if (thisProperties[i].alias == name) return true;
+            }
+            return false;
+        },
+
+        addProperty : function(symbol) {
+            var propertyAlias = symbol.alias;
+            var thisProperties = this.properties;
+            for (var i = 0, l = thisProperties.length; i < l; i++) {
+                if (thisProperties[i].alias == propertyAlias) {
+                    thisProperties[i] = symbol; // overwriting previous property
+                    return;
+                }
+            }
+
+            thisProperties.push(symbol); // new property with this alias
+        },
+        
+        addDocTag : function(docTag)
+        {
+            this.comment.tags.push(docTag);
+            if (docTag.title == 'cfg') {
+                this.addConfig(docTag);
+            }
+            
+        },
+        
+        addConfig : function(docTag)
+        {
+            if (typeof(docTag['memberOf']) == 'undefined') {
+                // remove prototype data...
+                //var a = this.alias.split('#')[0];
+                //docTag.memberOf = a;
+                docTag.memberOf = this.alias;
+            }
+            if (typeof(this.cfgs[docTag.name]) == 'undefined') {
+                this.cfgs[docTag.name] = docTag;
+            }
+            
+        },
+        configToArray: function()
+        {
+            var r = [];
+            for(var ci in this.cfgs) {
+                // dont show hidden!!
+                if (this.cfgs[ci].desc.match(/@hide/)) {
+                    continue;
+                }
+                r.push(this.cfgs[ci]); 
+               
+            }
+            return r;
+        }
+});
+
+/**
+ * Elements that are not serialized
+ * 
+ */
+Symbol.hide = [ 
+    '$args' // not needed AFAIK
+]
+
+Symbol.srcFile = ""; //running reference to the current file being parsed
+
+
+Symbol.fromDump = function(t)
+{
+    var ns = new Symbol();
+    for (var i in t) {
+        if (typeof(ns[i]) == "undefined") {
+            println("ERR:no default for Symbol:"+ i);
+        }
+        ns[i] = t[i];
+    }
+    return ns;
+}
diff --git a/JSDOC/SymbolSet.js b/JSDOC/SymbolSet.js
new file mode 100644 (file)
index 0000000..5843a94
--- /dev/null
@@ -0,0 +1,338 @@
+//<script type="text/javascript">
+
+XObject         = imports.XObject.XObject;
+DocComment      = imports.DocComment.DocComment;
+// circular references..
+///Options         = imports.BuildDocs.Options;
+//Parser          = imports.Parser.Parser;
+//Symbol          = imports.Symbol.Symbol;
+
+
+
+SymbolSet = XObject.define(
+    function() {
+        this.init();
+    },
+    Object,
+    {
+        
+        _index : false,
+        
+        
+        init : function() {
+            this._index = {};
+        },
+
+        keys : function() 
+        {
+            var found = [];
+            for (var p in this._index) {
+                found.push(p);
+            }
+            return found;
+        },
+
+
+        hasSymbol : function(alias) {
+            return typeof(this._index[alias]) != 'undefined';
+            //return this.keys().indexOf(alias) > -1;
+        },
+
+        addSymbol : function(symbol) {
+            //print("ADDING SYMBOL:"+symbol.alias.toString());
+            
+            
+            if (this.hasSymbol(symbol.alias)) {
+                imports.BuildDocs.Options.LOG.warn("Overwriting symbol documentation for: "+symbol.alias + ".");
+            }
+            this._index[symbol.alias] = symbol;
+        },
+
+        getSymbol : function(alias) {
+            
+            if (this.hasSymbol(alias)) return this._index[alias];
+            return false;
+        },
+
+        toArray : function() {
+            var found = [];
+            for (var p in this._index) {
+                found.push(this._index[p]);
+            }
+            return found;
+        },
+        /**
+         * for serializing
+         */
+        toJSON : function() {
+            return {
+                '*object' : 'SymbolSet',
+                _index : this._index
+            };
+            
+        },
+
+
+        deleteSymbol : function(alias) {
+            if (!this.hasSymbol(alias)) return;
+            delete this._index[alias];
+        },
+
+        renameSymbol : function(oldName, newName) {
+            // todo: should check if oldname or newname already exist
+            if (typeof(this._index[oldName]) == "undefined") {
+                throw "Cant rename " + oldName + " to " + newName + " As it doesnt exist";
+               }
+            this._index[newName] = this._index[oldName];
+            this.deleteSymbol(oldName);
+            this._index[newName].alias = newName;
+            return newName;
+        },
+
+        relate : function() {
+            this.resolveBorrows();
+            this.resolveMemberOf();
+            this.resolveAugments();
+        },
+
+        resolveBorrows : function() {
+            for (p in this._index) {
+                var symbol = this._index[p];
+                
+                
+                
+                if (symbol.is("FILE") || symbol.is("GLOBAL")) continue;
+                
+                var borrows = symbol.inherits;
+                for (var i = 0; i < borrows.length; i++) {
+                    var borrowed = this.getSymbol(borrows[i].alias);
+                    if (!borrowed) {
+                        imports.BuildDocs.Options.LOG.warn("Can't borrow undocumented "+borrows[i].alias+".");
+                        continue;
+                    }
+                    
+                    var borrowAsName = borrows[i].as;
+                    var borrowAsAlias = borrowAsName;
+                    if (!borrowAsName) {
+                        imports.BuildDocs.Options.LOG.warn("Malformed @borrow, 'as' is required.");
+                        continue;
+                    }
+                    
+                    if (borrowAsName.length > symbol.alias.length && borrowAsName.indexOf(symbol.alias) == 0) {
+                        borrowAsName = borrowAsName.replace(borrowed.alias, "")
+                    }
+                    else {
+                        var joiner = "";
+                        if (borrowAsName.charAt(0) != "#") joiner = ".";
+                        borrowAsAlias = borrowed.alias + joiner + borrowAsName;
+                    }
+                    
+                    borrowAsName = borrowAsName.replace(/^[#.]/, "");
+                            
+                    if (this.hasSymbol(borrowAsAlias)) continue;
+
+                    var clone = borrowed.clone();
+                    clone.name = borrowAsName;
+                    clone.alias = borrowAsAlias;
+                    this.addSymbol(clone);
+                }
+            }
+        },
+
+        resolveMemberOf : function() {
+            for (var p in this._index) {
+                var symbol = this.getSymbol(p);
+                
+                if (symbol.is("FILE") || symbol.is("GLOBAL")) continue;
+                
+                // the memberOf value was provided in the @memberOf tag
+                else if (symbol.memberOf) {
+                    var parts = symbol.alias.match(new RegExp("^("+symbol.memberOf+"[.#-])(.+)$"));
+                    
+                    // like foo.bar is a memberOf foo
+                    if (parts) {
+                        symbol.memberOf = parts[1];
+                        symbol.name = parts[2];
+                    }
+                    // like bar is a memberOf foo
+                    else {
+                        var joiner = symbol.memberOf.charAt(symbol.memberOf.length-1);
+                        if (!/[.#-]/.test(joiner)) symbol.memberOf += ".";
+                        
+                        this.renameSymbol(p, symbol.memberOf + symbol.name);
+                    }
+                }
+                // the memberOf must be calculated
+                else {
+                    var parts = symbol.alias.match(/^(.*[.#-])([^.#-]+)$/);
+                    if (parts) {
+                        symbol.memberOf = parts[1];
+                        symbol.name = parts[2];                                
+                    }
+                }
+
+                // set isStatic, isInner
+                if (symbol.memberOf) {
+                    switch (symbol.memberOf.charAt(symbol.memberOf.length-1)) {
+                        case '#' :
+                            symbol.isStatic = false;
+                            symbol.isInner = false;
+                            break;
+                            
+                        case '.' :
+                            symbol.isStatic = true;
+                            symbol.isInner = false;
+                            break;
+                            
+                        case '-' :
+                            symbol.isStatic = false;
+                            symbol.isInner = true;
+                            break;
+                            
+                    }
+                }
+                
+                // unowned methods and fields belong to the global object
+                if (!symbol.is("CONSTRUCTOR") && !symbol.isNamespace && symbol.memberOf == "") {
+                    symbol.memberOf = "_global_";
+                }
+                
+                // clean up
+                if (symbol.memberOf.match(/[.#-]$/)) {
+                    symbol.memberOf = symbol.memberOf.substr(0, symbol.memberOf.length-1);
+                }
+                //print("looking for memberOf: " + symbol.memberOf + " FOR " + symbol.alias);
+                // add to parent's methods or properties list
+                if (symbol.memberOf) {
+                    var container = this.getSymbol(symbol.memberOf);
+                    if (!container) {
+                        if (SymbolSet.isBuiltin(symbol.memberOf)) {
+                            container = imports.Parser.Parser.addBuiltin(symbol.memberOf);
+                        }
+                        else {
+                           // print("symbol NOT a BUILT IN - createing a container");
+                            // Eg. Ext.y.z (missing y)
+                            // we need to add in the missing symbol...
+                            container = new imports.Symbol.Symbol(symbol.memberOf, [], "OBJECT", new DocComment(""));
+                            container.isNamespace = true;
+                            this.addSymbol( container );
+                           // print(container.toSource());
+                            //container = this.getSymbol(symbol.memberOf);
+                            // fake container ... so dont ad symbols to it..
+                            continue;
+                            container = false;
+                            //LOG.warn("Can't document "+symbol.name +" as a member of undocumented symbol "+symbol.memberOf+".");
+                            //LOG.warn("We only have the following symbols: \n" + 
+                            //    this.keys.toSource());
+                        }
+                    }
+                    
+                    if (container && !container.isNamespace) container.addMember(symbol);
+                }
+            }
+        },
+
+        resolveAugments : function() {
+            // does this sort out multiple extends???
+            for (var p in this._index) {
+                var symbol = this.getSymbol(p);
+                this.buildAugmentsList(symbol); /// build heirachy of inheritance...
+                if (symbol.alias == "_global_" || symbol.is("FILE")) continue;
+                
+                var augments = symbol.augments;
+                for(var ii = 0, il = augments.length; ii < il; ii++) {
+                    var contributer = this.getSymbol(augments[ii]);
+                    
+                    
+                    
+                    if (contributer) {
+                        contributer.childClasses.push(symbol.alias);
+                        symbol.inheritsFrom.push(contributer.alias);
+                        //if (!isUnique(symbol.inheritsFrom)) {
+                        //    imports.BuildDocs.Options.LOG.warn("Can't resolve augments: Circular reference: "+symbol.alias+" inherits from "+contributer.alias+" more than once.");
+                        //}
+                        //else {
+                            var cmethods = contributer.methods;
+                            var cproperties = contributer.properties;
+                            var cfgs = contributer.cfgs;
+                            for (var ci = 0, cl = cmethods.length; ci < cl; ci++) {   
+                                symbol.inherit(cmethods[ci]);
+                            }
+                            for (var ci = 0, cl = cproperties.length; ci < cl; ci++) {
+                                symbol.inherit(cproperties[ci]);
+                            }
+                            for (var ci in cfgs) {
+                                symbol.addConfig(cfgs[ci]);
+                            }
+                            
+                                
+                        //}
+                    }
+                    else {
+                        
+                        imports.BuildDocs.Options.LOG.warn("Can't augment contributer: '"+augments[ii]+"', not found. FOR: " + symbol.alias);
+                        
+                        //LOG.warn("We only have the following symbols: \n" + 
+                          //      this.keys().toSource().split(",").join(",    \n"));
+                       }
+
+                }
+            }
+        },
+
+        buildAugmentsList : function(symbol)
+        {
+            // basic idea is to add all the child extends to the parent.. without looping forever..
+            
+            if (!symbol.augments.length) {
+                return;
+            }
+            
+            var _t = this;
+            print("buildAugmentsList:" + symbol.alias);
+            var addAugments = function (alist, forceit) { // returns number added..
+                if (!alist.length) {
+                    return 0;
+                }
+                print("buildAugmentsList:addAugments" + alist.length);
+                var rval = 0;
+                for(var ii = 0; ii < alist.length; ii++) {
+                    print("getAlias:" + alist[ii]);
+                    if (alist[ii] == symbol.alias) {
+                        continue;
+                    }
+                    var contributer = _t.getSymbol(alist[ii]);
+                    if (!contributer) {
+                        continue;
+                    }
+                    
+                    if (!forceit && symbol.augments.indexOf(alist[ii]) > -1) {
+                        continue;
+                    }
+                    if (symbol.augments.indexOf(alist[ii]) < 0) {
+                        symbol.augments.push(alist[ii]);
+                    }
+                        
+                    
+                    addAugments(contributer.augments,false);
+                    
+                    rval++;
+                }
+                print("buildAugmentsList: ADDED:" + rval);
+                return rval;
+            }
+            addAugments(symbol.augments, true);
+            //while(addAugments(symbol.augments) >  0) { }
+            
+        }
+         
+})
+
+SymbolSet.isBuiltin = function(name) {
+    return (SymbolSet.isBuiltin.coreObjects.indexOf(name) > -1);
+}
+SymbolSet.isBuiltin .coreObjects = [
+    '_global_', 'Array', 'Boolean', 'Date', 'Function', 
+    'Math', 'Number', 'Object', 'RegExp', 'String'
+];
\ No newline at end of file
diff --git a/JSDOC/Walker2.js b/JSDOC/Walker2.js
new file mode 100644 (file)
index 0000000..439a908
--- /dev/null
@@ -0,0 +1,929 @@
+//<Script type="text/javascript">
+XObject      = imports.XObject.XObject;
+
+Scope        = imports.Scope.Scope;
+DocComment   = imports.DocComment.DocComment;
+Symbol       = imports.Symbol.Symbol;
+
+
+/**
+* Scope stuff
+* 
+* // FIXME - I need this to do next() without doccomments..
+*/
+
+Walker2 = XObject.define(
+    function(ts) {
+        this.ts = ts;
+        this.warnings = [];
+        this.scopes = [];
+        this.indexedScopes = {};
+        this.symbols = {};
+        //this.timer = new Date() * 1;
+       
+    },
+    Object,
+    
+    {
+    /*
+        timer: 0,
+        timerPrint: function (str) {
+            var ntime = new Date() * 1;
+            var tdif =  ntime -this.timer;
+            this.timer = ntime;
+            var pref = '';
+            if (tdif > 100) { //slower ones..
+                pref = '***';
+            }
+            print(pref+'['+tdif+']'+str);
+            
+        },
+        */
+        warn: function(s) {
+            //this.warnings.push(s);
+            print("WARNING:" + htmlescape(s) + "<BR>");
+        },
+        // defaults should not be initialized here =- otherwise they get duped on new, rather than initalized..
+        warnings : false,
+        ts : false,
+        scopes : false,
+        global : false,
+        mode : "", //"BUILDING_SYMBOL_TREE",
+        braceNesting : 0,
+        indexedScopes : false,
+        munge: true,
+        symbols: false, /// object store of sumbols..
+
+
+
+
+        buildSymbolTree : function()
+        {
+            //print("<PRE>");
+            
+            this.ts.rewind();
+            this.braceNesting = 0;
+            this.scopes = [];
+            this.aliases = {};
+             
+            this.globalScope = new Scope(-1, false, -1, '$global$');
+            indexedScopes = { 0 : this.globalScope };
+            
+            this.mode = 'BUILDING_SYMBOL_TREE';
+            this.parseScope(this.globalScope);
+            
+        },
+        
+
+
+        log : function(str)
+        {
+              //print("<B>LOG:</B>" + htmlescape(str) + "<BR/>\n");
+        },
+        logR : function(str)
+        {
+                //print("<B>LOG:</B>" + str + "<BR/>");
+        },
+
+       
+        currentDoc: false,
+
+
+        parseScope : function(scope, ealiases) // parse a token stream..
+        {
+            //this.timerPrint("parseScope EnterScope"); 
+            
+            var aliases = {};
+            var fixAlias = function(str, nomore)
+            {
+                var ar = str.split('.');
+                var m = ar.shift();
+                
+                //print(str +"?=" +aliases.toSource());
+                if (aliases[m] == undefined) {
+                    return str;
+                }
+                var ret = aliases[m] + (ar.length? '.' : '' )+ ar.join('.');
+                if (nomore !== true) {
+                    ret = fixAlias(ret, true);
+                }
+                
+                
+                
+                return ret;
+            };
+
+            
+            
+            if (ealiases != undefined) {
+                // copy it down..
+                for(var i in ealiases) {
+                    aliases[i] = ealiases[i];
+                }
+                
+                
+            } else {
+                ealiases = {};
+            }
+            //print("STARTING SCOPE WITH: " + ealiases.toSource());
+            var symbol;
+            var token;
+            
+            var identifier;
+
+            var expressionBraceNesting = this.braceNesting;
+            var bracketNesting = 0;
+            var parensNesting = 0;
+           
+            
+            var l1 = '', l2 = '';
+            var scopeName ='';
+            
+            
+            var locBraceNest = 0;
+            // determines if we are in object literals...
+            
+            var isObjectLitAr = [ false ];
+            //print("SCOPE: ------------------START ----------------");
+            this.scopesIn(scope);
+            var scopeLen = this.scopes.length;
+            
+            if (this.ts.cursor < 1) {
+              // this.ts.cursor--; // hopeflly this kludge will work
+            }
+            
+            
+            //print(JSON.stringify(this.ts, null, 4)); Seed.quit();
+            
+            while (null != (token = this.ts.next())) {
+                //print("TOK"+ token.toString());
+                //  this.timerPrint("parseScope AFTER lookT: " + token.toString()); 
+                  
+                if (token.is('COMM')) {
+                      
+                 
+                    if (token.name != 'JSDOC') {
+                        //print("Walker2 : spce is not JSDOC");
+                        continue; //skip.
+                    }
+                    if (this.currentDoc) {
+                        // add it to the current scope????
+                        
+                        this.addSymbol('', true);
+                        //print ( "Unconsumed Doc: " + token.toString())
+                        //throw "Unconsumed Doc (TOKwhitespace): " + this.currentDoc.toSource();
+                    }
+                    
+                   // print ( "NEW COMMENT: " + token.toString())
+                    var newDoc = new DocComment(token.data);
+                    
+                    // it's a scope changer..
+                    if (newDoc.getTag("scope").length) {
+                        //print("Walker2 : doctag changes scope");
+                        //throw "done";
+                        scope.ident = '$private$|' + newDoc.getTag("scope")[0].desc;
+                        continue;
+                    }
+                    
+                    // it's a scope changer..
+                    if (newDoc.getTag("scopeAlias").length) {
+                        //print(newDoc.getTag("scopeAlias").toSource());
+                        // @scopeAlias a=b
+                        //print("Walker2 : doctag changes scope (alias)");
+                        var sal = newDoc.getTag("scopeAlias")[0].desc.split("=");
+                        aliases[sal[0]] = sal[1];
+                        
+                        continue;
+                    }
+                    
+                    
+                    /// got a  doc comment..
+                    //token.data might be this.??? (not sure though)
+                    //print("Walker2 : setting currentDoc");
+                    this.currentDoc = newDoc;
+                    continue;
+                }
+                
+                // catch the various issues .. - scoe changes or doc actions..
+                
+              
+                
+                // things that stop comments carrying on...??
+                
+                if (this.currentDoc && (
+                        token.data == ';' || 
+                        token.data == '}')) {
+                    this.addSymbol('', true);
+                    //throw "Unconsumed Doc ("+ token.toString() +"): " + this.currentDoc.toSource();
+                }
+                    
+                
+                // the rest are scoping issues...
+                
+                // var a = b;
+                
+                 if (token.name == 'VAR' &&
+                 
+                        this.ts.lookTok(1).type == 'NAME' &&
+                        this.ts.lookTok(2).data == '-' &&
+                        this.ts.lookTok(3).type == 'NAME'  &&
+                        this.ts.lookTok(4).data == ';'  
+                        
+                 
+                 ) {
+                    //print("SET ALIAS:" + this.ts.lookTok(1).data +'=' + this.ts.lookTok(3).data);
+                     
+                    aliases[this.ts.lookTok(1).data] = this.ts.lookTok(3).data;
+                    
+                
+                }
+                
+                if ((token.data == 'eval') || /\.eval$/.test(token.data)) {
+                    this.currentDoc = false;
+                    continue;
+                }
+              
+                // extends scoping  *** not sure if the can be x = Roo.apply(....)
+                // xxx.extends(a,b, {
+                    // $this$=b|b.prototype
+                // xxx.apply(a, {
+                    // a  << scope
+                // xxx.applyIf(a, {
+                    // a  << scope
+                if (token.type == 'NAME') {
+                    
+                    //print("TOK(ident)"+ token.toString());
+                     
+                    if (/\.extend$/.test(token.data) &&
+                        this.ts.lookTok(1).data == '(' &&
+                        this.ts.lookTok(2).type == 'NAME' &&
+                        this.ts.lookTok(3).data == ',' &&
+                        this.ts.lookTok(4).type == 'NAME' &&
+                        this.ts.lookTok(5).data == ',' &&
+                        this.ts.lookTok(6).data == '{' 
+                           
+                        ) {
+                        // ignore test for ( a and ,
+                        this.ts.nextTok(); /// (
+                        token = this.ts.nextTok(); // a
+                        scopeName = token.data;
+                        
+                        if (this.currentDoc) {
+                            this.addSymbol(scopeName,false,'OBJECT');
+
+                        }
+                        this.ts.nextTok(); // ,
+                        this.ts.nextTok(); // b
+                        
+                        
+                        this.ts.nextTok(); // ,
+                        token = this.ts.nextTok(); // {
+                            
+                        scopeName = fixAlias(scopeName);
+                        
+                        var fnScope = new Scope(this.braceNesting, scope, token.n, 
+                            '$this$=' + scopeName  + '|'+scopeName+'.prototype');
+                        this.indexedScopes[this.ts.cursor] = fnScope;
+                        scope = fnScope;
+                        this.scopesIn(fnScope);
+                       
+                        locBraceNest++;
+                        //print(">>" +locBraceNest);
+                        continue; // no more processing..
+                        
+                    }
+                    
+                    // a = Roo.extend(parentname, {
+                        
+                     if (/\.extend$/.test(token.data) &&
+                        this.ts.lookTok(-2).type == 'NAME'  &&
+                        this.ts.lookTok(-1).data == '=' &&
+                        this.ts.lookTok(1).data == '(' &&
+                        this.ts.lookTok(2).type == 'NAME' &&
+                        this.ts.lookTok(3).data == ',' &&
+                        this.ts.lookTok(4).data == '{' 
+                        ) {
+                        // ignore test for ( a and ,
+                        token = this.ts.lookTok(-2);
+                        scopeName = token.data;
+                        if (this.currentDoc) {
+                            this.addSymbol(scopeName,false,'OBJECT');
+
+                        }
+                        this.ts.nextTok(); /// (
+                        this.ts.nextTok(); // parent
+                        
+                        this.ts.nextTok(); // ,
+                        token =  this.ts.nextTok(); // {
+                             
+                        
+                        scopeName = fixAlias(scopeName);
+                        var fnScope = new Scope(this.braceNesting, scope, token.n, 
+                            '$this$=' + scopeName  + '|'+scopeName+'.prototype');
+                        this.indexedScopes[this.ts.cursor] = fnScope;
+                        scope = fnScope;
+                        this.scopesIn(fnScope);
+                       
+                        locBraceNest++;
+                        //print(">>" +locBraceNest);
+                        continue; // no more processing..
+                        
+                    }
+                    
+                    
+                     // apply ( XXXX,  {
+                    /*
+                    print(JSON.stringify([
+                        token.data,
+                        this.ts.lookTok(1).data ,
+                        this.ts.lookTok(2).type ,
+                        this.ts.lookTok(3).data ,
+                        this.ts.lookTok(4).data 
+                    ], null, 4));
+                    */
+                    
+                    if (/\.(applyIf|apply)$/.test(token.data) && 
+                        this.ts.lookTok(1).data == '('  &&
+                        this.ts.lookTok(2).type == 'NAME' &&
+                        this.ts.lookTok(3).data == ','  &&
+                        this.ts.lookTok(4).data == '{' 
+                        
+                        ) {
+                        this.ts.nextTok(); /// (
+                         
+                        //print("GOT : applyIF!"); 
+                         
+                        token = this.ts.nextTok(); // b
+                        scopeName = token.data;
+                        
+                                      
+                        if (this.currentDoc) {
+                            this.addSymbol(scopeName,false,'OBJECT');
+                        }
+                     
+
+                        
+                        this.ts.nextTok(); /// ,
+                        this.ts.nextTok(); // {
+                        scopeName = fixAlias(scopeName);
+                        var fnScope = new Scope(this.braceNesting, scope, token.n, scopeName);
+                        this.indexedScopes[this.ts.cursor] = fnScope;
+                        scope = fnScope;
+                        this.scopesIn(fnScope);
+                         
+                        locBraceNest++;
+                        //print(">>" +locBraceNest);
+                        continue; // no more processing..
+                    }
+                    
+                    
+                    // xxx = new yyy ( {
+                        
+                    // change scope to xxxx
+                    /*
+                    print(JSON.stringify([
+                        this.ts.lookTok(1).data ,
+                        this.ts.lookTok(2).name ,
+                        this.ts.lookTok(3).type ,
+                        this.ts.lookTok(4).data ,
+                        this.ts.lookTok(5).data 
+                    ], null, 4));
+                    */
+                    if ( this.ts.lookTok(1).data == '=' &&
+                        this.ts.lookTok(2).name == 'NEW' &&
+                        this.ts.lookTok(3).type == 'NAME' &&
+                        this.ts.lookTok(4).data == '(' &&
+                        this.ts.lookTok(5).data == '{' 
+                        ) {
+                        scopeName = token.data;
+                        if (this.currentDoc) {
+                            this.addSymbol(scopeName,false,'OBJECT');
+                            
+                        }
+                        
+                        this.ts.nextTok(); /// =
+                        this.ts.nextTok(); /// new
+                        this.ts.nextTok(); /// yyy
+                        this.ts.nextTok(); /// (
+                        this.ts.nextTok(); /// {
+                            
+                        scopeName = fixAlias(scopeName);
+                        var fnScope = new Scope(this.braceNesting, scope, token.n, scopeName);
+                        this.indexedScopes[this.ts.cursor] = fnScope;
+                        scope = fnScope;
+                        this.scopesIn(fnScope);
+                         
+                        locBraceNest++;
+                        //print(">>" +locBraceNest);
+                        
+                        continue; // no more processing..
+                    }
+                    
+
+                     
+                    
+                    
+                    
+                    
+                    // eval can be prefixed with a hint hider for the compresser..
+                    
+                    
+                    if (this.currentDoc) {
+                        //print(token.toString());
+                        
+                        // ident : function ()
+                        // ident = function ()
+                        var atype = 'OBJECT';
+                        
+                        if (((this.ts.lookTok(1).data == ':' )|| (this.ts.lookTok(1).data == '=')) &&
+                            (this.ts.lookTok(2).name == "FUNCTION")
+                            ) {
+                               // this.ts.nextTok();
+                               // this.ts.nextTok();
+                                atype = 'FUNCTION';
+                        }
+                        
+                        //print("ADD SYM:" + atype + ":" + token.toString() + this.ts.lookTok(1).toString() + this.ts.lookTok(2).toString());
+                        
+                        this.addSymbol(
+                            this.ts.lookTok(-1).data == '.' ? token.data :    fixAlias(token.data),
+                            false,
+                            atype);
+                        
+                        this.currentDoc = false;
+                        
+                        
+                    }
+                 
+                    
+                    continue; // dont care about other idents..
+                    
+                }
+                
+                //print ("NOT NAME");
+                
+                
+                if (token.type == "STRN")   { // THIS WILL NOT HAPPEN HERE?!!?
+                    if (this.currentDoc) {
+                        this.addSymbol(token.data.substring(1,token.data.length-1),false,'OBJECT');
+
+                    }
+                }
+            
+                // really we only have to deal with object constructs and function calls that change the scope...
+                
+                
+                if (token.name == 'FUNCTION') {
+                    //print("GOT FUNCTION");
+                    // see if we have an unconsumed doc...
+                    
+                    if (this.currentDoc) {
+                            throw {
+                                name: "ArgumentError", 
+                                message: "Unhandled doc (TOKfunction)" + token.toString()
+                            };
+                            
+                            //this.addSymbol(this.currentDoc.getTag('class')[0].name, true);
+
+                            //throw "Unconsumed Doc: (TOKrbrace)" + this.currentDoc.toSource();
+                    }
+                    
+                     
+                     
+                     
+                     
+                    /// foo = function() {} << really it set's the 'this' scope to foo.prototype
+                    //$this$=foo.prototype|$private$|foo.prototype
+        
+                    if (
+                            (this.ts.lookTok(-1).data == '=') && 
+                            (this.ts.lookTok(-2).type == 'NAME')
+                        ) {
+                        scopeName = this.ts.lookTok(-2).data;
+                        this.ts.balance('(');
+                        token = this.ts.nextTok(); // should be {
+                        //print("FOO=FUNCITON() {}" + this.ts.context() + "\n" + token.toString());
+                        
+                        
+                        scopeName = fixAlias(scopeName);
+                        var fnScope = new Scope(this.braceNesting, scope, token.n, 
+                            '$this$='+scopeName+'.prototype|$private$|'+scopeName+'.prototype');
+                            
+                        this.indexedScopes[this.ts.cursor] = fnScope;
+                        //scope = fnScope;
+                        //this.scopesIn(fnScope);
+                        this.parseScope(fnScope, aliases);
+                        
+                        
+                       
+                        locBraceNest++;
+                        //print(">>" +locBraceNest);
+                        continue; // no more processing..    
+                          
+                        
+                    }
+                        
+                
+                // foo = new function() {}
+                        // is this actually used much!?!?!
+                        //$private$
+                        
+                    if (
+                            (this.ts.lookTok(-1).name == 'NEW') && 
+                            (this.ts.lookTok(-2).data == '=') &&
+                            (this.ts.lookTok(-3).type = 'FUNCTION')
+                        ) {
+                        //scopeName = this.ts.look(-3).data;
+                        this.ts.balance("(");
+                        token = this.ts.nextTok(); // should be {
+                            scopeName = fixAlias(scopeName);
+                        var fnScope = new Scope(this.braceNesting, scope, token.n, '$private$');
+                        this.indexedScopes[this.ts.cursor] = fnScope;
+                        //scope = fnScope;
+                        //this.scopesIn(fnScope);
+                        this.parseScope(fnScope, aliases);
+                        
+                        locBraceNest++;
+                        //print(">>" +locBraceNest);
+                        continue; // no more processing..    
+                          
+                        
+                    }    
+                   
+                    
+    ///==== check/set isObjectLitAr ??                
+                    
+                    
+                 // foo: function() {}
+                        // no change to scoping..
+                        
+                    //print("checking for : function() {"); 
+                    //print( [this.ts.lookTok(-3).type , this.ts.lookTok(-2).type , this.ts.lookTok(-1).type ].join(":"));
+                    if (
+                            (this.ts.lookTok(-1).data == ':') && 
+                            (this.ts.lookTok(-2).type == 'NAME') &&
+                            (this.ts.lookTok(-3).data == '(' || this.ts.lookTok(-3).data== ',') 
+                        ) {
+                        //print("got for : function() {"); 
+                            
+                        //scopeName = this.ts.look(-3).data;
+                        this.ts.balance('(');
+                        //print(token.toString())
+                        token = this.ts.nextTok(); // should be {
+                        //print(token.toString())
+                        scopeName = fixAlias(scopeName);
+                        var fnScope = new Scope(this.braceNesting, scope, token.n, '');
+                        this.indexedScopes[this.ts.cursor] = fnScope;
+                        //scope = fnScope;
+                        //this.scopesIn(fnScope);
+                         this.parseScope(fnScope, aliases);
+                        locBraceNest++;
+                        //print(">>" +locBraceNest);
+                        continue; // no more processing..    
+                          
+                    } 
+               /// function foo() {} << really it set's the 'this' scope to foo.prototype
+                        //$this$=foo|$private$
+                        //$this$=foo
+                        
+                    if (
+                            (this.ts.lookTok(1).type == 'NAME') 
+                        ) {
+                        //scopeName = this.ts.look(-3).data;
+                        this.ts.balance('(');
+                        token = this.ts.nextTok(); // should be {
+                            
+                        var fnScope = new Scope(this.braceNesting, scope, token.n, '');
+                        this.indexedScopes[this.ts.cursor] = fnScope;
+                        //scope = fnScope;
+                        //this.scopesIn(fnScope);
+                        this.parseScope(fnScope, aliases);
+                        locBraceNest++;
+                        //print(">>" +locBraceNest);
+                        continue; // no more processing..    
+                          
+                    }
+                    
+                     
+                // foo = new (function() { }
+                // (function() { }
+                // RETURN function(...) {
+                    
+                    if (
+                           // (this.ts.lookTok(-1).tokN == Script.TOKlparen) && 
+                            (this.ts.lookTok(1).name != 'NAME')   
+                            
+                        //    (this.ts.lookTok(-2).tokN == Script.TOKnew) &&
+                         //   (this.ts.lookTok(-3).tokN == Script.TOKassign) &&
+                         //   (this.ts.lookTok(-4).tokN == Script.TOKidentifier)
+                        ) {
+                        //scopeName = this.ts.look(-3).data;
+                        this.ts.balance('(');
+                        token = this.ts.nextTok(); // should be {
+                        var fnScope = new Scope(this.braceNesting, scope, token.n, '$private$');
+                        this.indexedScopes[this.ts.cursor] = fnScope;
+                        //scope = ;
+                        //this.scopesIn(fnScope);
+                         this.parseScope(fnScope, aliases);
+                        locBraceNest++;
+                        //print(">>" +locBraceNest);
+                        continue; // no more processing..    
+                          
+                        
+                    }
+                    
+                    
+                    throw {
+                        name: "ArgumentError", 
+                        message: "dont know how to handle function syntax??\n" +
+                                token.toString()
+                    };
+            
+                    
+                    continue;
+                    
+                    
+                    
+                    
+                } // end checking for TOKfunction
+                    
+                if (token.data == '{') {
+                    
+                     // foo = { // !var!!!
+                        //$this$=foo|Foo
+               
+                
+                    if (
+                            (this.ts.lookTok(-1).data == '=') &&
+                            (this.ts.lookTok(-2).type == 'NAME') &&
+                            (this.ts.lookTok(-3).nane != 'VAR')  
+                        ) {
+                            
+                            scopeName = this.ts.look(-2).data;
+                            scopeName = fixAlias(scopeName);
+                            var fnScope = new Scope(this.braceNesting, scope, token.n, 
+                                '$this$='+scopeName + '|'+scopeName
+                            );
+                            this.indexedScopes[this.ts.cursor] = fnScope;
+                            scope = fnScope;
+                            this.scopesIn(fnScope);
+                            
+                              
+                            locBraceNest++;
+                            //print(">>" +locBraceNest);
+                            continue; // no more processing..   
+                    }
+                    // foo : {
+                    // ?? add |foo| ????
+                      
+                    //print("GOT LBRACE : check for :");
+                    if (
+                            (this.ts.lookTok(-1).data == ':') &&
+                            (this.ts.lookTok(-2).type == 'NAME') &&
+                            (this.ts.lookTok(-3).name != 'VAR') 
+                        ) {
+                            
+                            scopeName = this.ts.lookTok(-2).data;
+                            scopeName = fixAlias(scopeName);
+                            var fnScope = new Scope(this.braceNesting, scope, token.n, scopeName);
+                            this.indexedScopes[this.ts.cursor] = fnScope;
+                            scope = fnScope;
+                            this.scopesIn(fnScope);
+                            
+                            locBraceNest++;
+                            //print(">>" +locBraceNest);
+                            continue; // no more processing..   
+                    }
+                    var fnScope = new Scope(this.braceNesting, scope, token.n, '');
+                    this.indexedScopes[this.ts.cursor] = fnScope;
+                    scope = fnScope;
+                    this.scopesIn(fnScope);
+                   
+                    locBraceNest++;
+                    //print(">>" +locBraceNest);
+                    continue;
+                    
+                }
+                if (token.data == '}') {
+                    
+                     
+                        if (this.currentDoc) {
+                            this.addSymbol('', true);
+
+                            //throw "Unconsumed Doc: (TOKrbrace)" + this.currentDoc.toSource();
+                        }
+                        
+                       
+                        locBraceNest--;
+                        
+                            //assert braceNesting >= scope.getBraceNesting();
+                        var closescope = this.scopeOut();   
+                        scope = this.scopes[this.scopes.length-1];
+                        //print("<<:" +  locBraceNest)
+                        //print("<<<<<< " + locBraceNest );
+                        if (locBraceNest < 0) {
+                           // print("POPED OF END OF SCOPE!");
+                            ///this.scopeOut();   
+                            //var ls = this.scopeOut();
+                            //ls.getUsedSymbols();
+                            return;
+                        }
+                        continue;
+                }
+              
+                
+            }
+            
+            
+        },
+     
+         
+        addSymbol: function(lastIdent, appendIt, atype )
+        {
+            //print("Walker.addSymbol : " + lastIdent);
+           // print("Walker.curdoc: " + JSON.stringify(this.currentDoc, null,4));
+            
+            /*if (!this.currentDoc.tags.length) {
+                
+              
+                //print(this.currentDoc.toSource());
+                //  this.currentDoc = false;
+                
+                print("SKIP ADD SYM: no tags");
+                print(this.currentDoc.src);
+                return;
+            }
+            */
+            if (this.currentDoc.getTag('private').length) {
+                
+              
+                //print(this.currentDoc.toSource());
+                 this.currentDoc = false;
+                //print("SKIP ADD SYM:  it's private");
+                return;
+            }
+            
+            var token = this.ts.lookTok(0);
+            if (typeof(appendIt) == 'undefined') {
+                appendIt= false;
+            }
+          //  print(this.currentDoc.toSource(););
+            if (this.currentDoc.getTag('event').length) {
+                //?? why does it end up in desc - and not name/...
+                //print(this.currentDoc.getTag('event')[0]);
+                lastIdent = '*' + this.currentDoc.getTag('event')[0].desc;
+                //lastIdent = '*' + lastIdent ;
+            }
+            if (!lastIdent.length && this.currentDoc.getTag('property').length) {
+                lastIdent = this.currentDoc.getTag('property')[0].name;
+                //lastIdent = '*' + lastIdent ;
+            }
+            
+            var _s = lastIdent;
+            if (!/\./.test(_s)) {
+                    
+                //print("WALKER ADDsymbol: " + lastIdent);
+                
+                var s = [];
+                for (var i = 0; i < this.scopes.length;i++) {
+                    s.push(this.scopes[i].ident);
+                }
+                s.push(lastIdent);
+                
+                //print("FULLSCOPE: " + JSON.stringify(s));
+                
+                
+                var s = s.join('|').split('|');
+                //print("FULLSCOPE: " + s);
+             //  print("Walker:ADDSymbol: " + s.join('|') );
+                var _t = '';
+                 _s = '';
+                
+                /// fixme - needs
+                for (var i = 0; i < s.length;i++) {
+                    
+                    if (!s[i].length) {
+                        continue;
+                    }
+                    if ((s[i] == '$private$') || (s[i] == '$global$')) {
+                        _s = '';
+                        continue;
+                    }
+                    if (s[i].substring(0,6) == '$this$') {
+                        var ts = s[i].split('=');
+                        _t = ts[1];
+                        _s = ''; // ??? VERY QUESTIONABLE!!!
+                        continue;
+                    }
+                    // when to use $this$ (probabl for events)
+                    _s += _s.length ? '.' : '';
+                    _s += s[i];
+                }
+                //print("FULLSCOPE: s , t : " + _s +', ' + _t);
+                
+                /// calc scope!!
+                //print("ADDING SYMBOL: "+ s.join('|') +"\n"+ _s + "\n" +Script.prettyDump(this.currentDoc.toSource()));
+                //print("Walker.addsymbol - add : " + _s);
+                if (appendIt && !lastIdent.length) {
+                    
+                    // append, and no symbol???
+                    
+                    // see if it's a @class
+                    if (this.currentDoc.getTag('class').length) {
+                        _s = this.currentDoc.getTag('class')[0].desc;
+                        var symbol = new Symbol(_s, [], "CONSTRUCTOR", this.currentDoc);
+                        Parser       = imports.Parser.Parser;
+                        Parser.addSymbol(symbol);
+                        this.symbols[_s] = symbol;
+                        return;
+                    }
+                    
+                   // if (this.currentDoc.getTag('property').length) {
+                     //   print(Script.pretStringtyDump(this.currentDoc.toSource));
+                    //    throw "Add Prop?";
+                    //}
+                    
+                    _s = _s.replace(/\.prototype.*$/, '');
+                    if (typeof(this.symbols[_s]) == 'undefined') {
+                        //print("Symbol:" + _s);
+                    //print(this.currentDoc.src);
+                        
+                        //throw {
+                        //    name: "ArgumentError", 
+                        //    message: "Trying to append symbol '" + _s + "', but no doc available\n" +
+                        //        this.ts.lookTok(0).toString()
+                        //};
+                        this.currentDoc = false;
+                        return;
+                     
+                    }
+                        
+                    for (var i =0; i < this.currentDoc.tags.length;i++) {
+                        this.symbols[_s].addDocTag(this.currentDoc.tags[i]);
+                    }
+                    this.currentDoc = false;
+                    return;
+                }
+            }    
+            //print("Walker.addsymbol - chkdup: " + _s);
+            if (typeof(this.symbols[_s]) != 'undefined') {
+                
+                if (this.symbols[_s].comment.hasTags) {
+                    // then existing comment doesnt has tags 
+                    //throw {
+                    //    name: "ArgumentError", 
+                     //   message:"DUPLICATE Symbol " + _s + "\n" + token.toString()
+                    //};
+                    return;
+                }
+                // otherwise existing comment has tags - overwrite..
+                
+                
+            }
+            //print("Walker.addsymbol - ATYPE: " + _s);
+
+            if (typeof(atype) == "undefined") {
+                atype = 'OBJECT'; //this.currentDoc.getTag('class').length ? 'OBJECT' : 'FUNCTION';;
+               }
+            
+            //print("Walker.addsymbol - add : ");
+            var symbol = new Symbol(_s, [], atype, this.currentDoc);
+            Parser       = imports.Parser.Parser;
+            Parser.addSymbol(symbol);
+            this.symbols[_s] = symbol;
+            
+             this.currentDoc = false;
+            
+        },
+        
+        
+        
+        
+        scopesIn : function(s)
+        {
+            this.scopes.push(s);
+            //print(">>>" + this.ts.context()  + "\n>>>"+this.scopes.length+":" +this.scopeListToStr());
+            
+        },
+        scopeOut : function()
+        {
+            
+           // print("<<<" + this.ts.context()  + "\n<<<"+this.scopes.length+":" +this.scopeListToStr());
+            return this.scopes.pop();
+            
+        },
+        
+        scopeListToStr : function()
+        {
+            var s = [];
+            for (var i = 0; i < this.scopes.length;i++) {
+                s.push(this.scopes[i].ident);
+            }
+            return  s.join('\n\t');
+            
+        }
+        
+    
+    
+     
+});
\ No newline at end of file