| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805 | 
							- /*
 
-   Copyright (C) 2012-2013 Yusuke Suzuki <utatane.tea@gmail.com>
 
-   Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com>
 
-   Redistribution and use in source and binary forms, with or without
 
-   modification, are permitted provided that the following conditions are met:
 
-     * Redistributions of source code must retain the above copyright
 
-       notice, this list of conditions and the following disclaimer.
 
-     * Redistributions in binary form must reproduce the above copyright
 
-       notice, this list of conditions and the following disclaimer in the
 
-       documentation and/or other materials provided with the distribution.
 
-   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 
-   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
-   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
-   ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
 
-   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 
-   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 
-   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 
-   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
-   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 
-   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
- */
 
- /*jslint vars:false, bitwise:true*/
 
- /*jshint indent:4*/
 
- /*global exports:true*/
 
- (function clone(exports) {
 
-     'use strict';
 
-     var Syntax,
 
-         VisitorOption,
 
-         VisitorKeys,
 
-         BREAK,
 
-         SKIP,
 
-         REMOVE;
 
-     function deepCopy(obj) {
 
-         var ret = {}, key, val;
 
-         for (key in obj) {
 
-             if (obj.hasOwnProperty(key)) {
 
-                 val = obj[key];
 
-                 if (typeof val === 'object' && val !== null) {
 
-                     ret[key] = deepCopy(val);
 
-                 } else {
 
-                     ret[key] = val;
 
-                 }
 
-             }
 
-         }
 
-         return ret;
 
-     }
 
-     // based on LLVM libc++ upper_bound / lower_bound
 
-     // MIT License
 
-     function upperBound(array, func) {
 
-         var diff, len, i, current;
 
-         len = array.length;
 
-         i = 0;
 
-         while (len) {
 
-             diff = len >>> 1;
 
-             current = i + diff;
 
-             if (func(array[current])) {
 
-                 len = diff;
 
-             } else {
 
-                 i = current + 1;
 
-                 len -= diff + 1;
 
-             }
 
-         }
 
-         return i;
 
-     }
 
-     Syntax = {
 
-         AssignmentExpression: 'AssignmentExpression',
 
-         AssignmentPattern: 'AssignmentPattern',
 
-         ArrayExpression: 'ArrayExpression',
 
-         ArrayPattern: 'ArrayPattern',
 
-         ArrowFunctionExpression: 'ArrowFunctionExpression',
 
-         AwaitExpression: 'AwaitExpression', // CAUTION: It's deferred to ES7.
 
-         BlockStatement: 'BlockStatement',
 
-         BinaryExpression: 'BinaryExpression',
 
-         BreakStatement: 'BreakStatement',
 
-         CallExpression: 'CallExpression',
 
-         CatchClause: 'CatchClause',
 
-         ChainExpression: 'ChainExpression',
 
-         ClassBody: 'ClassBody',
 
-         ClassDeclaration: 'ClassDeclaration',
 
-         ClassExpression: 'ClassExpression',
 
-         ComprehensionBlock: 'ComprehensionBlock',  // CAUTION: It's deferred to ES7.
 
-         ComprehensionExpression: 'ComprehensionExpression',  // CAUTION: It's deferred to ES7.
 
-         ConditionalExpression: 'ConditionalExpression',
 
-         ContinueStatement: 'ContinueStatement',
 
-         DebuggerStatement: 'DebuggerStatement',
 
-         DirectiveStatement: 'DirectiveStatement',
 
-         DoWhileStatement: 'DoWhileStatement',
 
-         EmptyStatement: 'EmptyStatement',
 
-         ExportAllDeclaration: 'ExportAllDeclaration',
 
-         ExportDefaultDeclaration: 'ExportDefaultDeclaration',
 
-         ExportNamedDeclaration: 'ExportNamedDeclaration',
 
-         ExportSpecifier: 'ExportSpecifier',
 
-         ExpressionStatement: 'ExpressionStatement',
 
-         ForStatement: 'ForStatement',
 
-         ForInStatement: 'ForInStatement',
 
-         ForOfStatement: 'ForOfStatement',
 
-         FunctionDeclaration: 'FunctionDeclaration',
 
-         FunctionExpression: 'FunctionExpression',
 
-         GeneratorExpression: 'GeneratorExpression',  // CAUTION: It's deferred to ES7.
 
-         Identifier: 'Identifier',
 
-         IfStatement: 'IfStatement',
 
-         ImportExpression: 'ImportExpression',
 
-         ImportDeclaration: 'ImportDeclaration',
 
-         ImportDefaultSpecifier: 'ImportDefaultSpecifier',
 
-         ImportNamespaceSpecifier: 'ImportNamespaceSpecifier',
 
-         ImportSpecifier: 'ImportSpecifier',
 
-         Literal: 'Literal',
 
-         LabeledStatement: 'LabeledStatement',
 
-         LogicalExpression: 'LogicalExpression',
 
-         MemberExpression: 'MemberExpression',
 
-         MetaProperty: 'MetaProperty',
 
-         MethodDefinition: 'MethodDefinition',
 
-         ModuleSpecifier: 'ModuleSpecifier',
 
-         NewExpression: 'NewExpression',
 
-         ObjectExpression: 'ObjectExpression',
 
-         ObjectPattern: 'ObjectPattern',
 
-         PrivateIdentifier: 'PrivateIdentifier',
 
-         Program: 'Program',
 
-         Property: 'Property',
 
-         PropertyDefinition: 'PropertyDefinition',
 
-         RestElement: 'RestElement',
 
-         ReturnStatement: 'ReturnStatement',
 
-         SequenceExpression: 'SequenceExpression',
 
-         SpreadElement: 'SpreadElement',
 
-         Super: 'Super',
 
-         SwitchStatement: 'SwitchStatement',
 
-         SwitchCase: 'SwitchCase',
 
-         TaggedTemplateExpression: 'TaggedTemplateExpression',
 
-         TemplateElement: 'TemplateElement',
 
-         TemplateLiteral: 'TemplateLiteral',
 
-         ThisExpression: 'ThisExpression',
 
-         ThrowStatement: 'ThrowStatement',
 
-         TryStatement: 'TryStatement',
 
-         UnaryExpression: 'UnaryExpression',
 
-         UpdateExpression: 'UpdateExpression',
 
-         VariableDeclaration: 'VariableDeclaration',
 
-         VariableDeclarator: 'VariableDeclarator',
 
-         WhileStatement: 'WhileStatement',
 
-         WithStatement: 'WithStatement',
 
-         YieldExpression: 'YieldExpression'
 
-     };
 
-     VisitorKeys = {
 
-         AssignmentExpression: ['left', 'right'],
 
-         AssignmentPattern: ['left', 'right'],
 
-         ArrayExpression: ['elements'],
 
-         ArrayPattern: ['elements'],
 
-         ArrowFunctionExpression: ['params', 'body'],
 
-         AwaitExpression: ['argument'], // CAUTION: It's deferred to ES7.
 
-         BlockStatement: ['body'],
 
-         BinaryExpression: ['left', 'right'],
 
-         BreakStatement: ['label'],
 
-         CallExpression: ['callee', 'arguments'],
 
-         CatchClause: ['param', 'body'],
 
-         ChainExpression: ['expression'],
 
-         ClassBody: ['body'],
 
-         ClassDeclaration: ['id', 'superClass', 'body'],
 
-         ClassExpression: ['id', 'superClass', 'body'],
 
-         ComprehensionBlock: ['left', 'right'],  // CAUTION: It's deferred to ES7.
 
-         ComprehensionExpression: ['blocks', 'filter', 'body'],  // CAUTION: It's deferred to ES7.
 
-         ConditionalExpression: ['test', 'consequent', 'alternate'],
 
-         ContinueStatement: ['label'],
 
-         DebuggerStatement: [],
 
-         DirectiveStatement: [],
 
-         DoWhileStatement: ['body', 'test'],
 
-         EmptyStatement: [],
 
-         ExportAllDeclaration: ['source'],
 
-         ExportDefaultDeclaration: ['declaration'],
 
-         ExportNamedDeclaration: ['declaration', 'specifiers', 'source'],
 
-         ExportSpecifier: ['exported', 'local'],
 
-         ExpressionStatement: ['expression'],
 
-         ForStatement: ['init', 'test', 'update', 'body'],
 
-         ForInStatement: ['left', 'right', 'body'],
 
-         ForOfStatement: ['left', 'right', 'body'],
 
-         FunctionDeclaration: ['id', 'params', 'body'],
 
-         FunctionExpression: ['id', 'params', 'body'],
 
-         GeneratorExpression: ['blocks', 'filter', 'body'],  // CAUTION: It's deferred to ES7.
 
-         Identifier: [],
 
-         IfStatement: ['test', 'consequent', 'alternate'],
 
-         ImportExpression: ['source'],
 
-         ImportDeclaration: ['specifiers', 'source'],
 
-         ImportDefaultSpecifier: ['local'],
 
-         ImportNamespaceSpecifier: ['local'],
 
-         ImportSpecifier: ['imported', 'local'],
 
-         Literal: [],
 
-         LabeledStatement: ['label', 'body'],
 
-         LogicalExpression: ['left', 'right'],
 
-         MemberExpression: ['object', 'property'],
 
-         MetaProperty: ['meta', 'property'],
 
-         MethodDefinition: ['key', 'value'],
 
-         ModuleSpecifier: [],
 
-         NewExpression: ['callee', 'arguments'],
 
-         ObjectExpression: ['properties'],
 
-         ObjectPattern: ['properties'],
 
-         PrivateIdentifier: [],
 
-         Program: ['body'],
 
-         Property: ['key', 'value'],
 
-         PropertyDefinition: ['key', 'value'],
 
-         RestElement: [ 'argument' ],
 
-         ReturnStatement: ['argument'],
 
-         SequenceExpression: ['expressions'],
 
-         SpreadElement: ['argument'],
 
-         Super: [],
 
-         SwitchStatement: ['discriminant', 'cases'],
 
-         SwitchCase: ['test', 'consequent'],
 
-         TaggedTemplateExpression: ['tag', 'quasi'],
 
-         TemplateElement: [],
 
-         TemplateLiteral: ['quasis', 'expressions'],
 
-         ThisExpression: [],
 
-         ThrowStatement: ['argument'],
 
-         TryStatement: ['block', 'handler', 'finalizer'],
 
-         UnaryExpression: ['argument'],
 
-         UpdateExpression: ['argument'],
 
-         VariableDeclaration: ['declarations'],
 
-         VariableDeclarator: ['id', 'init'],
 
-         WhileStatement: ['test', 'body'],
 
-         WithStatement: ['object', 'body'],
 
-         YieldExpression: ['argument']
 
-     };
 
-     // unique id
 
-     BREAK = {};
 
-     SKIP = {};
 
-     REMOVE = {};
 
-     VisitorOption = {
 
-         Break: BREAK,
 
-         Skip: SKIP,
 
-         Remove: REMOVE
 
-     };
 
-     function Reference(parent, key) {
 
-         this.parent = parent;
 
-         this.key = key;
 
-     }
 
-     Reference.prototype.replace = function replace(node) {
 
-         this.parent[this.key] = node;
 
-     };
 
-     Reference.prototype.remove = function remove() {
 
-         if (Array.isArray(this.parent)) {
 
-             this.parent.splice(this.key, 1);
 
-             return true;
 
-         } else {
 
-             this.replace(null);
 
-             return false;
 
-         }
 
-     };
 
-     function Element(node, path, wrap, ref) {
 
-         this.node = node;
 
-         this.path = path;
 
-         this.wrap = wrap;
 
-         this.ref = ref;
 
-     }
 
-     function Controller() { }
 
-     // API:
 
-     // return property path array from root to current node
 
-     Controller.prototype.path = function path() {
 
-         var i, iz, j, jz, result, element;
 
-         function addToPath(result, path) {
 
-             if (Array.isArray(path)) {
 
-                 for (j = 0, jz = path.length; j < jz; ++j) {
 
-                     result.push(path[j]);
 
-                 }
 
-             } else {
 
-                 result.push(path);
 
-             }
 
-         }
 
-         // root node
 
-         if (!this.__current.path) {
 
-             return null;
 
-         }
 
-         // first node is sentinel, second node is root element
 
-         result = [];
 
-         for (i = 2, iz = this.__leavelist.length; i < iz; ++i) {
 
-             element = this.__leavelist[i];
 
-             addToPath(result, element.path);
 
-         }
 
-         addToPath(result, this.__current.path);
 
-         return result;
 
-     };
 
-     // API:
 
-     // return type of current node
 
-     Controller.prototype.type = function () {
 
-         var node = this.current();
 
-         return node.type || this.__current.wrap;
 
-     };
 
-     // API:
 
-     // return array of parent elements
 
-     Controller.prototype.parents = function parents() {
 
-         var i, iz, result;
 
-         // first node is sentinel
 
-         result = [];
 
-         for (i = 1, iz = this.__leavelist.length; i < iz; ++i) {
 
-             result.push(this.__leavelist[i].node);
 
-         }
 
-         return result;
 
-     };
 
-     // API:
 
-     // return current node
 
-     Controller.prototype.current = function current() {
 
-         return this.__current.node;
 
-     };
 
-     Controller.prototype.__execute = function __execute(callback, element) {
 
-         var previous, result;
 
-         result = undefined;
 
-         previous  = this.__current;
 
-         this.__current = element;
 
-         this.__state = null;
 
-         if (callback) {
 
-             result = callback.call(this, element.node, this.__leavelist[this.__leavelist.length - 1].node);
 
-         }
 
-         this.__current = previous;
 
-         return result;
 
-     };
 
-     // API:
 
-     // notify control skip / break
 
-     Controller.prototype.notify = function notify(flag) {
 
-         this.__state = flag;
 
-     };
 
-     // API:
 
-     // skip child nodes of current node
 
-     Controller.prototype.skip = function () {
 
-         this.notify(SKIP);
 
-     };
 
-     // API:
 
-     // break traversals
 
-     Controller.prototype['break'] = function () {
 
-         this.notify(BREAK);
 
-     };
 
-     // API:
 
-     // remove node
 
-     Controller.prototype.remove = function () {
 
-         this.notify(REMOVE);
 
-     };
 
-     Controller.prototype.__initialize = function(root, visitor) {
 
-         this.visitor = visitor;
 
-         this.root = root;
 
-         this.__worklist = [];
 
-         this.__leavelist = [];
 
-         this.__current = null;
 
-         this.__state = null;
 
-         this.__fallback = null;
 
-         if (visitor.fallback === 'iteration') {
 
-             this.__fallback = Object.keys;
 
-         } else if (typeof visitor.fallback === 'function') {
 
-             this.__fallback = visitor.fallback;
 
-         }
 
-         this.__keys = VisitorKeys;
 
-         if (visitor.keys) {
 
-             this.__keys = Object.assign(Object.create(this.__keys), visitor.keys);
 
-         }
 
-     };
 
-     function isNode(node) {
 
-         if (node == null) {
 
-             return false;
 
-         }
 
-         return typeof node === 'object' && typeof node.type === 'string';
 
-     }
 
-     function isProperty(nodeType, key) {
 
-         return (nodeType === Syntax.ObjectExpression || nodeType === Syntax.ObjectPattern) && 'properties' === key;
 
-     }
 
-   
 
-     function candidateExistsInLeaveList(leavelist, candidate) {
 
-         for (var i = leavelist.length - 1; i >= 0; --i) {
 
-             if (leavelist[i].node === candidate) {
 
-                 return true;
 
-             }
 
-         }
 
-         return false;
 
-     }
 
-     Controller.prototype.traverse = function traverse(root, visitor) {
 
-         var worklist,
 
-             leavelist,
 
-             element,
 
-             node,
 
-             nodeType,
 
-             ret,
 
-             key,
 
-             current,
 
-             current2,
 
-             candidates,
 
-             candidate,
 
-             sentinel;
 
-         this.__initialize(root, visitor);
 
-         sentinel = {};
 
-         // reference
 
-         worklist = this.__worklist;
 
-         leavelist = this.__leavelist;
 
-         // initialize
 
-         worklist.push(new Element(root, null, null, null));
 
-         leavelist.push(new Element(null, null, null, null));
 
-         while (worklist.length) {
 
-             element = worklist.pop();
 
-             if (element === sentinel) {
 
-                 element = leavelist.pop();
 
-                 ret = this.__execute(visitor.leave, element);
 
-                 if (this.__state === BREAK || ret === BREAK) {
 
-                     return;
 
-                 }
 
-                 continue;
 
-             }
 
-             if (element.node) {
 
-                 ret = this.__execute(visitor.enter, element);
 
-                 if (this.__state === BREAK || ret === BREAK) {
 
-                     return;
 
-                 }
 
-                 worklist.push(sentinel);
 
-                 leavelist.push(element);
 
-                 if (this.__state === SKIP || ret === SKIP) {
 
-                     continue;
 
-                 }
 
-                 node = element.node;
 
-                 nodeType = node.type || element.wrap;
 
-                 candidates = this.__keys[nodeType];
 
-                 if (!candidates) {
 
-                     if (this.__fallback) {
 
-                         candidates = this.__fallback(node);
 
-                     } else {
 
-                         throw new Error('Unknown node type ' + nodeType + '.');
 
-                     }
 
-                 }
 
-                 current = candidates.length;
 
-                 while ((current -= 1) >= 0) {
 
-                     key = candidates[current];
 
-                     candidate = node[key];
 
-                     if (!candidate) {
 
-                         continue;
 
-                     }
 
-                     if (Array.isArray(candidate)) {
 
-                         current2 = candidate.length;
 
-                         while ((current2 -= 1) >= 0) {
 
-                             if (!candidate[current2]) {
 
-                                 continue;
 
-                             }
 
-                             if (candidateExistsInLeaveList(leavelist, candidate[current2])) {
 
-                               continue;
 
-                             }
 
-                             if (isProperty(nodeType, candidates[current])) {
 
-                                 element = new Element(candidate[current2], [key, current2], 'Property', null);
 
-                             } else if (isNode(candidate[current2])) {
 
-                                 element = new Element(candidate[current2], [key, current2], null, null);
 
-                             } else {
 
-                                 continue;
 
-                             }
 
-                             worklist.push(element);
 
-                         }
 
-                     } else if (isNode(candidate)) {
 
-                         if (candidateExistsInLeaveList(leavelist, candidate)) {
 
-                           continue;
 
-                         }
 
-                         worklist.push(new Element(candidate, key, null, null));
 
-                     }
 
-                 }
 
-             }
 
-         }
 
-     };
 
-     Controller.prototype.replace = function replace(root, visitor) {
 
-         var worklist,
 
-             leavelist,
 
-             node,
 
-             nodeType,
 
-             target,
 
-             element,
 
-             current,
 
-             current2,
 
-             candidates,
 
-             candidate,
 
-             sentinel,
 
-             outer,
 
-             key;
 
-         function removeElem(element) {
 
-             var i,
 
-                 key,
 
-                 nextElem,
 
-                 parent;
 
-             if (element.ref.remove()) {
 
-                 // When the reference is an element of an array.
 
-                 key = element.ref.key;
 
-                 parent = element.ref.parent;
 
-                 // If removed from array, then decrease following items' keys.
 
-                 i = worklist.length;
 
-                 while (i--) {
 
-                     nextElem = worklist[i];
 
-                     if (nextElem.ref && nextElem.ref.parent === parent) {
 
-                         if  (nextElem.ref.key < key) {
 
-                             break;
 
-                         }
 
-                         --nextElem.ref.key;
 
-                     }
 
-                 }
 
-             }
 
-         }
 
-         this.__initialize(root, visitor);
 
-         sentinel = {};
 
-         // reference
 
-         worklist = this.__worklist;
 
-         leavelist = this.__leavelist;
 
-         // initialize
 
-         outer = {
 
-             root: root
 
-         };
 
-         element = new Element(root, null, null, new Reference(outer, 'root'));
 
-         worklist.push(element);
 
-         leavelist.push(element);
 
-         while (worklist.length) {
 
-             element = worklist.pop();
 
-             if (element === sentinel) {
 
-                 element = leavelist.pop();
 
-                 target = this.__execute(visitor.leave, element);
 
-                 // node may be replaced with null,
 
-                 // so distinguish between undefined and null in this place
 
-                 if (target !== undefined && target !== BREAK && target !== SKIP && target !== REMOVE) {
 
-                     // replace
 
-                     element.ref.replace(target);
 
-                 }
 
-                 if (this.__state === REMOVE || target === REMOVE) {
 
-                     removeElem(element);
 
-                 }
 
-                 if (this.__state === BREAK || target === BREAK) {
 
-                     return outer.root;
 
-                 }
 
-                 continue;
 
-             }
 
-             target = this.__execute(visitor.enter, element);
 
-             // node may be replaced with null,
 
-             // so distinguish between undefined and null in this place
 
-             if (target !== undefined && target !== BREAK && target !== SKIP && target !== REMOVE) {
 
-                 // replace
 
-                 element.ref.replace(target);
 
-                 element.node = target;
 
-             }
 
-             if (this.__state === REMOVE || target === REMOVE) {
 
-                 removeElem(element);
 
-                 element.node = null;
 
-             }
 
-             if (this.__state === BREAK || target === BREAK) {
 
-                 return outer.root;
 
-             }
 
-             // node may be null
 
-             node = element.node;
 
-             if (!node) {
 
-                 continue;
 
-             }
 
-             worklist.push(sentinel);
 
-             leavelist.push(element);
 
-             if (this.__state === SKIP || target === SKIP) {
 
-                 continue;
 
-             }
 
-             nodeType = node.type || element.wrap;
 
-             candidates = this.__keys[nodeType];
 
-             if (!candidates) {
 
-                 if (this.__fallback) {
 
-                     candidates = this.__fallback(node);
 
-                 } else {
 
-                     throw new Error('Unknown node type ' + nodeType + '.');
 
-                 }
 
-             }
 
-             current = candidates.length;
 
-             while ((current -= 1) >= 0) {
 
-                 key = candidates[current];
 
-                 candidate = node[key];
 
-                 if (!candidate) {
 
-                     continue;
 
-                 }
 
-                 if (Array.isArray(candidate)) {
 
-                     current2 = candidate.length;
 
-                     while ((current2 -= 1) >= 0) {
 
-                         if (!candidate[current2]) {
 
-                             continue;
 
-                         }
 
-                         if (isProperty(nodeType, candidates[current])) {
 
-                             element = new Element(candidate[current2], [key, current2], 'Property', new Reference(candidate, current2));
 
-                         } else if (isNode(candidate[current2])) {
 
-                             element = new Element(candidate[current2], [key, current2], null, new Reference(candidate, current2));
 
-                         } else {
 
-                             continue;
 
-                         }
 
-                         worklist.push(element);
 
-                     }
 
-                 } else if (isNode(candidate)) {
 
-                     worklist.push(new Element(candidate, key, null, new Reference(node, key)));
 
-                 }
 
-             }
 
-         }
 
-         return outer.root;
 
-     };
 
-     function traverse(root, visitor) {
 
-         var controller = new Controller();
 
-         return controller.traverse(root, visitor);
 
-     }
 
-     function replace(root, visitor) {
 
-         var controller = new Controller();
 
-         return controller.replace(root, visitor);
 
-     }
 
-     function extendCommentRange(comment, tokens) {
 
-         var target;
 
-         target = upperBound(tokens, function search(token) {
 
-             return token.range[0] > comment.range[0];
 
-         });
 
-         comment.extendedRange = [comment.range[0], comment.range[1]];
 
-         if (target !== tokens.length) {
 
-             comment.extendedRange[1] = tokens[target].range[0];
 
-         }
 
-         target -= 1;
 
-         if (target >= 0) {
 
-             comment.extendedRange[0] = tokens[target].range[1];
 
-         }
 
-         return comment;
 
-     }
 
-     function attachComments(tree, providedComments, tokens) {
 
-         // At first, we should calculate extended comment ranges.
 
-         var comments = [], comment, len, i, cursor;
 
-         if (!tree.range) {
 
-             throw new Error('attachComments needs range information');
 
-         }
 
-         // tokens array is empty, we attach comments to tree as 'leadingComments'
 
-         if (!tokens.length) {
 
-             if (providedComments.length) {
 
-                 for (i = 0, len = providedComments.length; i < len; i += 1) {
 
-                     comment = deepCopy(providedComments[i]);
 
-                     comment.extendedRange = [0, tree.range[0]];
 
-                     comments.push(comment);
 
-                 }
 
-                 tree.leadingComments = comments;
 
-             }
 
-             return tree;
 
-         }
 
-         for (i = 0, len = providedComments.length; i < len; i += 1) {
 
-             comments.push(extendCommentRange(deepCopy(providedComments[i]), tokens));
 
-         }
 
-         // This is based on John Freeman's implementation.
 
-         cursor = 0;
 
-         traverse(tree, {
 
-             enter: function (node) {
 
-                 var comment;
 
-                 while (cursor < comments.length) {
 
-                     comment = comments[cursor];
 
-                     if (comment.extendedRange[1] > node.range[0]) {
 
-                         break;
 
-                     }
 
-                     if (comment.extendedRange[1] === node.range[0]) {
 
-                         if (!node.leadingComments) {
 
-                             node.leadingComments = [];
 
-                         }
 
-                         node.leadingComments.push(comment);
 
-                         comments.splice(cursor, 1);
 
-                     } else {
 
-                         cursor += 1;
 
-                     }
 
-                 }
 
-                 // already out of owned node
 
-                 if (cursor === comments.length) {
 
-                     return VisitorOption.Break;
 
-                 }
 
-                 if (comments[cursor].extendedRange[0] > node.range[1]) {
 
-                     return VisitorOption.Skip;
 
-                 }
 
-             }
 
-         });
 
-         cursor = 0;
 
-         traverse(tree, {
 
-             leave: function (node) {
 
-                 var comment;
 
-                 while (cursor < comments.length) {
 
-                     comment = comments[cursor];
 
-                     if (node.range[1] < comment.extendedRange[0]) {
 
-                         break;
 
-                     }
 
-                     if (node.range[1] === comment.extendedRange[0]) {
 
-                         if (!node.trailingComments) {
 
-                             node.trailingComments = [];
 
-                         }
 
-                         node.trailingComments.push(comment);
 
-                         comments.splice(cursor, 1);
 
-                     } else {
 
-                         cursor += 1;
 
-                     }
 
-                 }
 
-                 // already out of owned node
 
-                 if (cursor === comments.length) {
 
-                     return VisitorOption.Break;
 
-                 }
 
-                 if (comments[cursor].extendedRange[0] > node.range[1]) {
 
-                     return VisitorOption.Skip;
 
-                 }
 
-             }
 
-         });
 
-         return tree;
 
-     }
 
-     exports.Syntax = Syntax;
 
-     exports.traverse = traverse;
 
-     exports.replace = replace;
 
-     exports.attachComments = attachComments;
 
-     exports.VisitorKeys = VisitorKeys;
 
-     exports.VisitorOption = VisitorOption;
 
-     exports.Controller = Controller;
 
-     exports.cloneEnvironment = function () { return clone({}); };
 
-     return exports;
 
- }(exports));
 
- /* vim: set sw=4 ts=4 et tw=80 : */
 
 
  |