You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by da...@apache.org on 2019/12/18 17:56:31 UTC

[couchdb-escodegen] branch gh-pages created (now 6acfbc2)

This is an automated email from the ASF dual-hosted git repository.

davisp pushed a change to branch gh-pages
in repository https://gitbox.apache.org/repos/asf/couchdb-escodegen.git.


      at 6acfbc2  Merge pull request #227 from toothbrush7777777/patch-1

This branch includes the following new commits:

     new 480a003  First commit to gh-pages
     new 78548f5  Add index.html on the top
     new e3b815d  Insert redirect meta tag to /index.html
     new 9ede380  update escodegen.js
     new 590f4f8  script upgrade
     new b660de6  Update gh-pages
     new c6dc33c  Update browser escodegen.js
     new 8544537  www.esprima.org should be esprima.org
     new 578cfbd  Merge pull request #141 from jiyinyiyong/gh-pages
     new 141741c  Updated old URL and standardised the indenting
     new 6acfbc2  Merge pull request #227 from toothbrush7777777/patch-1

The 11 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[couchdb-escodegen] 07/11: Update browser escodegen.js

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch gh-pages
in repository https://gitbox.apache.org/repos/asf/couchdb-escodegen.git

commit c6dc33c3c95b5bc149b130f4cab3c4df9c6cd143
Author: Constellation <ut...@gmail.com>
AuthorDate: Wed Jan 23 10:13:12 2013 +0900

    Update browser escodegen.js
---
 demo/index.html                      |   2 +-
 escodegen.js => escodegen.browser.js | 900 +++++++++++++++++++++++++++++++----
 2 files changed, 819 insertions(+), 83 deletions(-)

diff --git a/demo/index.html b/demo/index.html
index e25c485..134c497 100644
--- a/demo/index.html
+++ b/demo/index.html
@@ -5,7 +5,7 @@
 	<title>JS code generator demo: JS → AST → JS</title>
   <link rel="stylesheet" href="../assets/style.css" type="text/css" />
   <script src='../assets/esprima.js'></script>
-  <script src='../escodegen.js'></script>
+  <script src='../escodegen.browser.js'></script>
   <script type="text/javascript">
 function $D(elm) {
   var range = document.createRange();
diff --git a/escodegen.js b/escodegen.browser.js
similarity index 76%
rename from escodegen.js
rename to escodegen.browser.js
index 5d8400e..2961fd5 100644
--- a/escodegen.js
+++ b/escodegen.browser.js
@@ -1,4 +1,442 @@
-/*
+// Generated by browserify
+(function(){var require = function (file, cwd) {
+    var resolved = require.resolve(file, cwd || '/');
+    var mod = require.modules[resolved];
+    if (!mod) throw new Error(
+        'Failed to resolve module ' + file + ', tried ' + resolved
+    );
+    var cached = require.cache[resolved];
+    var res = cached? cached.exports : mod();
+    return res;
+};
+
+require.paths = [];
+require.modules = {};
+require.cache = {};
+require.extensions = [".js",".coffee",".json"];
+
+require._core = {
+    'assert': true,
+    'events': true,
+    'fs': true,
+    'path': true,
+    'vm': true
+};
+
+require.resolve = (function () {
+    return function (x, cwd) {
+        if (!cwd) cwd = '/';
+        
+        if (require._core[x]) return x;
+        var path = require.modules.path();
+        cwd = path.resolve('/', cwd);
+        var y = cwd || '/';
+        
+        if (x.match(/^(?:\.\.?\/|\/)/)) {
+            var m = loadAsFileSync(path.resolve(y, x))
+                || loadAsDirectorySync(path.resolve(y, x));
+            if (m) return m;
+        }
+        
+        var n = loadNodeModulesSync(x, y);
+        if (n) return n;
+        
+        throw new Error("Cannot find module '" + x + "'");
+        
+        function loadAsFileSync (x) {
+            x = path.normalize(x);
+            if (require.modules[x]) {
+                return x;
+            }
+            
+            for (var i = 0; i < require.extensions.length; i++) {
+                var ext = require.extensions[i];
+                if (require.modules[x + ext]) return x + ext;
+            }
+        }
+        
+        function loadAsDirectorySync (x) {
+            x = x.replace(/\/+$/, '');
+            var pkgfile = path.normalize(x + '/package.json');
+            if (require.modules[pkgfile]) {
+                var pkg = require.modules[pkgfile]();
+                var b = pkg.browserify;
+                if (typeof b === 'object' && b.main) {
+                    var m = loadAsFileSync(path.resolve(x, b.main));
+                    if (m) return m;
+                }
+                else if (typeof b === 'string') {
+                    var m = loadAsFileSync(path.resolve(x, b));
+                    if (m) return m;
+                }
+                else if (pkg.main) {
+                    var m = loadAsFileSync(path.resolve(x, pkg.main));
+                    if (m) return m;
+                }
+            }
+            
+            return loadAsFileSync(x + '/index');
+        }
+        
+        function loadNodeModulesSync (x, start) {
+            var dirs = nodeModulesPathsSync(start);
+            for (var i = 0; i < dirs.length; i++) {
+                var dir = dirs[i];
+                var m = loadAsFileSync(dir + '/' + x);
+                if (m) return m;
+                var n = loadAsDirectorySync(dir + '/' + x);
+                if (n) return n;
+            }
+            
+            var m = loadAsFileSync(x);
+            if (m) return m;
+        }
+        
+        function nodeModulesPathsSync (start) {
+            var parts;
+            if (start === '/') parts = [ '' ];
+            else parts = path.normalize(start).split('/');
+            
+            var dirs = [];
+            for (var i = parts.length - 1; i >= 0; i--) {
+                if (parts[i] === 'node_modules') continue;
+                var dir = parts.slice(0, i + 1).join('/') + '/node_modules';
+                dirs.push(dir);
+            }
+            
+            return dirs;
+        }
+    };
+})();
+
+require.alias = function (from, to) {
+    var path = require.modules.path();
+    var res = null;
+    try {
+        res = require.resolve(from + '/package.json', '/');
+    }
+    catch (err) {
+        res = require.resolve(from, '/');
+    }
+    var basedir = path.dirname(res);
+    
+    var keys = (Object.keys || function (obj) {
+        var res = [];
+        for (var key in obj) res.push(key);
+        return res;
+    })(require.modules);
+    
+    for (var i = 0; i < keys.length; i++) {
+        var key = keys[i];
+        if (key.slice(0, basedir.length + 1) === basedir + '/') {
+            var f = key.slice(basedir.length);
+            require.modules[to + f] = require.modules[basedir + f];
+        }
+        else if (key === basedir) {
+            require.modules[to] = require.modules[basedir];
+        }
+    }
+};
+
+(function () {
+    var process = {};
+    var global = typeof window !== 'undefined' ? window : {};
+    var definedProcess = false;
+    
+    require.define = function (filename, fn) {
+        if (!definedProcess && require.modules.__browserify_process) {
+            process = require.modules.__browserify_process();
+            definedProcess = true;
+        }
+        
+        var dirname = require._core[filename]
+            ? ''
+            : require.modules.path().dirname(filename)
+        ;
+        
+        var require_ = function (file) {
+            var requiredModule = require(file, dirname);
+            var cached = require.cache[require.resolve(file, dirname)];
+
+            if (cached && cached.parent === null) {
+                cached.parent = module_;
+            }
+
+            return requiredModule;
+        };
+        require_.resolve = function (name) {
+            return require.resolve(name, dirname);
+        };
+        require_.modules = require.modules;
+        require_.define = require.define;
+        require_.cache = require.cache;
+        var module_ = {
+            id : filename,
+            filename: filename,
+            exports : {},
+            loaded : false,
+            parent: null
+        };
+        
+        require.modules[filename] = function () {
+            require.cache[filename] = module_;
+            fn.call(
+                module_.exports,
+                require_,
+                module_,
+                module_.exports,
+                dirname,
+                filename,
+                process,
+                global
+            );
+            module_.loaded = true;
+            return module_.exports;
+        };
+    };
+})();
+
+
+require.define("path",function(require,module,exports,__dirname,__filename,process,global){function filter (xs, fn) {
+    var res = [];
+    for (var i = 0; i < xs.length; i++) {
+        if (fn(xs[i], i, xs)) res.push(xs[i]);
+    }
+    return res;
+}
+
+// resolves . and .. elements in a path array with directory names there
+// must be no slashes, empty elements, or device names (c:\) in the array
+// (so also no leading and trailing slashes - it does not distinguish
+// relative and absolute paths)
+function normalizeArray(parts, allowAboveRoot) {
+  // if the path tries to go above the root, `up` ends up > 0
+  var up = 0;
+  for (var i = parts.length; i >= 0; i--) {
+    var last = parts[i];
+    if (last == '.') {
+      parts.splice(i, 1);
+    } else if (last === '..') {
+      parts.splice(i, 1);
+      up++;
+    } else if (up) {
+      parts.splice(i, 1);
+      up--;
+    }
+  }
+
+  // if the path is allowed to go above the root, restore leading ..s
+  if (allowAboveRoot) {
+    for (; up--; up) {
+      parts.unshift('..');
+    }
+  }
+
+  return parts;
+}
+
+// Regex to split a filename into [*, dir, basename, ext]
+// posix version
+var splitPathRe = /^(.+\/(?!$)|\/)?((?:.+?)?(\.[^.]*)?)$/;
+
+// path.resolve([from ...], to)
+// posix version
+exports.resolve = function() {
+var resolvedPath = '',
+    resolvedAbsolute = false;
+
+for (var i = arguments.length; i >= -1 && !resolvedAbsolute; i--) {
+  var path = (i >= 0)
+      ? arguments[i]
+      : process.cwd();
+
+  // Skip empty and invalid entries
+  if (typeof path !== 'string' || !path) {
+    continue;
+  }
+
+  resolvedPath = path + '/' + resolvedPath;
+  resolvedAbsolute = path.charAt(0) === '/';
+}
+
+// At this point the path should be resolved to a full absolute path, but
+// handle relative paths to be safe (might happen when process.cwd() fails)
+
+// Normalize the path
+resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) {
+    return !!p;
+  }), !resolvedAbsolute).join('/');
+
+  return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
+};
+
+// path.normalize(path)
+// posix version
+exports.normalize = function(path) {
+var isAbsolute = path.charAt(0) === '/',
+    trailingSlash = path.slice(-1) === '/';
+
+// Normalize the path
+path = normalizeArray(filter(path.split('/'), function(p) {
+    return !!p;
+  }), !isAbsolute).join('/');
+
+  if (!path && !isAbsolute) {
+    path = '.';
+  }
+  if (path && trailingSlash) {
+    path += '/';
+  }
+  
+  return (isAbsolute ? '/' : '') + path;
+};
+
+
+// posix version
+exports.join = function() {
+  var paths = Array.prototype.slice.call(arguments, 0);
+  return exports.normalize(filter(paths, function(p, index) {
+    return p && typeof p === 'string';
+  }).join('/'));
+};
+
+
+exports.dirname = function(path) {
+  var dir = splitPathRe.exec(path)[1] || '';
+  var isWindows = false;
+  if (!dir) {
+    // No dirname
+    return '.';
+  } else if (dir.length === 1 ||
+      (isWindows && dir.length <= 3 && dir.charAt(1) === ':')) {
+    // It is just a slash or a drive letter with a slash
+    return dir;
+  } else {
+    // It is a full dirname, strip trailing slash
+    return dir.substring(0, dir.length - 1);
+  }
+};
+
+
+exports.basename = function(path, ext) {
+  var f = splitPathRe.exec(path)[2] || '';
+  // TODO: make this comparison case-insensitive on windows?
+  if (ext && f.substr(-1 * ext.length) === ext) {
+    f = f.substr(0, f.length - ext.length);
+  }
+  return f;
+};
+
+
+exports.extname = function(path) {
+  return splitPathRe.exec(path)[3] || '';
+};
+
+exports.relative = function(from, to) {
+  from = exports.resolve(from).substr(1);
+  to = exports.resolve(to).substr(1);
+
+  function trim(arr) {
+    var start = 0;
+    for (; start < arr.length; start++) {
+      if (arr[start] !== '') break;
+    }
+
+    var end = arr.length - 1;
+    for (; end >= 0; end--) {
+      if (arr[end] !== '') break;
+    }
+
+    if (start > end) return [];
+    return arr.slice(start, end - start + 1);
+  }
+
+  var fromParts = trim(from.split('/'));
+  var toParts = trim(to.split('/'));
+
+  var length = Math.min(fromParts.length, toParts.length);
+  var samePartsLength = length;
+  for (var i = 0; i < length; i++) {
+    if (fromParts[i] !== toParts[i]) {
+      samePartsLength = i;
+      break;
+    }
+  }
+
+  var outputParts = [];
+  for (var i = samePartsLength; i < fromParts.length; i++) {
+    outputParts.push('..');
+  }
+
+  outputParts = outputParts.concat(toParts.slice(samePartsLength));
+
+  return outputParts.join('/');
+};
+
+});
+
+require.define("__browserify_process",function(require,module,exports,__dirname,__filename,process,global){var process = module.exports = {};
+
+process.nextTick = (function () {
+    var canSetImmediate = typeof window !== 'undefined'
+        && window.setImmediate;
+    var canPost = typeof window !== 'undefined'
+        && window.postMessage && window.addEventListener
+    ;
+
+    if (canSetImmediate) {
+        return function (f) { return window.setImmediate(f) };
+    }
+
+    if (canPost) {
+        var queue = [];
+        window.addEventListener('message', function (ev) {
+            if (ev.source === window && ev.data === 'browserify-tick') {
+                ev.stopPropagation();
+                if (queue.length > 0) {
+                    var fn = queue.shift();
+                    fn();
+                }
+            }
+        }, true);
+
+        return function nextTick(fn) {
+            queue.push(fn);
+            window.postMessage('browserify-tick', '*');
+        };
+    }
+
+    return function nextTick(fn) {
+        setTimeout(fn, 0);
+    };
+})();
+
+process.title = 'browser';
+process.browser = true;
+process.env = {};
+process.argv = [];
+
+process.binding = function (name) {
+    if (name === 'evals') return (require)('vm')
+    else throw new Error('No such module. (Possibly not yet loaded)')
+};
+
+(function () {
+    var cwd = '/';
+    var path;
+    process.cwd = function () { return cwd };
+    process.chdir = function (dir) {
+        if (!path) path = require('path');
+        cwd = path.resolve(dir, cwd);
+    };
+})();
+
+});
+
+require.define("/package.json",function(require,module,exports,__dirname,__filename,process,global){module.exports = {"main":"escodegen.js"}
+});
+
+require.define("/escodegen.js",function(require,module,exports,__dirname,__filename,process,global){/*
   Copyright (C) 2012 Michael Ficarra <es...@michael.ficarra.me>
   Copyright (C) 2012 Robert Gust-Bardon <do...@robert.gust-bardon.org>
   Copyright (C) 2012 John Freeman <jf...@gmail.com>
@@ -32,22 +470,7 @@
 
 /*jslint bitwise:true */
 /*global escodegen:true, exports:true, generateStatement:true, generateExpression:true, generateFunctionBody:true, process:true, require:true, define:true*/
-
-(function (factory, global) {
-    'use strict';
-
-    // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js,
-    // and plain browser loading,
-    if (typeof define === 'function' && define.amd) {
-        define(['exports'], function (exports) {
-            factory(exports, global);
-        });
-    } else if (typeof exports !== 'undefined') {
-        factory(exports, global);
-    } else {
-        factory((global.escodegen = {}), global);
-    }
-}(function (exports, global) {
+(function () {
     'use strict';
 
     var Syntax,
@@ -73,7 +496,10 @@
         directive,
         extra,
         parse,
-        sourceMap;
+        sourceMap,
+        traverse;
+
+    traverse = require('estraverse').traverse;
 
     Syntax = {
         AssignmentExpression: 'AssignmentExpression',
@@ -207,6 +633,7 @@
                 parenthesizedComprehensionBlock: false
             },
             sourceMap: null,
+            sourceMapRoot: null,
             sourceMapWithCode: false,
             directive: false,
             verbatim: null
@@ -806,17 +1233,18 @@
     }
 
     function generateExpression(expr, option) {
-        var result, precedence, currentPrecedence, i, len, raw, fragment, multiline, leftChar, leftSource, rightChar, rightSource, allowIn, allowCall, allowUnparenthesizedNew, property, key, value;
+        var result, precedence, type, currentPrecedence, i, len, raw, fragment, multiline, leftChar, leftSource, rightChar, rightSource, allowIn, allowCall, allowUnparenthesizedNew, property, key, value;
 
         precedence = option.precedence;
         allowIn = option.allowIn;
         allowCall = option.allowCall;
+        type = expr.type || option.type;
 
         if (extra.verbatim && expr.hasOwnProperty(extra.verbatim)) {
             return generateVerbatim(expr, option);
         }
 
-        switch (expr.type) {
+        switch (type) {
         case Syntax.SequenceExpression:
             result = [];
             allowIn |= (Precedence.Sequence < precedence);
@@ -1188,7 +1616,8 @@
                 fragment = generateExpression(expr.properties[0], {
                     precedence: Precedence.Sequence,
                     allowIn: true,
-                    allowCall: true
+                    allowCall: true,
+                    type: Syntax.Property
                 });
             });
 
@@ -1216,7 +1645,8 @@
                         result.push(indent, generateExpression(expr.properties[i], {
                             precedence: Precedence.Sequence,
                             allowIn: true,
-                            allowCall: true
+                            allowCall: true,
+                            type: Syntax.Property
                         }));
                         if (i + 1 < len) {
                             result.push(',' + newline);
@@ -1881,8 +2311,9 @@
         extra = options;
 
         if (sourceMap) {
-            if (typeof process !== 'undefined') {
+            if (!exports.browser) {
                 // We assume environment is node.js
+                // And prevent from including source-map by browserify
                 SourceNode = require('source-map').SourceNode;
             } else {
                 SourceNode = global.sourceMap.SourceNode;
@@ -1955,7 +2386,10 @@
             return result.toString();
         }
 
-        pair = result.toStringWithSourceMap({file: options.sourceMap});
+        pair = result.toStringWithSourceMap({
+            file: options.sourceMap,
+            sourceRoot: options.sourceMapRoot
+        });
 
         if (options.sourceMapWithCode) {
             return pair;
@@ -2017,62 +2451,6 @@
         Skip: 2
     };
 
-    function traverse(top, visitor) {
-        var worklist, leavelist, node, ret, current, current2, candidates, candidate, marker = {};
-
-        worklist = [ top ];
-        leavelist = [ null ];
-
-        while (worklist.length) {
-            node = worklist.pop();
-
-            if (node === marker) {
-                node = leavelist.pop();
-                if (visitor.leave) {
-                    ret = visitor.leave(node, leavelist[leavelist.length - 1]);
-                } else {
-                    ret = undefined;
-                }
-                if (ret === VisitorOption.Break) {
-                    return;
-                }
-            } else if (node) {
-                if (visitor.enter) {
-                    ret = visitor.enter(node, leavelist[leavelist.length - 1]);
-                } else {
-                    ret = undefined;
-                }
-
-                if (ret === VisitorOption.Break) {
-                    return;
-                }
-
-                worklist.push(marker);
-                leavelist.push(node);
-
-                if (ret !== VisitorOption.Skip) {
-                    candidates = VisitorKeys[node.type];
-                    current = candidates.length;
-                    while ((current -= 1) >= 0) {
-                        candidate = node[candidates[current]];
-                        if (candidate) {
-                            if (isArray(candidate)) {
-                                current2 = candidate.length;
-                                while ((current2 -= 1) >= 0) {
-                                    if (candidate[current2]) {
-                                        worklist.push(candidate[current2]);
-                                    }
-                                }
-                            } else {
-                                worklist.push(candidate);
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
     // based on LLVM libc++ upper_bound / lower_bound
     // MIT License
 
@@ -2238,8 +2616,366 @@
     exports.version = '0.0.16-dev';
 
     exports.generate = generate;
-    exports.traverse = traverse;
     exports.attachComments = attachComments;
+    exports.browser = false;
+}());
+/* vim: set sw=4 ts=4 et tw=80 : */
+
+});
+
+require.define("/node_modules/estraverse/package.json",function(require,module,exports,__dirname,__filename,process,global){module.exports = {"main":"estraverse.js"}
+});
+
+require.define("/node_modules/estraverse/estraverse.js",function(require,module,exports,__dirname,__filename,process,global){/*
+  Copyright (C) 2012 Yusuke Suzuki <ut...@gmail.com>
+  Copyright (C) 2012 Ariya Hidayat <ar...@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));
+  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 bitwise:true */
+/*global exports:true, define:true, window:true */
+(function (factory) {
+    'use strict';
+
+    // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js,
+    // and plain browser loading,
+    if (typeof define === 'function' && define.amd) {
+        define(['exports'], factory);
+    } else if (typeof exports !== 'undefined') {
+        factory(exports);
+    } else {
+        factory((window.estraverse = {}));
+    }
+}(function (exports) {
+    'use strict';
+
+    var Syntax,
+        isArray,
+        VisitorOption,
+        VisitorKeys,
+        wrappers;
+
+    Syntax = {
+        AssignmentExpression: 'AssignmentExpression',
+        ArrayExpression: 'ArrayExpression',
+        BlockStatement: 'BlockStatement',
+        BinaryExpression: 'BinaryExpression',
+        BreakStatement: 'BreakStatement',
+        CallExpression: 'CallExpression',
+        CatchClause: 'CatchClause',
+        ConditionalExpression: 'ConditionalExpression',
+        ContinueStatement: 'ContinueStatement',
+        DebuggerStatement: 'DebuggerStatement',
+        DirectiveStatement: 'DirectiveStatement',
+        DoWhileStatement: 'DoWhileStatement',
+        EmptyStatement: 'EmptyStatement',
+        ExpressionStatement: 'ExpressionStatement',
+        ForStatement: 'ForStatement',
+        ForInStatement: 'ForInStatement',
+        FunctionDeclaration: 'FunctionDeclaration',
+        FunctionExpression: 'FunctionExpression',
+        Identifier: 'Identifier',
+        IfStatement: 'IfStatement',
+        Literal: 'Literal',
+        LabeledStatement: 'LabeledStatement',
+        LogicalExpression: 'LogicalExpression',
+        MemberExpression: 'MemberExpression',
+        NewExpression: 'NewExpression',
+        ObjectExpression: 'ObjectExpression',
+        Program: 'Program',
+        Property: 'Property',
+        ReturnStatement: 'ReturnStatement',
+        SequenceExpression: 'SequenceExpression',
+        SwitchStatement: 'SwitchStatement',
+        SwitchCase: 'SwitchCase',
+        ThisExpression: 'ThisExpression',
+        ThrowStatement: 'ThrowStatement',
+        TryStatement: 'TryStatement',
+        UnaryExpression: 'UnaryExpression',
+        UpdateExpression: 'UpdateExpression',
+        VariableDeclaration: 'VariableDeclaration',
+        VariableDeclarator: 'VariableDeclarator',
+        WhileStatement: 'WhileStatement',
+        WithStatement: 'WithStatement'
+    };
+
+    isArray = Array.isArray;
+    if (!isArray) {
+        isArray = function isArray(array) {
+            return Object.prototype.toString.call(array) === '[object Array]';
+        };
+    }
+
+    VisitorKeys = {
+        AssignmentExpression: ['left', 'right'],
+        ArrayExpression: ['elements'],
+        BlockStatement: ['body'],
+        BinaryExpression: ['left', 'right'],
+        BreakStatement: ['label'],
+        CallExpression: ['callee', 'arguments'],
+        CatchClause: ['param', 'body'],
+        ConditionalExpression: ['test', 'consequent', 'alternate'],
+        ContinueStatement: ['label'],
+        DebuggerStatement: [],
+        DirectiveStatement: [],
+        DoWhileStatement: ['body', 'test'],
+        EmptyStatement: [],
+        ExpressionStatement: ['expression'],
+        ForStatement: ['init', 'test', 'update', 'body'],
+        ForInStatement: ['left', 'right', 'body'],
+        FunctionDeclaration: ['id', 'params', 'body'],
+        FunctionExpression: ['id', 'params', 'body'],
+        Identifier: [],
+        IfStatement: ['test', 'consequent', 'alternate'],
+        Literal: [],
+        LabeledStatement: ['label', 'body'],
+        LogicalExpression: ['left', 'right'],
+        MemberExpression: ['object', 'property'],
+        NewExpression: ['callee', 'arguments'],
+        ObjectExpression: ['properties'],
+        Program: ['body'],
+        Property: ['key', 'value'],
+        ReturnStatement: ['argument'],
+        SequenceExpression: ['expressions'],
+        SwitchStatement: ['discriminant', 'cases'],
+        SwitchCase: ['test', 'consequent'],
+        ThisExpression: [],
+        ThrowStatement: ['argument'],
+        TryStatement: ['block', 'handlers', 'finalizer'],
+        UnaryExpression: ['argument'],
+        UpdateExpression: ['argument'],
+        VariableDeclaration: ['declarations'],
+        VariableDeclarator: ['id', 'init'],
+        WhileStatement: ['test', 'body'],
+        WithStatement: ['object', 'body']
+    };
+
+    VisitorOption = {
+        Break: 1,
+        Skip: 2
+    };
+
+    wrappers = {
+        PropertyWrapper: 'Property'
+    };
+
+    function traverse(top, visitor) {
+        var worklist, leavelist, node, nodeType, ret, current, current2, candidates, candidate, marker = {};
+
+        worklist = [ top ];
+        leavelist = [ null ];
+
+        while (worklist.length) {
+            node = worklist.pop();
+            nodeType = node.type;
+
+            if (node === marker) {
+                node = leavelist.pop();
+                if (visitor.leave) {
+                    ret = visitor.leave(node, leavelist[leavelist.length - 1]);
+                } else {
+                    ret = undefined;
+                }
+                if (ret === VisitorOption.Break) {
+                    return;
+                }
+            } else if (node) {
+                if (wrappers.hasOwnProperty(nodeType)) {
+                    node = node.node;
+                    nodeType = wrappers[nodeType];
+                }
+
+                if (visitor.enter) {
+                    ret = visitor.enter(node, leavelist[leavelist.length - 1]);
+                } else {
+                    ret = undefined;
+                }
+
+                if (ret === VisitorOption.Break) {
+                    return;
+                }
+
+                worklist.push(marker);
+                leavelist.push(node);
+
+                if (ret !== VisitorOption.Skip) {
+                    candidates = VisitorKeys[nodeType];
+                    current = candidates.length;
+                    while ((current -= 1) >= 0) {
+                        candidate = node[candidates[current]];
+                        if (candidate) {
+                            if (isArray(candidate)) {
+                                current2 = candidate.length;
+                                while ((current2 -= 1) >= 0) {
+                                    if (candidate[current2]) {
+                                        if(nodeType === Syntax.ObjectExpression && 'properties' === candidates[current] && null == candidates[current].type) {
+                                            worklist.push({type: 'PropertyWrapper', node: candidate[current2]});
+                                        } else {
+                                            worklist.push(candidate[current2]);
+                                        }
+                                    }
+                                }
+                            } else {
+                                worklist.push(candidate);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    function replace(top, visitor) {
+        var worklist, leavelist, node, nodeType, target, tuple, ret, current, current2, candidates, candidate, marker = {}, result;
+
+        result = {
+            top: top
+        };
+
+        tuple = [ top, result, 'top' ];
+        worklist = [ tuple ];
+        leavelist = [ tuple ];
+
+        function notify(v) {
+            ret = v;
+        }
+
+        while (worklist.length) {
+            tuple = worklist.pop();
+
+            if (tuple === marker) {
+                tuple = leavelist.pop();
+                ret = undefined;
+                if (visitor.leave) {
+                    node = tuple[0];
+                    target = visitor.leave(tuple[0], leavelist[leavelist.length - 1][0], notify);
+                    if (target !== undefined) {
+                        node = target;
+                    }
+                    tuple[1][tuple[2]] = node;
+                }
+                if (ret === VisitorOption.Break) {
+                    return result.top;
+                }
+            } else if (tuple[0]) {
+                ret = undefined;
+                node = tuple[0];
+
+                nodeType = node.type;
+                if (wrappers.hasOwnProperty(nodeType)) {
+                    tuple[0] = node = node.node;
+                    nodeType = wrappers[nodeType];
+                }
+
+                if (visitor.enter) {
+                    target = visitor.enter(tuple[0], leavelist[leavelist.length - 1][0], notify);
+                    if (target !== undefined) {
+                        node = target;
+                    }
+                    tuple[1][tuple[2]] = node;
+                    tuple[0] = node;
+                }
+
+                if (ret === VisitorOption.Break) {
+                    return result.top;
+                }
+
+                if (tuple[0]) {
+                    worklist.push(marker);
+                    leavelist.push(tuple);
+
+                    if (ret !== VisitorOption.Skip) {
+                        candidates = VisitorKeys[nodeType];
+                        current = candidates.length;
+                        while ((current -= 1) >= 0) {
+                            candidate = node[candidates[current]];
+                            if (candidate) {
+                                if (isArray(candidate)) {
+                                    current2 = candidate.length;
+                                    while ((current2 -= 1) >= 0) {
+                                        if (candidate[current2]) {
+                                            if(nodeType === Syntax.ObjectExpression && 'properties' === candidates[current] && null == candidates[current].type) {
+                                                worklist.push([{type: 'PropertyWrapper', node: candidate[current2]}, candidate, current2]);
+                                            } else {
+                                                worklist.push([candidate[current2], candidate, current2]);
+                                            }
+                                        }
+                                    }
+                                } else {
+                                    worklist.push([candidate, node, candidates[current]]);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        return result.top;
+    }
+
+    exports.version = '0.0.4';
+    exports.Syntax = Syntax;
+    exports.traverse = traverse;
+    exports.replace = replace;
+    exports.VisitorKeys = VisitorKeys;
+    exports.VisitorOption = VisitorOption;
+}));
 /* vim: set sw=4 ts=4 et tw=80 : */
+
+});
+
+require.define("/tools/entry-point.js",function(require,module,exports,__dirname,__filename,process,global){/*
+  Copyright (C) 2012 Yusuke Suzuki <ut...@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.
+*/
+
+(function () {
+    'use strict';
+    var escodegen;
+    escodegen = global.escodegen = require('../escodegen');
+    escodegen.browser = true;
+}());
+
+});
+require("/tools/entry-point.js");
+})();
+


[couchdb-escodegen] 04/11: update escodegen.js

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch gh-pages
in repository https://gitbox.apache.org/repos/asf/couchdb-escodegen.git

commit 9ede3805d6979391dd58e2ad7dde7b3e8d349b40
Author: Constellation <ut...@gmail.com>
AuthorDate: Sun May 13 12:19:20 2012 +0900

    update escodegen.js
---
 escodegen.js | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 74 insertions(+), 11 deletions(-)

diff --git a/escodegen.js b/escodegen.js
index b4ea9ad..0590190 100644
--- a/escodegen.js
+++ b/escodegen.js
@@ -133,10 +133,19 @@
         '/': Precedence.Multiplicative
     };
 
-    if (typeof Object.freeze === 'function') {
-        Object.freeze(Syntax);
-        Object.freeze(Precedence);
-        Object.freeze(BinaryPrecedence);
+    function getDefaultOptions() {
+        // default options
+        return {
+            indent: null,
+            base: null,
+            parse: null,
+            format: {
+                indent: {
+                    style: '    ',
+                    base: 0
+                }
+            }
+        };
     }
 
     function unicodeEscape(ch) {
@@ -158,6 +167,42 @@
         return result;
     }
 
+    function stringRepeat(str, num) {
+        var result = '';
+
+        for (num |= 0; num > 0; num >>>= 1, str += str) {
+            if (num & 1) {
+                result += str;
+            }
+        }
+
+        return result;
+    }
+
+    function updateDeeply(target, override) {
+        var key, val;
+
+        function isHashObject(target) {
+            return typeof target === 'object' && target instanceof Object && !(target instanceof RegExp);
+        }
+
+        for (key in override) {
+            if (override.hasOwnProperty(key)) {
+                val = override[key];
+                if (isHashObject(val)) {
+                    if (isHashObject(target[key])) {
+                        updateDeeply(target[key], val);
+                    } else {
+                        target[key] = updateDeeply({}, val);
+                    }
+                } else {
+                    target[key] = val;
+                }
+            }
+        }
+        return target;
+    }
+
     function escapeString(str) {
         var result = '', i, len, ch;
 
@@ -723,7 +768,7 @@
         case Syntax.Program:
             result = '';
             for (i = 0, len = stmt.body.length; i < len; i += 1) {
-                result += generateStatement(stmt.body[i]);
+                result += addIndent(generateStatement(stmt.body[i]));
                 if ((i + 1) < len) {
                     result += '\n';
                 }
@@ -773,14 +818,32 @@
     }
 
     function generate(node, options) {
+        var defaultOptions = getDefaultOptions();
+
         if (typeof options !== 'undefined') {
-            base = options.base || '';
-            indent = options.indent || '    ';
+            // Obsolete options
+            //
+            //   `options.indent`
+            //   `options.base`
+            //
+            // Instead of them, we can use `option.format.indent`.
+            if (typeof options.indent === 'string') {
+                defaultOptions.format.indent.style = options.indent;
+            }
+
+            options = updateDeeply(defaultOptions, options);
+            indent = options.format.indent.style;
+            if (typeof options.base === 'string') {
+                base = options.base;
+            } else {
+                base = stringRepeat(indent, options.format.indent.base);
+            }
             parse = options.parse;
         } else {
-            base = '';
-            indent = '    ';
-            parse = null;
+            options = defaultOptions;
+            indent = options.format.indent.style;
+            base = stringRepeat(indent, options.format.indent.base);
+            parse = options.parse;
         }
 
         switch (node.type) {
@@ -835,7 +898,7 @@
     }
 
     // Sync with package.json.
-    exports.version = '0.0.3-dev';
+    exports.version = '0.0.4-dev';
 
     exports.generate = generate;
 


[couchdb-escodegen] 06/11: Update gh-pages

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch gh-pages
in repository https://gitbox.apache.org/repos/asf/couchdb-escodegen.git

commit b660de6b026d7d2b49092f10e0f59ed1d7fd46f7
Author: Constellation <ut...@gmail.com>
AuthorDate: Mon Jan 14 19:05:42 2013 +0900

    Update gh-pages
---
 escodegen.js | 1826 ++++++++++++++++++++++++++++++++++++++++------------------
 1 file changed, 1272 insertions(+), 554 deletions(-)

diff --git a/escodegen.js b/escodegen.js
index 59087f6..5d8400e 100644
--- a/escodegen.js
+++ b/escodegen.js
@@ -1,12 +1,13 @@
 /*
+  Copyright (C) 2012 Michael Ficarra <es...@michael.ficarra.me>
+  Copyright (C) 2012 Robert Gust-Bardon <do...@robert.gust-bardon.org>
   Copyright (C) 2012 John Freeman <jf...@gmail.com>
-  Copyright (C) 2012 Ariya Hidayat <ar...@gmail.com>
+  Copyright (C) 2011-2012 Ariya Hidayat <ar...@gmail.com>
   Copyright (C) 2012 Mathias Bynens <ma...@qiwi.be>
   Copyright (C) 2012 Joost-Wim Boekesteijn <jo...@boekesteijn.nl>
   Copyright (C) 2012 Kris Kowal <kr...@cixar.com>
   Copyright (C) 2012 Yusuke Suzuki <ut...@gmail.com>
   Copyright (C) 2012 Arpad Borsos <ar...@googlemail.com>
-  Copyright (C) 2011 Ariya Hidayat <ar...@gmail.com>
 
   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:
@@ -30,32 +31,64 @@
 */
 
 /*jslint bitwise:true */
-/*global escodegen:true, exports:true, generateStatement: true*/
+/*global escodegen:true, exports:true, generateStatement:true, generateExpression:true, generateFunctionBody:true, process:true, require:true, define:true*/
 
-(function (exports) {
+(function (factory, global) {
+    'use strict';
+
+    // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js,
+    // and plain browser loading,
+    if (typeof define === 'function' && define.amd) {
+        define(['exports'], function (exports) {
+            factory(exports, global);
+        });
+    } else if (typeof exports !== 'undefined') {
+        factory(exports, global);
+    } else {
+        factory((global.escodegen = {}), global);
+    }
+}(function (exports, global) {
     'use strict';
 
     var Syntax,
         Precedence,
         BinaryPrecedence,
+        Regex,
         VisitorKeys,
         VisitorOption,
+        SourceNode,
         isArray,
         base,
         indent,
+        json,
+        renumber,
+        hexadecimal,
+        quotes,
+        escapeless,
+        newline,
+        space,
+        parentheses,
+        semicolons,
+        safeConcatenation,
+        directive,
         extra,
-        parse;
+        parse,
+        sourceMap;
 
     Syntax = {
         AssignmentExpression: 'AssignmentExpression',
         ArrayExpression: 'ArrayExpression',
+        ArrayPattern: 'ArrayPattern',
         BlockStatement: 'BlockStatement',
         BinaryExpression: 'BinaryExpression',
         BreakStatement: 'BreakStatement',
         CallExpression: 'CallExpression',
         CatchClause: 'CatchClause',
+        ComprehensionBlock: 'ComprehensionBlock',
+        ComprehensionExpression: 'ComprehensionExpression',
         ConditionalExpression: 'ConditionalExpression',
         ContinueStatement: 'ContinueStatement',
+        DirectiveStatement: 'DirectiveStatement',
         DoWhileStatement: 'DoWhileStatement',
         DebuggerStatement: 'DebuggerStatement',
         EmptyStatement: 'EmptyStatement',
@@ -72,6 +105,7 @@
         MemberExpression: 'MemberExpression',
         NewExpression: 'NewExpression',
         ObjectExpression: 'ObjectExpression',
+        ObjectPattern: 'ObjectPattern',
         Program: 'Program',
         Property: 'Property',
         ReturnStatement: 'ReturnStatement',
@@ -86,7 +120,9 @@
         VariableDeclaration: 'VariableDeclaration',
         VariableDeclarator: 'VariableDeclarator',
         WhileStatement: 'WhileStatement',
-        WithStatement: 'WithStatement'
+        WithStatement: 'WithStatement',
+        YieldExpression: 'YieldExpression',
+
     };
 
     Precedence = {
@@ -95,8 +131,8 @@
         Conditional: 2,
         LogicalOR: 3,
         LogicalAND: 4,
-        LogicalXOR: 5,
-        BitwiseOR: 6,
+        BitwiseOR: 5,
+        BitwiseXOR: 6,
         BitwiseAND: 7,
         Equality: 8,
         Relational: 9,
@@ -114,13 +150,15 @@
     BinaryPrecedence = {
         '||': Precedence.LogicalOR,
         '&&': Precedence.LogicalAND,
-        '^': Precedence.LogicalXOR,
         '|': Precedence.BitwiseOR,
+        '^': Precedence.BitwiseXOR,
         '&': Precedence.BitwiseAND,
         '==': Precedence.Equality,
         '!=': Precedence.Equality,
         '===': Precedence.Equality,
         '!==': Precedence.Equality,
+        'is': Precedence.Equality,
+        'isnt': Precedence.Equality,
         '<': Precedence.Relational,
         '>': Precedence.Relational,
         '<=': Precedence.Relational,
@@ -137,6 +175,10 @@
         '/': Precedence.Multiplicative
     };
 
+    Regex = {
+        NonAsciiIdentifierPart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0300-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u0483-\u0487\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u05d0-\u05ea\u05f0-\u05f2\u0610-\u061a\u0620-\u0669\u066e-\u06d3\u06d5-\u06dc\u06df-\u06e8\u06ea-\u06fc\u06ff\u0710-\u074a\u074d-\u07b1\u07c0-\u07f5\u07fa\u08 [...]
+    };
+
     function getDefaultOptions() {
         // default options
         return {
@@ -149,20 +191,28 @@
                     style: '    ',
                     base: 0,
                     adjustMultilineComment: false
-                }
-            }
+                },
+                json: false,
+                renumber: false,
+                hexadecimal: false,
+                quotes: 'single',
+                escapeless: false,
+                compact: false,
+                parentheses: true,
+                semicolons: true,
+                safeConcatenation: false
+            },
+            moz: {
+                starlessGenerator: false,
+                parenthesizedComprehensionBlock: false
+            },
+            sourceMap: null,
+            sourceMapWithCode: false,
+            directive: false,
+            verbatim: null
         };
     }
 
-    function unicodeEscape(ch) {
-        var result, i;
-        result = ch.charCodeAt(0).toString(16);
-        for (i = result.length; i < 4; i += 1) {
-            result = '0' + result;
-        }
-        return '\\u' + result;
-    }
-
     function stringToArray(str) {
         var length = str.length,
             result = [],
@@ -192,8 +242,73 @@
         };
     }
 
-    function endsWithLineTerminator(value) {
-        return (/(?:\r\n|[\n\r])$/).test(value);
+    // Fallback for the non SourceMap environment
+    function SourceNodeMock(line, column, filename, chunk) {
+        var result = [];
+
+        function flatten(input) {
+            var i, iz;
+            if (isArray(input)) {
+                for (i = 0, iz = input.length; i < iz; ++i) {
+                    flatten(input[i]);
+                }
+            } else if (input instanceof SourceNodeMock) {
+                result.push(input);
+            } else if (typeof input === 'string' && input) {
+                result.push(input);
+            }
+        }
+
+        flatten(chunk);
+        this.children = result;
+    }
+
+    SourceNodeMock.prototype.toString = function toString() {
+        var res = '', i, iz, node;
+        for (i = 0, iz = this.children.length; i < iz; ++i) {
+            node = this.children[i];
+            if (node instanceof SourceNodeMock) {
+                res += node.toString();
+            } else {
+                res += node;
+            }
+        }
+        return res;
+    };
+
+    SourceNodeMock.prototype.replaceRight = function replaceRight(pattern, replacement) {
+        var last = this.children[this.children.length - 1];
+        if (last instanceof SourceNodeMock) {
+            last.replaceRight(pattern, replacement);
+        } else if (typeof last === 'string') {
+            this.children[this.children.length - 1] = last.replace(pattern, replacement);
+        } else {
+            this.children.push(''.replace(pattern, replacement));
+        }
+        return this;
+    };
+
+    SourceNodeMock.prototype.join = function join(sep) {
+        var i, iz, result;
+        result = [];
+        iz = this.children.length;
+        if (iz > 0) {
+            for (i = 0, iz -= 1; i < iz; ++i) {
+                result.push(this.children[i], sep);
+            }
+            result.push(this.children[iz]);
+            this.children = result;
+        }
+        return this;
+    };
+
+    function hasLineTerminator(str) {
+        return /[\r\n]/g.test(str);
+    }
+
+    function endsWithLineTerminator(str) {
+        var ch = str.charAt(str.length - 1);
+        return ch === '\r' || ch === '\n';
     }
 
     function shallowCopy(obj) {
@@ -245,8 +360,142 @@
         return target;
     }
 
+    function generateNumber(value) {
+        var result, point, temp, exponent, pos;
+
+        if (value !== value) {
+            throw new Error('Numeric literal whose value is NaN');
+        }
+        if (value < 0 || (value === 0 && 1 / value < 0)) {
+            throw new Error('Numeric literal whose value is negative');
+        }
+
+        if (value === 1 / 0) {
+            return json ? 'null' : renumber ? '1e400' : '1e+400';
+        }
+
+        result = '' + value;
+        if (!renumber || result.length < 3) {
+            return result;
+        }
+
+        point = result.indexOf('.');
+        if (!json && result.charAt(0) === '0' && point === 1) {
+            point = 0;
+            result = result.slice(1);
+        }
+        temp = result;
+        result = result.replace('e+', 'e');
+        exponent = 0;
+        if ((pos = temp.indexOf('e')) > 0) {
+            exponent = +temp.slice(pos + 1);
+            temp = temp.slice(0, pos);
+        }
+        if (point >= 0) {
+            exponent -= temp.length - point - 1;
+            temp = +(temp.slice(0, point) + temp.slice(point + 1)) + '';
+        }
+        pos = 0;
+        while (temp.charAt(temp.length + pos - 1) === '0') {
+            pos -= 1;
+        }
+        if (pos !== 0) {
+            exponent -= pos;
+            temp = temp.slice(0, pos);
+        }
+        if (exponent !== 0) {
+            temp += 'e' + exponent;
+        }
+        if ((temp.length < result.length ||
+                    (hexadecimal && value > 1e12 && Math.floor(value) === value && (temp = '0x' + value.toString(16)).length < result.length)) &&
+                +temp === value) {
+            result = temp;
+        }
+
+        return result;
+    }
+
+    function escapeAllowedCharacter(ch, next) {
+        var code = ch.charCodeAt(0), hex = code.toString(16), result = '\\';
+
+        switch (ch) {
+        case '\b':
+            result += 'b';
+            break;
+        case '\f':
+            result += 'f';
+            break;
+        case '\t':
+            result += 't';
+            break;
+        default:
+            if (json || code > 0xff) {
+                result += 'u' + '0000'.slice(hex.length) + hex;
+            } else if (ch === '\u0000' && '0123456789'.indexOf(next) < 0) {
+                result += '0';
+            } else if (ch === '\v') {
+                result += 'v';
+            } else {
+                result += 'x' + '00'.slice(hex.length) + hex;
+            }
+            break;
+        }
+
+        return result;
+    }
+
+    function escapeDisallowedCharacter(ch) {
+        var result = '\\';
+        switch (ch) {
+        case '\\':
+            result += '\\';
+            break;
+        case '\n':
+            result += 'n';
+            break;
+        case '\r':
+            result += 'r';
+            break;
+        case '\u2028':
+            result += 'u2028';
+            break;
+        case '\u2029':
+            result += 'u2029';
+            break;
+        default:
+            throw new Error('Incorrectly classified character');
+        }
+
+        return result;
+    }
+
+    function escapeDirective(str) {
+        var i, iz, ch, single, buf, quote;
+
+        buf = str;
+        if (typeof buf[0] === 'undefined') {
+            buf = stringToArray(buf);
+        }
+
+        quote = quotes === 'double' ? '"' : '\'';
+        for (i = 0, iz = buf.length; i < iz; i += 1) {
+            ch = buf[i];
+            if (ch === '\'') {
+                quote = '"';
+                break;
+            } else if (ch === '"') {
+                quote = '\'';
+                break;
+            } else if (ch === '\\') {
+                i += 1;
+            }
+        }
+
+        return quote + str + quote;
+    }
+
     function escapeString(str) {
-        var result = '', i, len, ch;
+        var result = '', i, len, ch, next, singleQuotes = 0, doubleQuotes = 0, single;
 
         if (typeof str[0] === 'undefined') {
             str = stringToArray(str);
@@ -254,57 +503,112 @@
 
         for (i = 0, len = str.length; i < len; i += 1) {
             ch = str[i];
-            if ('\'\\\b\f\n\r\t'.indexOf(ch) >= 0) {
+            if (ch === '\'') {
+                singleQuotes += 1;
+            } else if (ch === '"') {
+                doubleQuotes += 1;
+            } else if (ch === '/' && json) {
+                result += '\\';
+            } else if ('\\\n\r\u2028\u2029'.indexOf(ch) >= 0) {
+                result += escapeDisallowedCharacter(ch);
+                continue;
+            } else if ((json && ch < ' ') || !(json || escapeless || (ch >= ' ' && ch <= '~'))) {
+                result += escapeAllowedCharacter(ch, str[i + 1]);
+                continue;
+            }
+            result += ch;
+        }
+
+        single = !(quotes === 'double' || (quotes === 'auto' && doubleQuotes < singleQuotes));
+        str = result;
+        result = single ? '\'' : '"';
+
+        if (typeof str[0] === 'undefined') {
+            str = stringToArray(str);
+        }
+
+        for (i = 0, len = str.length; i < len; i += 1) {
+            ch = str[i];
+            if ((ch === '\'' && single) || (ch === '"' && !single)) {
                 result += '\\';
-                switch (ch) {
-                case '\'':
-                    result += '\'';
-                    break;
-                case '\\':
-                    result += '\\';
-                    break;
-                case '\b':
-                    result += 'b';
-                    break;
-                case '\f':
-                    result += 'f';
-                    break;
-                case '\n':
-                    result += 'n';
-                    break;
-                case '\r':
-                    result += 'r';
-                    break;
-                case '\t':
-                    result += 't';
-                    break;
-                }
-            } else if (ch < ' ' || ch.charCodeAt(0) >= 0x80) {
-                result += unicodeEscape(ch);
-            } else {
-                result += ch;
             }
+            result += ch;
         }
 
-        return '\'' + result + '\'';
+        return result + (single ? '\'' : '"');
     }
 
     function isWhiteSpace(ch) {
-        return (ch === ' ') || (ch === '\u0009') || (ch === '\u000B') ||
-            (ch === '\u000C') || (ch === '\u00A0') ||
-            (ch.charCodeAt(0) >= 0x1680 &&
-             '\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\uFEFF'.indexOf(ch) >= 0);
+        return '\t\v\f \xa0'.indexOf(ch) >= 0 || (ch.charCodeAt(0) >= 0x1680 && '\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\ufeff'.indexOf(ch) >= 0);
+    }
+
+    function isLineTerminator(ch) {
+        return '\n\r\u2028\u2029'.indexOf(ch) >= 0;
+    }
+
+    function isIdentifierPart(ch) {
+        return (ch === '$') || (ch === '_') || (ch === '\\') ||
+            (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
+            ((ch >= '0') && (ch <= '9')) ||
+            ((ch.charCodeAt(0) >= 0x80) && Regex.NonAsciiIdentifierPart.test(ch));
+    }
+
+    function toSourceNode(generated, node) {
+        if (node == null) {
+            if (generated instanceof SourceNode) {
+                return generated;
+            } else {
+                node = {};
+            }
+        }
+        if (node.loc == null) {
+            return new SourceNode(null, null, sourceMap, generated);
+        }
+        return new SourceNode(node.loc.start.line, node.loc.start.column, (sourceMap === true ? node.loc.source || null : sourceMap), generated);
+    }
+
+    function join(left, right) {
+        var leftSource = toSourceNode(left).toString(),
+            rightSource = toSourceNode(right).toString(),
+            leftChar = leftSource.charAt(leftSource.length - 1),
+            rightChar = rightSource.charAt(0);
+
+        if (((leftChar === '+' || leftChar === '-') && leftChar === rightChar) || (isIdentifierPart(leftChar) && isIdentifierPart(rightChar))) {
+            return [left, ' ', right];
+        } else if (isWhiteSpace(leftChar) || isLineTerminator(leftChar) || isWhiteSpace(rightChar) || isLineTerminator(rightChar)) {
+            return [left, right];
+        }
+        return [left, space, right];
     }
 
     function addIndent(stmt) {
-        return base + stmt;
+        return [base, stmt];
+    }
+
+    function withIndent(fn) {
+        var previousBase, result;
+        previousBase = base;
+        base += indent;
+        result = fn.call(this, base);
+        base = previousBase;
+        return result;
     }
 
-    function adjustMultilineComment(value) {
-        var array, i, len, line, j, ch, spaces;
+    function calculateSpaces(str) {
+        var i;
+        for (i = str.length - 1; i >= 0; i -= 1) {
+            if (isLineTerminator(str.charAt(i))) {
+                break;
+            }
+        }
+        return (str.length - 1) - i;
+    }
+
+    function adjustMultilineComment(value, specialBase) {
+        var array, i, len, line, j, ch, spaces, previousBase;
 
-        spaces = Number.MAX_VALUE;
         array = value.split(/\r\n|[\r\n]/);
+        spaces = Number.MAX_VALUE;
 
         // first line doesn't have indentation
         for (i = 1, len = array.length; i < len; i += 1) {
@@ -318,95 +622,212 @@
             }
         }
 
-        if (spaces % 2 === 1) {
-            // /*
-            //  *
-            //  */
-            // If spaces are odd number, above pattern is considered.
-            // We waste 1 space.
-            spaces -= 1;
+        if (typeof specialBase !== 'undefined') {
+            // pattern like
+            // {
+            //   var t = 20;  /*
+            //                 * this is comment
+            //                 */
+            // }
+            previousBase = base;
+            if (array[1][spaces] === '*') {
+                specialBase += ' ';
+            }
+            base = specialBase;
+        } else {
+            if (spaces & 1) {
+                // /*
+                //  *
+                //  */
+                // If spaces are odd number, above pattern is considered.
+                // We waste 1 space.
+                spaces -= 1;
+            }
+            previousBase = base;
         }
+
         for (i = 1, len = array.length; i < len; i += 1) {
-            array[i] = addIndent(array[i].slice(spaces));
+            array[i] = toSourceNode(addIndent(array[i].slice(spaces))).join('');
         }
+
+        base = previousBase;
+
         return array.join('\n');
     }
 
-    function generateComment(comment) {
+    function generateComment(comment, specialBase) {
         if (comment.type === 'Line') {
-            // Esprima always produce last line comment with LineTerminator
-            return '//' + comment.value;
+            if (endsWithLineTerminator(comment.value)) {
+                return '//' + comment.value;
+            } else {
+                // Always use LineTerminator
+                return '//' + comment.value + '\n';
+            }
         }
         if (extra.format.indent.adjustMultilineComment && /[\n\r]/.test(comment.value)) {
-            return adjustMultilineComment('/*' + comment.value + '*/');
+            return adjustMultilineComment('/*' + comment.value + '*/', specialBase);
         }
         return '/*' + comment.value + '*/';
     }
 
+    function addCommentsToStatement(stmt, result) {
+        var i, len, comment, save, node, tailingToStatement, specialBase, fragment;
+
+        if (stmt.leadingComments && stmt.leadingComments.length > 0) {
+            save = result;
+
+            comment = stmt.leadingComments[0];
+            result = [];
+            if (safeConcatenation && stmt.type === Syntax.Program && stmt.body.length === 0) {
+                result.push('\n');
+            }
+            result.push(generateComment(comment));
+            if (!endsWithLineTerminator(toSourceNode(result).toString())) {
+                result.push('\n');
+            }
+
+            for (i = 1, len = stmt.leadingComments.length; i < len; i += 1) {
+                comment = stmt.leadingComments[i];
+                fragment = [generateComment(comment)];
+                if (!endsWithLineTerminator(toSourceNode(fragment).toString())) {
+                    fragment.push('\n');
+                }
+                result.push(addIndent(fragment));
+            }
+
+            result.push(addIndent(save));
+        }
+
+        if (stmt.trailingComments) {
+            tailingToStatement = !endsWithLineTerminator(toSourceNode(result).toString());
+            specialBase = stringRepeat(' ', calculateSpaces(toSourceNode([base, result, indent]).toString()));
+            for (i = 0, len = stmt.trailingComments.length; i < len; i += 1) {
+                comment = stmt.trailingComments[i];
+                if (tailingToStatement) {
+                    // We assume target like following script
+                    //
+                    // var t = 20;  /**
+                    //               * This is comment of t
+                    //               */
+                    if (i === 0) {
+                        // first case
+                        result = [result, indent];
+                    } else {
+                        result = [result, specialBase];
+                    }
+                    result.push(generateComment(comment, specialBase));
+                } else {
+                    result = [result, addIndent(generateComment(comment))];
+                }
+                if (i !== len - 1 && !endsWithLineTerminator(toSourceNode(result).toString())) {
+                    result = [result, '\n'];
+                }
+            }
+        }
+
+        return result;
+    }
+
     function parenthesize(text, current, should) {
         if (current < should) {
-            return '(' + text + ')';
+            return ['(', text, ')'];
         }
         return text;
     }
 
-    function maybeBlock(stmt, suffix) {
-        var previousBase, result;
+    function maybeBlock(stmt, semicolonOptional, functionBody) {
+        var result, noLeadingComment;
 
-        if (stmt.type === Syntax.BlockStatement && (!extra.comment || !stmt.leadingComments)) {
-            result = ' ' + generateStatement(stmt);
-            if (suffix) {
-                return result + ' ';
-            }
-            return result;
-        }
+        noLeadingComment = !extra.comment || !stmt.leadingComments;
 
-        if (stmt.type === Syntax.EmptyStatement && (!extra.comment || !stmt.leadingComments)) {
-            result = ';';
-        } else {
-            previousBase = base;
-            base += indent;
-            result = '\n' + addIndent(generateStatement(stmt));
-            base = previousBase;
+        if (stmt.type === Syntax.BlockStatement && noLeadingComment) {
+            return [space, generateStatement(stmt, { functionBody: functionBody })];
         }
 
-        if (suffix) {
-            return result + '\n' + addIndent('');
+        if (stmt.type === Syntax.EmptyStatement && noLeadingComment) {
+            return ';';
         }
+
+        withIndent(function () {
+            result = [newline, addIndent(generateStatement(stmt, { semicolonOptional: semicolonOptional, functionBody: functionBody }))];
+        });
+
         return result;
     }
 
+    function maybeBlockSuffix(stmt, result) {
+        var ends = endsWithLineTerminator(toSourceNode(result).toString());
+        if (stmt.type === Syntax.BlockStatement && (!extra.comment || !stmt.leadingComments) && !ends) {
+            return [result, space];
+        }
+        if (ends) {
+            return [result, base];
+        }
+        return [result, newline, base];
+    }
+
+    function generateVerbatim(expr, option) {
+        var i, result;
+        result = expr[extra.verbatim].split(/\r\n|\n/);
+        for (i = 1; i < result.length; i++) {
+            result[i] = newline + base + result[i];
+        }
+
+        result = parenthesize(result, Precedence.Sequence, option.precedence);
+        return toSourceNode(result, expr);
+    }
+
     function generateFunctionBody(node) {
-        var result, i, len;
-        result = '(';
+        var result, i, len, expr;
+        result = ['('];
         for (i = 0, len = node.params.length; i < len; i += 1) {
-            result += node.params[i].name;
-            if ((i + 1) < len) {
-                result += ', ';
+            result.push(node.params[i].name);
+            if (i + 1 < len) {
+                result.push(',' + space);
             }
         }
-        return result + ')' + maybeBlock(node.body);
+        result.push(')');
+
+        if (node.expression) {
+            result.push(space);
+            expr = generateExpression(node.body, {
+                precedence: Precedence.Assignment,
+                allowIn: true,
+                allowCall: true
+            });
+            if (expr.toString().charAt(0) === '{') {
+                expr = ['(', expr, ')'];
+            }
+            result.push(expr);
+        } else {
+            result.push(maybeBlock(node.body, false, true));
+        }
+        return result;
     }
 
     function generateExpression(expr, option) {
-        var result, precedence, currentPrecedence, previousBase, i, len, raw, allowIn, allowCall;
+        var result, precedence, currentPrecedence, i, len, raw, fragment, multiline, leftChar, leftSource, rightChar, rightSource, allowIn, allowCall, allowUnparenthesizedNew, property, key, value;
 
         precedence = option.precedence;
         allowIn = option.allowIn;
         allowCall = option.allowCall;
 
+        if (extra.verbatim && expr.hasOwnProperty(extra.verbatim)) {
+            return generateVerbatim(expr, option);
+        }
+
         switch (expr.type) {
         case Syntax.SequenceExpression:
-            result = '';
+            result = [];
             allowIn |= (Precedence.Sequence < precedence);
             for (i = 0, len = expr.expressions.length; i < len; i += 1) {
-                result += generateExpression(expr.expressions[i], {
+                result.push(generateExpression(expr.expressions[i], {
                     precedence: Precedence.Assignment,
                     allowIn: allowIn,
                     allowCall: true
-                });
-                if ((i + 1) < len) {
-                    result += ', ';
+                }));
+                if (i + 1 < len) {
+                    result.push(',' + space);
                 }
             }
             result = parenthesize(result, Precedence.Sequence, precedence);
@@ -415,16 +836,19 @@
         case Syntax.AssignmentExpression:
             allowIn |= (Precedence.Assignment < precedence);
             result = parenthesize(
-                generateExpression(expr.left, {
-                    precedence: Precedence.Call,
-                    allowIn: allowIn,
-                    allowCall: true
-                }) + ' ' + expr.operator + ' ' +
+                [
+                    generateExpression(expr.left, {
+                        precedence: Precedence.Call,
+                        allowIn: allowIn,
+                        allowCall: true
+                    }),
+                    space + expr.operator + space,
                     generateExpression(expr.right, {
                         precedence: Precedence.Assignment,
                         allowIn: allowIn,
                         allowCall: true
-                    }),
+                    })
+                ],
                 Precedence.Assignment,
                 precedence
             );
@@ -433,21 +857,25 @@
         case Syntax.ConditionalExpression:
             allowIn |= (Precedence.Conditional < precedence);
             result = parenthesize(
-                generateExpression(expr.test, {
-                    precedence: Precedence.LogicalOR,
-                    allowIn: allowIn,
-                    allowCall: true
-                }) + ' ? ' +
+                [
+                    generateExpression(expr.test, {
+                        precedence: Precedence.LogicalOR,
+                        allowIn: allowIn,
+                        allowCall: true
+                    }),
+                    space + '?' + space,
                     generateExpression(expr.consequent, {
                         precedence: Precedence.Assignment,
                         allowIn: allowIn,
                         allowCall: true
-                    }) + ' : ' +
+                    }),
+                    space + ':' + space,
                     generateExpression(expr.alternate, {
                         precedence: Precedence.Assignment,
                         allowIn: allowIn,
                         allowCall: true
-                    }),
+                    })
+                ],
                 Precedence.Conditional,
                 precedence
             );
@@ -459,20 +887,30 @@
 
             allowIn |= (currentPrecedence < precedence);
 
-            result =
+            result = join(
                 generateExpression(expr.left, {
                     precedence: currentPrecedence,
                     allowIn: allowIn,
                     allowCall: true
-                }) + ' ' + expr.operator + ' ' +
-                generateExpression(expr.right, {
-                    precedence: currentPrecedence + 1,
-                    allowIn: allowIn,
-                    allowCall: true
-                });
+                }),
+                expr.operator
+            );
+
+            fragment = generateExpression(expr.right, {
+                precedence: currentPrecedence + 1,
+                allowIn: allowIn,
+                allowCall: true
+            });
+
+            if (expr.operator === '/' && fragment.toString().charAt(0) === '/') {
+                // If '/' concats with '/', it is interpreted as comment start
+                result.push(' ', fragment);
+            } else {
+                result = join(result, fragment);
+            }
 
             if (expr.operator === 'in' && !allowIn) {
-                result = '(' + result + ')';
+                result = ['(', result, ')'];
             } else {
                 result = parenthesize(result, currentPrecedence, precedence);
             }
@@ -480,121 +918,167 @@
             break;
 
         case Syntax.CallExpression:
-            result = generateExpression(expr.callee, {
+            result = [generateExpression(expr.callee, {
                 precedence: Precedence.Call,
                 allowIn: true,
-                allowCall: true
-            });
+                allowCall: true,
+                allowUnparenthesizedNew: false
+            })];
 
-            result += '(';
+            result.push('(');
             for (i = 0, len = expr['arguments'].length; i < len; i += 1) {
-                result += generateExpression(expr['arguments'][i], {
+                result.push(generateExpression(expr['arguments'][i], {
                     precedence: Precedence.Assignment,
                     allowIn: true,
                     allowCall: true
-                });
-                if ((i + 1) < len) {
-                    result += ', ';
+                }));
+                if (i + 1 < len) {
+                    result.push(',' + space);
                 }
             }
-            result += ')';
+            result.push(')');
 
             if (!allowCall) {
-                result = '(' + result + ')';
+                result = ['(', result, ')'];
             } else {
                 result = parenthesize(result, Precedence.Call, precedence);
             }
             break;
 
         case Syntax.NewExpression:
-            result = 'new ' + generateExpression(expr.callee, {
-                precedence: Precedence.New,
-                allowIn: true,
-                allowCall: false
-            });
+            len = expr['arguments'].length;
+            allowUnparenthesizedNew = option.allowUnparenthesizedNew === undefined || option.allowUnparenthesizedNew;
 
-            result += '(';
-            for (i = 0, len = expr['arguments'].length; i < len; i += 1) {
-                result += generateExpression(expr['arguments'][i], {
-                    precedence: Precedence.Assignment,
+            result = join(
+                'new',
+                generateExpression(expr.callee, {
+                    precedence: Precedence.New,
                     allowIn: true,
-                    allowCall: true
-                });
-                if ((i + 1) < len) {
-                    result += ', ';
+                    allowCall: false,
+                    allowUnparenthesizedNew: allowUnparenthesizedNew && !parentheses && len === 0
+                })
+            );
+
+            if (!allowUnparenthesizedNew || parentheses || len > 0) {
+                result.push('(');
+                for (i = 0; i < len; i += 1) {
+                    result.push(generateExpression(expr['arguments'][i], {
+                        precedence: Precedence.Assignment,
+                        allowIn: true,
+                        allowCall: true
+                    }));
+                    if (i + 1 < len) {
+                        result.push(',' + space);
+                    }
                 }
+                result.push(')');
             }
-            result += ')';
 
             result = parenthesize(result, Precedence.New, precedence);
             break;
 
         case Syntax.MemberExpression:
-            result = generateExpression(expr.object, {
+            result = [generateExpression(expr.object, {
                 precedence: Precedence.Call,
                 allowIn: true,
-                allowCall: allowCall
-            });
+                allowCall: allowCall,
+                allowUnparenthesizedNew: false
+            })];
 
             if (expr.computed) {
-                result += '[' + generateExpression(expr.property, {
+                result.push('[', generateExpression(expr.property, {
                     precedence: Precedence.Sequence,
                     allowIn: true,
                     allowCall: allowCall
-                }) + ']';
+                }), ']');
             } else {
                 if (expr.object.type === Syntax.Literal && typeof expr.object.value === 'number') {
                     if (result.indexOf('.') < 0) {
                         if (!/[eExX]/.test(result) && !(result.length >= 2 && result[0] === '0')) {
-                            result += '.';
+                            result.push('.');
                         }
                     }
                 }
-                result += '.' + expr.property.name;
+                result.push('.' + expr.property.name);
             }
 
             result = parenthesize(result, Precedence.Member, precedence);
             break;
 
         case Syntax.UnaryExpression:
-            result = expr.operator;
-            if (result.length > 2) {
-                result += ' ';
+            fragment = generateExpression(expr.argument, {
+                precedence: Precedence.Unary,
+                allowIn: true,
+                allowCall: true
+            });
+
+            if (space === '') {
+                result = join(expr.operator, fragment);
+            } else {
+                result = [expr.operator];
+                if (expr.operator.length > 2) {
+                    // delete, void, typeof
+                    // get `typeof []`, not `typeof[]`
+                    result = join(result, fragment);
+                } else {
+                    // Prevent inserting spaces between operator and argument if it is unnecessary
+                    // like, `!cond`
+                    leftSource = toSourceNode(result).toString();
+                    leftChar = leftSource.charAt(leftSource.length - 1);
+                    rightChar = fragment.toString().charAt(0);
+
+                    if (((leftChar === '+' || leftChar === '-') && leftChar === rightChar) || (isIdentifierPart(leftChar) && isIdentifierPart(rightChar))) {
+                        result.push(' ', fragment);
+                    } else {
+                        result.push(fragment);
+                    }
+                }
+            }
+            result = parenthesize(result, Precedence.Unary, precedence);
+            break;
+
+        case Syntax.YieldExpression:
+            if (expr.delegate) {
+                result = 'yield*';
+            } else {
+                result = 'yield';
+            }
+            if (expr.argument) {
+                result = join(
+                    result,
+                    generateExpression(expr.argument, {
+                        precedence: Precedence.Assignment,
+                        allowIn: true,
+                        allowCall: true
+                    })
+                );
             }
-            result = parenthesize(
-                result + generateExpression(expr.argument, {
-                    precedence: Precedence.Unary + (
-                        expr.argument.type === Syntax.UnaryExpression &&
-                            expr.operator.length < 3 &&
-                            expr.argument.operator === expr.operator ? 1 : 0
-                    ),
-                    allowIn: true,
-                    allowCall: true
-                }),
-                Precedence.Unary,
-                precedence
-            );
             break;
 
         case Syntax.UpdateExpression:
             if (expr.prefix) {
                 result = parenthesize(
-                    expr.operator +
+                    [
+                        expr.operator,
                         generateExpression(expr.argument, {
                             precedence: Precedence.Unary,
                             allowIn: true,
                             allowCall: true
-                        }),
+                        })
+                    ],
                     Precedence.Unary,
                     precedence
                 );
             } else {
                 result = parenthesize(
-                    generateExpression(expr.argument, {
-                        precedence: Precedence.Postfix,
-                        allowIn: true,
-                        allowCall: true
-                    }) + expr.operator,
+                    [
+                        generateExpression(expr.argument, {
+                            precedence: Precedence.Postfix,
+                            allowIn: true,
+                            allowCall: true
+                        }),
+                        expr.operator
+                    ],
                     Precedence.Postfix,
                     precedence
                 );
@@ -602,60 +1086,94 @@
             break;
 
         case Syntax.FunctionExpression:
-            result = 'function ';
+            result = 'function';
             if (expr.id) {
-                result += expr.id.name;
+                result += ' ' + expr.id.name;
+            } else {
+                result += space;
             }
-            result += generateFunctionBody(expr);
+
+            result = [result, generateFunctionBody(expr)];
             break;
 
+        case Syntax.ArrayPattern:
         case Syntax.ArrayExpression:
             if (!expr.elements.length) {
                 result = '[]';
                 break;
             }
-            result = '[\n';
-            previousBase = base;
-            base += indent;
-            for (i = 0, len = expr.elements.length; i < len; i += 1) {
-                if (!expr.elements[i]) {
-                    result += addIndent('');
-                    if ((i + 1) === len) {
-                        result += ',';
+            multiline = expr.elements.length > 1;
+            result = ['[', multiline ? newline : ''];
+            withIndent(function (indent) {
+                for (i = 0, len = expr.elements.length; i < len; i += 1) {
+                    if (!expr.elements[i]) {
+                        if (multiline) {
+                            result.push(indent);
+                        }
+                        if (i + 1 === len) {
+                            result.push(',');
+                        }
+                    } else {
+                        result.push(multiline ? indent : '', generateExpression(expr.elements[i], {
+                            precedence: Precedence.Assignment,
+                            allowIn: true,
+                            allowCall: true
+                        }));
+                    }
+                    if (i + 1 < len) {
+                        result.push(',' + (multiline ? newline : space));
                     }
-                } else {
-                    result += addIndent(generateExpression(expr.elements[i], {
-                        precedence: Precedence.Assignment,
-                        allowIn: true,
-                        allowCall: true
-                    }));
-                }
-                if ((i + 1) < len) {
-                    result += ',\n';
                 }
+            });
+            if (multiline && !endsWithLineTerminator(toSourceNode(result).toString())) {
+                result.push(newline);
             }
-            base = previousBase;
-            result += '\n' + addIndent(']');
+            result.push(multiline ? base : '', ']');
             break;
 
         case Syntax.Property:
             if (expr.kind === 'get' || expr.kind === 'set') {
-                result = expr.kind + ' ' + generateExpression(expr.key, {
-                    precedence: Precedence.Sequence,
-                    allowIn: true,
-                    allowCall: true
-                }) + generateFunctionBody(expr.value);
-            } else {
-                result =
+                result = [
+                    expr.kind + ' ',
                     generateExpression(expr.key, {
                         precedence: Precedence.Sequence,
                         allowIn: true,
                         allowCall: true
-                    }) + ': ' + generateExpression(expr.value, {
-                        precedence: Precedence.Assignment,
+                    }),
+                    generateFunctionBody(expr.value)
+                ];
+            } else {
+                if (expr.shorthand) {
+                    result = generateExpression(expr.key, {
+                        precedence: Precedence.Sequence,
                         allowIn: true,
                         allowCall: true
                     });
+                } else if (expr.method) {
+                    result = [];
+                    if (expr.value.generator) {
+                        result.push('*');
+                    }
+                    result.push(generateExpression(expr.key, {
+                        precedence: Precedence.Sequence,
+                        allowIn: true,
+                        allowCall: true
+                    }), generateFunctionBody(expr.value));
+                } else {
+                    result = [
+                        generateExpression(expr.key, {
+                            precedence: Precedence.Sequence,
+                            allowIn: true,
+                            allowCall: true
+                        }),
+                        ':' + space,
+                        generateExpression(expr.value, {
+                            precedence: Precedence.Assignment,
+                            allowIn: true,
+                            allowCall: true
+                        })
+                    ];
+                }
             }
             break;
 
@@ -664,21 +1182,95 @@
                 result = '{}';
                 break;
             }
-            result = '{\n';
-            previousBase = base;
-            base += indent;
-            for (i = 0, len = expr.properties.length; i < len; i += 1) {
-                result += addIndent(generateExpression(expr.properties[i], {
+            multiline = expr.properties.length > 1;
+
+            withIndent(function (indent) {
+                fragment = generateExpression(expr.properties[0], {
                     precedence: Precedence.Sequence,
                     allowIn: true,
                     allowCall: true
-                }));
-                if ((i + 1) < len) {
-                    result += ',\n';
+                });
+            });
+
+            if (!multiline) {
+                // issues 4
+                // Do not transform from
+                //   dejavu.Class.declare({
+                //       method2: function () {}
+                //   });
+                // to
+                //   dejavu.Class.declare({method2: function () {
+                //       }});
+                if (!hasLineTerminator(toSourceNode(fragment).toString())) {
+                    result = [ '{', space, fragment, space, '}' ];
+                    break;
+                }
+            }
+
+            withIndent(function (indent) {
+                result = [ '{', newline, indent, fragment ];
+
+                if (multiline) {
+                    result.push(',' + newline);
+                    for (i = 1, len = expr.properties.length; i < len; i += 1) {
+                        result.push(indent, generateExpression(expr.properties[i], {
+                            precedence: Precedence.Sequence,
+                            allowIn: true,
+                            allowCall: true
+                        }));
+                        if (i + 1 < len) {
+                            result.push(',' + newline);
+                        }
+                    }
+                }
+            });
+
+            if (!endsWithLineTerminator(toSourceNode(result).toString())) {
+                result.push(newline);
+            }
+            result.push(base, '}');
+            break;
+
+        case Syntax.ObjectPattern:
+            if (!expr.properties.length) {
+                result = '{}';
+                break;
+            }
+
+            multiline = false;
+            if (expr.properties.length === 1) {
+                property = expr.properties[0];
+                if (property.value.type !== Syntax.Identifier) {
+                    multiline = true;
+                }
+            } else {
+                for (i = 0, len = expr.properties.length; i < len; i += 1) {
+                    property = expr.properties[i];
+                    if (!property.shorthand) {
+                        multiline = true;
+                        break;
+                    }
+                }
+            }
+            result = ['{', multiline ? newline : '' ];
+
+            withIndent(function (indent) {
+                for (i = 0, len = expr.properties.length; i < len; i += 1) {
+                    result.push(multiline ? indent : '', generateExpression(expr.properties[i], {
+                        precedence: Precedence.Sequence,
+                        allowIn: true,
+                        allowCall: true
+                    }));
+                    if (i + 1 < len) {
+                        result.push(',' + (multiline ? newline : space));
+                    }
                 }
+            });
+
+            if (multiline && !endsWithLineTerminator(toSourceNode(result).toString())) {
+                result.push(newline);
             }
-            base = previousBase;
-            result += '\n' + addIndent('}');
+            result.push(multiline ? base : '', '}');
             break;
 
         case Syntax.ThisExpression:
@@ -709,90 +1301,185 @@
                 break;
             }
 
-            if (typeof expr.value === 'string') {
-                result = escapeString(expr.value);
-                break;
+            if (typeof expr.value === 'string') {
+                result = escapeString(expr.value);
+                break;
+            }
+
+            if (typeof expr.value === 'number') {
+                result = generateNumber(expr.value);
+                break;
+            }
+
+            result = expr.value.toString();
+            break;
+
+        case Syntax.ComprehensionExpression:
+            result = [
+                '[',
+                generateExpression(expr.body, {
+                    precedence: Precedence.Assignment,
+                    allowIn: true,
+                    allowCall: true
+                })
+            ];
+
+            if (expr.blocks) {
+                for (i = 0, len = expr.blocks.length; i < len; i += 1) {
+                    fragment = generateExpression(expr.blocks[i], {
+                        precedence: Precedence.Sequence,
+                        allowIn: true,
+                        allowCall: true
+                    });
+                    result = join(result, fragment);
+                }
+            }
+
+            if (expr.filter) {
+                result = join(result, 'if' + space);
+                fragment = generateExpression(expr.filter, {
+                    precedence: Precedence.Sequence,
+                    allowIn: true,
+                    allowCall: true
+                });
+                if (extra.moz.parenthesizedComprehensionBlock) {
+                    result = join(result, [ '(', fragment, ')' ]);
+                } else {
+                    result = join(result, fragment);
+                }
+            }
+            result.push(']');
+            break;
+
+        case Syntax.ComprehensionBlock:
+            if (expr.left.type === Syntax.VariableDeclaration) {
+                fragment = [
+                    expr.left.kind + ' ',
+                    generateStatement(expr.left.declarations[0], {
+                        allowIn: false
+                    })
+                ];
+            } else {
+                fragment = generateExpression(expr.left, {
+                    precedence: Precedence.Call,
+                    allowIn: true,
+                    allowCall: true
+                });
             }
 
-            if (typeof expr.value === 'number' && expr.value === Infinity) {
-                // Infinity is variable
-                result = '1e+1000';
-                break;
-            }
+            fragment = join(fragment, expr.of ? 'of' : 'in');
+            fragment = join(fragment, generateExpression(expr.right, {
+                precedence: Precedence.Sequence,
+                allowIn: true,
+                allowCall: true
+            }));
 
-            result = expr.value.toString();
+            if (extra.moz.parenthesizedComprehensionBlock) {
+                result = [ 'for' + space + '(', fragment, ')' ];
+            } else {
+                result = join('for' + space, fragment);
+            }
             break;
 
         default:
-            break;
-        }
-
-        if (result === undefined) {
             throw new Error('Unknown expression type: ' + expr.type);
         }
-        return result;
+
+        return toSourceNode(result, expr);
     }
 
     function generateStatement(stmt, option) {
-        var i, len, result, previousBase, comment, save, ret, node, allowIn;
+        var i, len, result, node, allowIn, functionBody, directiveContext, fragment, semicolon;
 
         allowIn = true;
+        semicolon = ';';
+        functionBody = false;
+        directiveContext = false;
         if (option) {
-            allowIn = option.allowIn;
+            allowIn = option.allowIn === undefined || option.allowIn;
+            if (!semicolons && option.semicolonOptional === true) {
+                semicolon = '';
+            }
+            functionBody = option.functionBody;
+            directiveContext = option.directiveContext;
         }
 
         switch (stmt.type) {
         case Syntax.BlockStatement:
-            result = '{\n';
+            result = ['{', newline];
 
-            previousBase = base;
-            base += indent;
-            for (i = 0, len = stmt.body.length; i < len; i += 1) {
-                result += addIndent(generateStatement(stmt.body[i])) + '\n';
-            }
-            base = previousBase;
+            withIndent(function () {
+                for (i = 0, len = stmt.body.length; i < len; i += 1) {
+                    fragment = addIndent(generateStatement(stmt.body[i], {
+                        semicolonOptional: i === len - 1,
+                        directiveContext: functionBody
+                    }));
+                    result.push(fragment);
+                    if (!endsWithLineTerminator(toSourceNode(fragment).toString())) {
+                        result.push(newline);
+                    }
+                }
+            });
 
-            result += addIndent('}');
+            result.push(addIndent('}'));
             break;
 
         case Syntax.BreakStatement:
             if (stmt.label) {
-                result = 'break ' + stmt.label.name + ';';
+                result = 'break ' + stmt.label.name + semicolon;
             } else {
-                result = 'break;';
+                result = 'break' + semicolon;
             }
             break;
 
         case Syntax.ContinueStatement:
             if (stmt.label) {
-                result = 'continue ' + stmt.label.name + ';';
+                result = 'continue ' + stmt.label.name + semicolon;
+            } else {
+                result = 'continue' + semicolon;
+            }
+            break;
+
+        case Syntax.DirectiveStatement:
+            if (stmt.raw) {
+                result = stmt.raw + semicolon;
             } else {
-                result = 'continue;';
+                result = escapeDirective(stmt.directive) + semicolon;
             }
             break;
 
         case Syntax.DoWhileStatement:
-            result = 'do' + maybeBlock(stmt.body, true) + 'while (' + generateExpression(stmt.test, {
-                precedence: Precedence.Sequence,
-                allowIn: true,
-                allowCall: true
-            }) + ');';
+            // Because `do 42 while (cond)` is Syntax Error. We need semicolon.
+            result = join('do', maybeBlock(stmt.body));
+            result = maybeBlockSuffix(stmt.body, result);
+            result = join(result, [
+                'while' + space + '(',
+                generateExpression(stmt.test, {
+                    precedence: Precedence.Sequence,
+                    allowIn: true,
+                    allowCall: true
+                }),
+                ')' + semicolon
+            ]);
             break;
 
         case Syntax.CatchClause:
-            previousBase = base;
-            base += indent;
-            result = ' catch (' + generateExpression(stmt.param, {
-                precedence: Precedence.Sequence,
-                allowIn: true,
-                allowCall: true
-            }) + ')';
-            base = previousBase;
-            result += maybeBlock(stmt.body);
+            withIndent(function () {
+                result = [
+                    'catch' + space + '(',
+                    generateExpression(stmt.param, {
+                        precedence: Precedence.Sequence,
+                        allowIn: true,
+                        allowCall: true
+                    }),
+                    ')'
+                ];
+            });
+            result.push(maybeBlock(stmt.body));
             break;
 
         case Syntax.DebuggerStatement:
-            result = 'debugger;';
+            result = 'debugger' + semicolon;
             break;
 
         case Syntax.EmptyStatement:
@@ -800,358 +1487,356 @@
             break;
 
         case Syntax.ExpressionStatement:
-            result = generateExpression(stmt.expression, {
+            result = [generateExpression(stmt.expression, {
                 precedence: Precedence.Sequence,
                 allowIn: true,
                 allowCall: true
-            });
+            })];
             // 12.4 '{', 'function' is not allowed in this position.
-            // wrap espression with parentheses
-            if (result[0] === '{' || result.indexOf('function ') === 0) {
-                result = '(' + result + ');';
+            // wrap expression with parentheses
+            if (result.toString().charAt(0) === '{' || (result.toString().slice(0, 8) === 'function' && " (".indexOf(result.toString().charAt(8)) >= 0) || (directive && directiveContext && stmt.expression.type === Syntax.Literal && typeof stmt.expression.value === 'string')) {
+                result = ['(', result, ')' + semicolon];
             } else {
-                result += ';';
+                result.push(semicolon);
             }
             break;
 
         case Syntax.VariableDeclarator:
             if (stmt.init) {
-                result = stmt.id.name + ' = ' + generateExpression(stmt.init, {
-                    precedence: Precedence.Assignment,
-                    allowIn: allowIn,
-                    allowCall: true
-                });
+                result = [
+                    generateExpression(stmt.id, {
+                        precedence: Precedence.Assignment,
+                        allowIn: allowIn,
+                        allowCall: true
+                    }) + space + '=' + space,
+                    generateExpression(stmt.init, {
+                        precedence: Precedence.Assignment,
+                        allowIn: allowIn,
+                        allowCall: true
+                    })
+                ];
             } else {
                 result = stmt.id.name;
             }
             break;
 
         case Syntax.VariableDeclaration:
-            result = stmt.kind;
+            result = [stmt.kind];
             // special path for
             // var x = function () {
             // };
             if (stmt.declarations.length === 1 && stmt.declarations[0].init &&
                     stmt.declarations[0].init.type === Syntax.FunctionExpression) {
-                result += ' ' + generateStatement(stmt.declarations[0], {
+                result.push(' ', generateStatement(stmt.declarations[0], {
                     allowIn: allowIn
-                });
+                }));
             } else {
                 // VariableDeclarator is typed as Statement,
                 // but joined with comma (not LineTerminator).
                 // So if comment is attached to target node, we should specialize.
-                previousBase = base;
-                base += indent;
-
-                node = stmt.declarations[0];
-                if (extra.comment && node.leadingComments) {
-                    result += '\n' + addIndent(generateStatement(node, {
-                        allowIn: allowIn
-                    }));
-                } else {
-                    result += ' ' + generateStatement(node, {
-                        allowIn: allowIn
-                    });
-                }
-
-                for (i = 1, len = stmt.declarations.length; i < len; i += 1) {
-                    node = stmt.declarations[i];
+                withIndent(function () {
+                    node = stmt.declarations[0];
                     if (extra.comment && node.leadingComments) {
-                        result += ',\n' + addIndent(generateStatement(node, {
+                        result.push('\n', addIndent(generateStatement(node, {
                             allowIn: allowIn
-                        }));
+                        })));
                     } else {
-                        result += ', ' + generateStatement(node, {
+                        result.push(' ', generateStatement(node, {
                             allowIn: allowIn
-                        });
+                        }));
                     }
-                }
-                base = previousBase;
+
+                    for (i = 1, len = stmt.declarations.length; i < len; i += 1) {
+                        node = stmt.declarations[i];
+                        if (extra.comment && node.leadingComments) {
+                            result.push(',' + newline, addIndent(generateStatement(node, {
+                                allowIn: allowIn
+                            })));
+                        } else {
+                            result.push(',' + space, generateStatement(node, {
+                                allowIn: allowIn
+                            }));
+                        }
+                    }
+                });
             }
-            result += ';';
+            result.push(semicolon);
             break;
 
         case Syntax.ThrowStatement:
-            result = 'throw ' + generateExpression(stmt.argument, {
-                precedence: Precedence.Sequence,
-                allowIn: true,
-                allowCall: true
-            }) + ';';
+            result = [join(
+                'throw',
+                generateExpression(stmt.argument, {
+                    precedence: Precedence.Sequence,
+                    allowIn: true,
+                    allowCall: true
+                })
+            ), semicolon];
             break;
 
         case Syntax.TryStatement:
-            result = 'try' + maybeBlock(stmt.block);
+            result = ['try', maybeBlock(stmt.block)];
+            result = maybeBlockSuffix(stmt.block, result);
             for (i = 0, len = stmt.handlers.length; i < len; i += 1) {
-                result += generateStatement(stmt.handlers[i]);
+                result = join(result, generateStatement(stmt.handlers[i]));
+                if (stmt.finalizer || i + 1 !== len) {
+                    result = maybeBlockSuffix(stmt.handlers[i].body, result);
+                }
             }
             if (stmt.finalizer) {
-                result += ' finally' + maybeBlock(stmt.finalizer);
+                result = join(result, ['finally', maybeBlock(stmt.finalizer)]);
             }
             break;
 
         case Syntax.SwitchStatement:
-            previousBase = base;
-            base += indent;
-            result = 'switch (' + generateExpression(stmt.discriminant, {
-                precedence: Precedence.Sequence,
-                allowIn: true,
-                allowCall: true
-            }) + ') {\n';
-            base = previousBase;
+            withIndent(function () {
+                result = [
+                    'switch' + space + '(',
+                    generateExpression(stmt.discriminant, {
+                        precedence: Precedence.Sequence,
+                        allowIn: true,
+                        allowCall: true
+                    }),
+                    ')' + space + '{' + newline
+                ];
+            });
             if (stmt.cases) {
                 for (i = 0, len = stmt.cases.length; i < len; i += 1) {
-                    result += addIndent(generateStatement(stmt.cases[i])) + '\n';
+                    fragment = addIndent(generateStatement(stmt.cases[i], {semicolonOptional: i === len - 1}));
+                    result.push(fragment);
+                    if (!endsWithLineTerminator(toSourceNode(fragment).toString())) {
+                        result.push(newline);
+                    }
                 }
             }
-            result += addIndent('}');
+            result.push(addIndent('}'));
             break;
 
         case Syntax.SwitchCase:
-            previousBase = base;
-            base += indent;
-            if (stmt.test) {
-                result = 'case ' + generateExpression(stmt.test, {
-                    precedence: Precedence.Sequence,
-                    allowIn: true,
-                    allowCall: true
-                }) + ':';
-            } else {
-                result = 'default:';
-            }
+            withIndent(function () {
+                if (stmt.test) {
+                    result = [
+                        join('case', generateExpression(stmt.test, {
+                            precedence: Precedence.Sequence,
+                            allowIn: true,
+                            allowCall: true
+                        })),
+                        ':'
+                    ];
+                } else {
+                    result = ['default:'];
+                }
 
-            i = 0;
-            len = stmt.consequent.length;
-            if (len && stmt.consequent[0].type === Syntax.BlockStatement) {
-                result += maybeBlock(stmt.consequent[0]);
-                i = 1;
-            }
+                i = 0;
+                len = stmt.consequent.length;
+                if (len && stmt.consequent[0].type === Syntax.BlockStatement) {
+                    fragment = maybeBlock(stmt.consequent[0]);
+                    result.push(fragment);
+                    i = 1;
+                }
 
-            for (; i < len; i += 1) {
-                result += '\n' + addIndent(generateStatement(stmt.consequent[i]));
-            }
+                if (i !== len && !endsWithLineTerminator(toSourceNode(result).toString())) {
+                    result.push(newline);
+                }
 
-            base = previousBase;
+                for (; i < len; i += 1) {
+                    fragment = addIndent(generateStatement(stmt.consequent[i], {semicolonOptional: i === len - 1 && semicolon === ''}));
+                    result.push(fragment);
+                    if (i + 1 !== len && !endsWithLineTerminator(toSourceNode(fragment).toString())) {
+                        result.push(newline);
+                    }
+                }
+            });
             break;
 
         case Syntax.IfStatement:
-            if (stmt.alternate) {
-                if (stmt.alternate.type === Syntax.IfStatement) {
-                    previousBase = base;
-                    base += indent;
-                    result = 'if (' +  generateExpression(stmt.test, {
+            withIndent(function () {
+                result = [
+                    'if' + space + '(',
+                    generateExpression(stmt.test, {
                         precedence: Precedence.Sequence,
                         allowIn: true,
                         allowCall: true
-                    }) + ')';
-                    base = previousBase;
-                    result += maybeBlock(stmt.consequent, true) + 'else ' + generateStatement(stmt.alternate);
+                    }),
+                    ')'
+                ];
+            });
+            if (stmt.alternate) {
+                result.push(maybeBlock(stmt.consequent));
+                result = maybeBlockSuffix(stmt.consequent, result);
+                if (stmt.alternate.type === Syntax.IfStatement) {
+                    result = join(result, ['else ', generateStatement(stmt.alternate, {semicolonOptional: semicolon === ''})]);
                 } else {
-                    previousBase = base;
-                    base += indent;
-                    result = 'if (' + generateExpression(stmt.test, {
-                        precedence: Precedence.Sequence,
-                        allowIn: true,
-                        allowCall: true
-                    }) + ')';
-                    base = previousBase;
-                    result += maybeBlock(stmt.consequent, true) + 'else' + maybeBlock(stmt.alternate);
+                    result = join(result, join('else', maybeBlock(stmt.alternate, semicolon === '')));
                 }
             } else {
-                previousBase = base;
-                base += indent;
-                result = 'if (' + generateExpression(stmt.test, {
-                    precedence: Precedence.Sequence,
-                    allowIn: true,
-                    allowCall: true
-                }) + ')';
-                base = previousBase;
-                result += maybeBlock(stmt.consequent);
+                result.push(maybeBlock(stmt.consequent, semicolon === ''));
             }
             break;
 
         case Syntax.ForStatement:
-            previousBase = base;
-            base += indent;
-            result = 'for (';
-            if (stmt.init) {
-                if (stmt.init.type === Syntax.VariableDeclaration) {
-                    result += generateStatement(stmt.init, {
-                        allowIn: false
-                    });
+            withIndent(function () {
+                result = ['for' + space + '('];
+                if (stmt.init) {
+                    if (stmt.init.type === Syntax.VariableDeclaration) {
+                        result.push(generateStatement(stmt.init, {allowIn: false}));
+                    } else {
+                        result.push(generateExpression(stmt.init, {
+                            precedence: Precedence.Sequence,
+                            allowIn: false,
+                            allowCall: true
+                        }), ';');
+                    }
                 } else {
-                    result += generateExpression(stmt.init, {
+                    result.push(';');
+                }
+
+                if (stmt.test) {
+                    result.push(space, generateExpression(stmt.test, {
                         precedence: Precedence.Sequence,
-                        allowIn: false,
+                        allowIn: true,
                         allowCall: true
-                    }) + ';';
+                    }), ';');
+                } else {
+                    result.push(';');
                 }
-            } else {
-                result += ';';
-            }
 
-            if (stmt.test) {
-                result += ' ' + generateExpression(stmt.test, {
-                    precedence: Precedence.Sequence,
-                    allowIn: true,
-                    allowCall: true
-                }) + ';';
-            } else {
-                result += ';';
-            }
-
-            if (stmt.update) {
-                result += ' ' + generateExpression(stmt.update, {
-                    precedence: Precedence.Sequence,
-                    allowIn: true,
-                    allowCall: true
-                }) + ')';
-            } else {
-                result += ')';
-            }
-            base = previousBase;
+                if (stmt.update) {
+                    result.push(space, generateExpression(stmt.update, {
+                        precedence: Precedence.Sequence,
+                        allowIn: true,
+                        allowCall: true
+                    }), ')');
+                } else {
+                    result.push(')');
+                }
+            });
 
-            result += maybeBlock(stmt.body);
+            result.push(maybeBlock(stmt.body, semicolon === ''));
             break;
 
         case Syntax.ForInStatement:
-            result = 'for (';
-            if (stmt.left.type === Syntax.VariableDeclaration) {
-                previousBase = base;
-                base += indent + indent;
-                result += stmt.left.kind + ' ' + generateStatement(stmt.left.declarations[0], {
-                    allowIn: false
-                });
-                base = previousBase;
-            } else {
-                previousBase = base;
-                base += indent;
-                result += generateExpression(stmt.left, {
-                    precedence: Precedence.Call,
-                    allowIn: true,
-                    allowCall: true
-                });
-                base = previousBase;
-            }
+            result = ['for' + space + '('];
+            withIndent(function () {
+                if (stmt.left.type === Syntax.VariableDeclaration) {
+                    withIndent(function () {
+                        result.push(stmt.left.kind + ' ', generateStatement(stmt.left.declarations[0], {
+                            allowIn: false
+                        }));
+                    });
+                } else {
+                    result.push(generateExpression(stmt.left, {
+                        precedence: Precedence.Call,
+                        allowIn: true,
+                        allowCall: true
+                    }));
+                }
 
-            previousBase = base;
-            base += indent;
-            result += ' in ' + generateExpression(stmt.right, {
-                precedence: Precedence.Sequence,
-                allowIn: true,
-                allowCall: true
-            }) + ')';
-            base = previousBase;
-            result += maybeBlock(stmt.body);
+                result = join(result, 'in');
+                result = [join(
+                    result,
+                    generateExpression(stmt.right, {
+                        precedence: Precedence.Sequence,
+                        allowIn: true,
+                        allowCall: true
+                    })
+                ), ')'];
+            });
+            result.push(maybeBlock(stmt.body, semicolon === ''));
             break;
 
         case Syntax.LabeledStatement:
-            result = stmt.label.name + ':' + maybeBlock(stmt.body);
+            result = [stmt.label.name + ':', maybeBlock(stmt.body, semicolon === '')];
             break;
 
         case Syntax.Program:
-            result = '';
-            for (i = 0, len = stmt.body.length; i < len; i += 1) {
-                result += addIndent(generateStatement(stmt.body[i]));
-                if ((i + 1) < len) {
-                    result += '\n';
+            len = stmt.body.length;
+            result = [safeConcatenation && len > 0 ? '\n' : ''];
+            for (i = 0; i < len; i += 1) {
+                fragment = addIndent(
+                    generateStatement(stmt.body[i], {
+                        semicolonOptional: !safeConcatenation && i === len - 1,
+                        directiveContext: true
+                    })
+                );
+                result.push(fragment);
+                if (i + 1 < len && !endsWithLineTerminator(toSourceNode(fragment).toString())) {
+                    result.push(newline);
                 }
             }
             break;
 
         case Syntax.FunctionDeclaration:
-            result = 'function ';
-            if (stmt.id) {
-                result += stmt.id.name;
-            }
-            result += generateFunctionBody(stmt);
+            result = [(stmt.generator && !extra.moz.starlessGenerator ? 'function* ' : 'function ') + stmt.id.name, generateFunctionBody(stmt)];
             break;
 
         case Syntax.ReturnStatement:
             if (stmt.argument) {
-                result = 'return ' + generateExpression(stmt.argument, {
-                    precedence: Precedence.Sequence,
-                    allowIn: true,
-                    allowCall: true
-                }) + ';';
+                result = [join(
+                    'return',
+                    generateExpression(stmt.argument, {
+                        precedence: Precedence.Sequence,
+                        allowIn: true,
+                        allowCall: true
+                    })
+                ), semicolon];
             } else {
-                result = 'return;';
+                result = ['return' + semicolon];
             }
             break;
 
         case Syntax.WhileStatement:
-            previousBase = base;
-            base += indent;
-            result = 'while (' + generateExpression(stmt.test, {
-                precedence: Precedence.Sequence,
-                allowIn: true,
-                allowCall: true
-            }) + ')';
-            base = previousBase;
-            result += maybeBlock(stmt.body);
+            withIndent(function () {
+                result = [
+                    'while' + space + '(',
+                    generateExpression(stmt.test, {
+                        precedence: Precedence.Sequence,
+                        allowIn: true,
+                        allowCall: true
+                    }),
+                    ')'
+                ];
+            });
+            result.push(maybeBlock(stmt.body, semicolon === ''));
             break;
 
         case Syntax.WithStatement:
-            previousBase = base;
-            base += indent;
-            result = 'with (' + generateExpression(stmt.object, {
-                precedence: Precedence.Sequence,
-                allowIn: true,
-                allowCall: true
-            }) + ')';
-            base = previousBase;
-            result += maybeBlock(stmt.body);
+            withIndent(function () {
+                result = [
+                    'with' + space + '(',
+                    generateExpression(stmt.object, {
+                        precedence: Precedence.Sequence,
+                        allowIn: true,
+                        allowCall: true
+                    }),
+                    ')'
+                ];
+            });
+            result.push(maybeBlock(stmt.body, semicolon === ''));
             break;
 
         default:
-            break;
-        }
-
-        if (result === undefined) {
             throw new Error('Unknown statement type: ' + stmt.type);
         }
 
         // Attach comments
 
         if (extra.comment) {
-            if (stmt.leadingComments) {
-                save = result;
-
-                comment = stmt.leadingComments[0];
-                result = generateComment(comment);
-                if (!endsWithLineTerminator(result)) {
-                    result += '\n';
-                }
-
-                for (i = 1, len = stmt.leadingComments.length; i < len; i += 1) {
-                    comment = stmt.leadingComments[i];
-                    ret = generateComment(comment);
-                    if (!endsWithLineTerminator(ret)) {
-                        ret += '\n';
-                    }
-                    result += addIndent(ret);
-                }
-
-                result += addIndent(save);
-            }
+            result = addCommentsToStatement(stmt, result);
+        }
 
-            if (stmt.trailingComments) {
-                for (i = 0, len = stmt.trailingComments.length; i < len; i += 1) {
-                    comment = stmt.trailingComments[i];
-                    if (!endsWithLineTerminator(result)) {
-                        result += '\n';
-                    }
-                    result += addIndent(generateComment(comment));
-                }
-            }
+        fragment = toSourceNode(result).toString();
+        if (stmt.type === Syntax.Program && !safeConcatenation && newline === '' &&  fragment.charAt(fragment.length - 1) === '\n') {
+            result = toSourceNode(result).replaceRight(/\s+$/, '');
         }
 
-        return result;
+        return toSourceNode(result, stmt);
     }
 
     function generate(node, options) {
-        var defaultOptions = getDefaultOptions();
+        var defaultOptions = getDefaultOptions(), result, pair;
 
-        if (typeof options !== 'undefined') {
+        if (options != null) {
             // Obsolete options
             //
             //   `options.indent`
@@ -1161,7 +1846,9 @@
             if (typeof options.indent === 'string') {
                 defaultOptions.format.indent.style = options.indent;
             }
-
+            if (typeof options.base === 'number') {
+                defaultOptions.format.indent.base = options.base;
+            }
             options = updateDeeply(defaultOptions, options);
             indent = options.format.indent.style;
             if (typeof options.base === 'string') {
@@ -1169,20 +1856,47 @@
             } else {
                 base = stringRepeat(indent, options.format.indent.base);
             }
-            parse = options.parse;
         } else {
             options = defaultOptions;
             indent = options.format.indent.style;
             base = stringRepeat(indent, options.format.indent.base);
-            parse = options.parse;
         }
+        json = options.format.json;
+        renumber = options.format.renumber;
+        hexadecimal = json ? false : options.format.hexadecimal;
+        quotes = json ? 'double' : options.format.quotes;
+        escapeless = options.format.escapeless;
+        if (options.format.compact) {
+            newline = space = indent = base = '';
+        } else {
+            newline = '\n';
+            space = ' ';
+        }
+        parentheses = options.format.parentheses;
+        semicolons = options.format.semicolons;
+        safeConcatenation = options.format.safeConcatenation;
+        directive = options.directive;
+        parse = json ? null : options.parse;
+        sourceMap = options.sourceMap;
         extra = options;
 
+        if (sourceMap) {
+            if (typeof process !== 'undefined') {
+                // We assume environment is node.js
+                SourceNode = require('source-map').SourceNode;
+            } else {
+                SourceNode = global.sourceMap.SourceNode;
+            }
+        } else {
+            SourceNode = SourceNodeMock;
+        }
+
         switch (node.type) {
         case Syntax.BlockStatement:
         case Syntax.BreakStatement:
         case Syntax.CatchClause:
         case Syntax.ContinueStatement:
+        case Syntax.DirectiveStatement:
         case Syntax.DoWhileStatement:
         case Syntax.DebuggerStatement:
         case Syntax.EmptyStatement:
@@ -1202,10 +1916,12 @@
         case Syntax.VariableDeclarator:
         case Syntax.WhileStatement:
         case Syntax.WithStatement:
-            return generateStatement(node);
+            result = generateStatement(node);
+            break;
 
         case Syntax.AssignmentExpression:
         case Syntax.ArrayExpression:
+        case Syntax.ArrayPattern:
         case Syntax.BinaryExpression:
         case Syntax.CallExpression:
         case Syntax.ConditionalExpression:
@@ -1216,21 +1932,35 @@
         case Syntax.MemberExpression:
         case Syntax.NewExpression:
         case Syntax.ObjectExpression:
+        case Syntax.ObjectPattern:
         case Syntax.Property:
         case Syntax.SequenceExpression:
         case Syntax.ThisExpression:
         case Syntax.UnaryExpression:
         case Syntax.UpdateExpression:
-            return generateExpression(node, {
+        case Syntax.YieldExpression:
+
+            result = generateExpression(node, {
                 precedence: Precedence.Sequence,
                 allowIn: true,
                 allowCall: true
             });
+            break;
 
         default:
-            break;
+            throw new Error('Unknown node type: ' + node.type);
+        }
+
+        if (!sourceMap) {
+            return result.toString();
+        }
+
+        pair = result.toStringWithSourceMap({file: options.sourceMap});
+
+        if (options.sourceMapWithCode) {
+            return pair;
         }
-        throw new Error('Unknown node type: ' + node.type);
+        return pair.map.toString();
     }
 
     // simple visitor implementation
@@ -1238,6 +1968,7 @@
     VisitorKeys = {
         AssignmentExpression: ['left', 'right'],
         ArrayExpression: ['elements'],
+        ArrayPattern: ['elements'],
         BlockStatement: ['body'],
         BinaryExpression: ['left', 'right'],
         BreakStatement: ['label'],
@@ -1245,6 +1976,7 @@
         CatchClause: ['param', 'body'],
         ConditionalExpression: ['test', 'consequent', 'alternate'],
         ContinueStatement: ['label'],
+        DirectiveStatement: [],
         DoWhileStatement: ['body', 'test'],
         DebuggerStatement: [],
         EmptyStatement: [],
@@ -1261,11 +1993,12 @@
         MemberExpression: ['object', 'property'],
         NewExpression: ['callee', 'arguments'],
         ObjectExpression: ['properties'],
+        ObjectPattern: ['properties'],
         Program: ['body'],
         Property: ['key', 'value'],
         ReturnStatement: ['argument'],
         SequenceExpression: ['expressions'],
-        SwitchStatement: ['descriminant', 'cases'],
+        SwitchStatement: ['discriminant', 'cases'],
         SwitchCase: ['test', 'consequent'],
         ThisExpression: [],
         ThrowStatement: ['argument'],
@@ -1275,7 +2008,8 @@
         VariableDeclaration: ['declarations'],
         VariableDeclarator: ['id', 'init'],
         WhileStatement: ['test', 'body'],
-        WithStatement: ['object', 'body']
+        WithStatement: ['object', 'body'],
+        YieldExpression: ['argument']
     };
 
     VisitorOption = {
@@ -1284,17 +2018,27 @@
     };
 
     function traverse(top, visitor) {
-        var worklist, leavelist, node, ret, current, current2, candidates, candidate;
+        var worklist, leavelist, node, ret, current, current2, candidates, candidate, marker = {};
 
         worklist = [ top ];
-        leavelist = [];
+        leavelist = [ null ];
 
         while (worklist.length) {
             node = worklist.pop();
 
-            if (node) {
+            if (node === marker) {
+                node = leavelist.pop();
+                if (visitor.leave) {
+                    ret = visitor.leave(node, leavelist[leavelist.length - 1]);
+                } else {
+                    ret = undefined;
+                }
+                if (ret === VisitorOption.Break) {
+                    return;
+                }
+            } else if (node) {
                 if (visitor.enter) {
-                    ret = visitor.enter(node);
+                    ret = visitor.enter(node, leavelist[leavelist.length - 1]);
                 } else {
                     ret = undefined;
                 }
@@ -1303,7 +2047,7 @@
                     return;
                 }
 
-                worklist.push(null);
+                worklist.push(marker);
                 leavelist.push(node);
 
                 if (ret !== VisitorOption.Skip) {
@@ -1325,21 +2069,10 @@
                         }
                     }
                 }
-            } else {
-                node = leavelist.pop();
-                if (visitor.leave) {
-                    ret = visitor.leave(node);
-                } else {
-                    ret = undefined;
-                }
-                if (ret === VisitorOption.Break) {
-                    return;
-                }
             }
         }
     }
 
-
     // based on LLVM libc++ upper_bound / lower_bound
     // MIT License
 
@@ -1408,45 +2141,30 @@
 
     function attachComments(tree, providedComments, tokens) {
         // At first, we should calculate extended comment ranges.
-        var comments = [], len, i;
+        var comments = [], comment, len, i;
 
         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));
         }
 
-        //
-        // For example,
-        //
-        //      var i1 = 10,  // test
-        //          i2 = 20;
-        //
-        //  Above comment is probably trailing to i1 = 10.
-        //  So we specialize comma token.
-        //
-        //  And second, comma first style example,
-        //
-        //  var i = [
-        //        10  // testing
-        //      , 20  // testing 2
-        //  ];
-        //
-        //  'testing' comment is trailing to 10 is proper.
-        //
-        //  So we add some specialize path.
-        //
-        //      1. check comment is'nt containing LineTerminator
-        //      2. check LineTerminator is not found between previous token and comment
-        //      3. check LineTerminator is found between comment and next token
-        //
-        //  If above conditions are all true,
-        //  we assume this comment should be attached to previous token as trailing comment.
-        //
-
-        // This traverse attacher is based on John Freeman's implementation.
+        // This is based on John Freeman's implementation.
         traverse(tree, {
             cursor: 0,
             enter: function (node) {
@@ -1517,11 +2235,11 @@
     }
 
     // Sync with package.json.
-    exports.version = '0.0.4';
+    exports.version = '0.0.16-dev';
 
     exports.generate = generate;
     exports.traverse = traverse;
     exports.attachComments = attachComments;
 
-}(typeof exports === 'undefined' ? (escodegen = {}) : exports));
+}, this));
 /* vim: set sw=4 ts=4 et tw=80 : */


[couchdb-escodegen] 03/11: Insert redirect meta tag to /index.html

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch gh-pages
in repository https://gitbox.apache.org/repos/asf/couchdb-escodegen.git

commit e3b815df232ca4db719cdb0c26d1bdc8e3c74014
Author: Constellation <ut...@gmail.com>
AuthorDate: Fri Mar 16 10:34:45 2012 +0900

    Insert redirect meta tag to /index.html
---
 index.html | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/index.html b/index.html
index e69de29..944d8fd 100644
--- a/index.html
+++ b/index.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML>
+<html lang="en">
+<head>
+	<meta charset="UTF-8">
+  <meta http-equiv="refresh" content="0; URL=http://constellation.github.com/escodegen/demo/index.html">
+</head>
+<body>
+</body>
+</html>


[couchdb-escodegen] 08/11: www.esprima.org should be esprima.org

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch gh-pages
in repository https://gitbox.apache.org/repos/asf/couchdb-escodegen.git

commit 8544537ae3371e80fba0a737d4a2a6fc3e1fc7ec
Author: 题叶 <ji...@gmail.com>
AuthorDate: Sun Oct 27 10:04:35 2013 +0800

    www.esprima.org should be esprima.org
    
    ```
    ➤➤ curl www.esprima.org
    curl: (6) Could not resolve host: www.esprima.org
    ```
    And visiting http://www.esprima.org/ get nothing
---
 demo/index.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/demo/index.html b/demo/index.html
index 134c497..781b9f4 100644
--- a/demo/index.html
+++ b/demo/index.html
@@ -63,7 +63,7 @@ document.addEventListener('DOMContentLoaded', function(ev) {
 </head>
 <body>
 <h1>JS code generator demo: JS → AST → JS</h1>
-<p>using <a href="http://www.esprima.org/">esprima</a> as parser</p>
+<p>using <a href="http://esprima.org/">esprima</a> as parser</p>
 <p>and using <a href="https://github.com/Constellation/escodegen">escodegen</a> as code generator</p>
 <textarea id="console" rows="10" cols="30" placeholder="write your code"></textarea>
 <pre id="output"></pre>


[couchdb-escodegen] 11/11: Merge pull request #227 from toothbrush7777777/patch-1

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch gh-pages
in repository https://gitbox.apache.org/repos/asf/couchdb-escodegen.git

commit 6acfbc215fe12ab1ebbf456bfb661dcad21e0fe1
Merge: 578cfbd 141741c
Author: Michael Ficarra <gi...@michael.ficarra.me>
AuthorDate: Fri Apr 3 08:56:12 2015 -0700

    Merge pull request #227 from toothbrush7777777/patch-1
    
    Updated old URL and standardised the indenting

 index.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)


[couchdb-escodegen] 02/11: Add index.html on the top

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch gh-pages
in repository https://gitbox.apache.org/repos/asf/couchdb-escodegen.git

commit 78548f55945b80d7af11b3540e2ba0ee823772dd
Author: Constellation <ut...@gmail.com>
AuthorDate: Fri Mar 16 04:35:53 2012 +0900

    Add index.html on the top
---
 index.html | 0
 1 file changed, 0 insertions(+), 0 deletions(-)

diff --git a/index.html b/index.html
new file mode 100644
index 0000000..e69de29


[couchdb-escodegen] 10/11: Updated old URL and standardised the indenting

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch gh-pages
in repository https://gitbox.apache.org/repos/asf/couchdb-escodegen.git

commit 141741c4925570f4c46b670db01850492b04b893
Author: Toothbrush <to...@gmail.com>
AuthorDate: Fri Apr 3 14:55:23 2015 +0100

    Updated old URL and standardised the indenting
---
 index.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/index.html b/index.html
index 944d8fd..610c0e4 100644
--- a/index.html
+++ b/index.html
@@ -2,7 +2,7 @@
 <html lang="en">
 <head>
 	<meta charset="UTF-8">
-  <meta http-equiv="refresh" content="0; URL=http://constellation.github.com/escodegen/demo/index.html">
+	<meta http-equiv="refresh" content="0; URL=http://estools.github.com/escodegen/demo/index.html">
 </head>
 <body>
 </body>


[couchdb-escodegen] 01/11: First commit to gh-pages

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch gh-pages
in repository https://gitbox.apache.org/repos/asf/couchdb-escodegen.git

commit 480a003098c6fc7658ddf4c04fad569e1a9a1613
Author: Constellation <ut...@gmail.com>
AuthorDate: Fri Mar 16 04:29:02 2012 +0900

    First commit to gh-pages
---
 assets/esprima.js | 3744 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 assets/style.css  |   52 +
 demo/index.html   |   71 +
 escodegen.js      |  843 ++++++++++++
 4 files changed, 4710 insertions(+)

diff --git a/assets/esprima.js b/assets/esprima.js
new file mode 100644
index 0000000..8a11eba
--- /dev/null
+++ b/assets/esprima.js
@@ -0,0 +1,3744 @@
+/*
+  Copyright (C) 2012 Ariya Hidayat <ar...@gmail.com>
+  Copyright (C) 2012 Mathias Bynens <ma...@qiwi.be>
+  Copyright (C) 2012 Joost-Wim Boekesteijn <jo...@boekesteijn.nl>
+  Copyright (C) 2012 Kris Kowal <kr...@cixar.com>
+  Copyright (C) 2012 Yusuke Suzuki <ut...@gmail.com>
+  Copyright (C) 2012 Arpad Borsos <ar...@googlemail.com>
+  Copyright (C) 2011 Ariya Hidayat <ar...@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 bitwise:true */
+/*global esprima:true, exports:true,
+throwError: true, createLiteral: true, generateStatement: true,
+parseAssignmentExpression: true, parseBlock: true, parseExpression: true,
+parseFunctionDeclaration: true, parseFunctionExpression: true,
+parseFunctionSourceElements: true, parseVariableIdentifier: true,
+parseLeftHandSideExpression: true,
+parseStatement: true, parseSourceElement: true */
+
+(function (exports) {
+    'use strict';
+
+    var Token,
+        TokenName,
+        Syntax,
+        PropertyKind,
+        Messages,
+        Regex,
+        source,
+        allowIn,
+        lastParenthesized,
+        strict,
+        index,
+        lineNumber,
+        lineStart,
+        length,
+        buffer,
+        extra,
+        labelSet,
+        inIteration,
+        inSwitch,
+        inFunctionBody;
+
+    Token = {
+        BooleanLiteral: 1,
+        EOF: 2,
+        Identifier: 3,
+        Keyword: 4,
+        NullLiteral: 5,
+        NumericLiteral: 6,
+        Punctuator: 7,
+        StringLiteral: 8
+    };
+
+    TokenName = {};
+    TokenName[Token.BooleanLiteral] = 'Boolean';
+    TokenName[Token.EOF] = '<end>';
+    TokenName[Token.Identifier] = 'Identifier';
+    TokenName[Token.Keyword] = 'Keyword';
+    TokenName[Token.NullLiteral] = 'Null';
+    TokenName[Token.NumericLiteral] = 'Numeric';
+    TokenName[Token.Punctuator] = 'Punctuator';
+    TokenName[Token.StringLiteral] = 'String';
+
+    Syntax = {
+        AssignmentExpression: 'AssignmentExpression',
+        ArrayExpression: 'ArrayExpression',
+        BlockStatement: 'BlockStatement',
+        BinaryExpression: 'BinaryExpression',
+        BreakStatement: 'BreakStatement',
+        CallExpression: 'CallExpression',
+        CatchClause: 'CatchClause',
+        ConditionalExpression: 'ConditionalExpression',
+        ContinueStatement: 'ContinueStatement',
+        DoWhileStatement: 'DoWhileStatement',
+        DebuggerStatement: 'DebuggerStatement',
+        EmptyStatement: 'EmptyStatement',
+        ExpressionStatement: 'ExpressionStatement',
+        ForStatement: 'ForStatement',
+        ForInStatement: 'ForInStatement',
+        FunctionDeclaration: 'FunctionDeclaration',
+        FunctionExpression: 'FunctionExpression',
+        Identifier: 'Identifier',
+        IfStatement: 'IfStatement',
+        Literal: 'Literal',
+        LabeledStatement: 'LabeledStatement',
+        LogicalExpression: 'LogicalExpression',
+        MemberExpression: 'MemberExpression',
+        NewExpression: 'NewExpression',
+        ObjectExpression: 'ObjectExpression',
+        Program: 'Program',
+        Property: 'Property',
+        ReturnStatement: 'ReturnStatement',
+        SequenceExpression: 'SequenceExpression',
+        SwitchStatement: 'SwitchStatement',
+        SwitchCase: 'SwitchCase',
+        ThisExpression: 'ThisExpression',
+        ThrowStatement: 'ThrowStatement',
+        TryStatement: 'TryStatement',
+        UnaryExpression: 'UnaryExpression',
+        UpdateExpression: 'UpdateExpression',
+        VariableDeclaration: 'VariableDeclaration',
+        VariableDeclarator: 'VariableDeclarator',
+        WhileStatement: 'WhileStatement',
+        WithStatement: 'WithStatement'
+    };
+
+    PropertyKind = {
+        Data: 1,
+        Get: 2,
+        Set: 4
+    };
+
+    // Error messages should be identical to V8.
+    Messages = {
+        UnexpectedToken:  'Unexpected token %0',
+        UnexpectedNumber:  'Unexpected number',
+        UnexpectedString:  'Unexpected string',
+        UnexpectedIdentifier:  'Unexpected identifier',
+        UnexpectedReserved:  'Unexpected reserved word',
+        UnexpectedEOS:  'Unexpected end of input',
+        NewlineAfterThrow:  'Illegal newline after throw',
+        InvalidRegExp: 'Invalid regular expression',
+        UnterminatedRegExp:  'Invalid regular expression: missing /',
+        InvalidLHSInAssignment:  'Invalid left-hand side in assignment',
+        InvalidLHSInForIn:  'Invalid left-hand side in for-in',
+        NoCatchOrFinally:  'Missing catch or finally after try',
+        UnknownLabel: 'Undefined label \'%0\'',
+        Redeclaration: '%0 \'%1\' has already been declared',
+        IllegalContinue: 'Illegal continue statement',
+        IllegalBreak: 'Illegal break statement',
+        IllegalReturn: 'Illegal return statement',
+        StrictModeWith:  'Strict mode code may not include a with statement',
+        StrictCatchVariable:  'Catch variable may not be eval or arguments in strict mode',
+        StrictVarName:  'Variable name may not be eval or arguments in strict mode',
+        StrictParamName:  'Parameter name eval or arguments is not allowed in strict mode',
+        StrictParamDupe: 'Strict mode function may not have duplicate parameter names',
+        StrictFunctionName:  'Function name may not be eval or arguments in strict mode',
+        StrictOctalLiteral:  'Octal literals are not allowed in strict mode.',
+        StrictDelete:  'Delete of an unqualified identifier in strict mode.',
+        StrictDuplicateProperty:  'Duplicate data property in object literal not allowed in strict mode',
+        AccessorDataProperty:  'Object literal may not have data and accessor property with the same name',
+        AccessorGetSet:  'Object literal may not have multiple get/set accessors with the same name',
+        StrictLHSAssignment:  'Assignment to eval or arguments is not allowed in strict mode',
+        StrictLHSPostfix:  'Postfix increment/decrement may not have eval or arguments operand in strict mode',
+        StrictLHSPrefix:  'Prefix increment/decrement may not have eval or arguments operand in strict mode',
+        StrictReservedWord:  'Use of future reserved word in strict mode'
+    };
+
+    // See also tools/generate-unicode-regex.py.
+    Regex = {
+        NonAsciiIdentifierStart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840- [...]
+        NonAsciiIdentifierPart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0300-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u0483-\u0487\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u05d0-\u05ea\u05f0-\u05f2\u0610-\u061a\u0620-\u0669\u066e-\u06d3\u06d5-\u06dc\u06df-\u06e8\u06ea-\u06fc\u06ff\u0710-\u074a\u074d-\u07b1\u07c0-\u07f5\u07fa\u08 [...]
+    };
+
+    if (typeof Object.freeze === 'function') {
+        Object.freeze(Token);
+        Object.freeze(TokenName);
+        Object.freeze(Syntax);
+        Object.freeze(PropertyKind);
+        Object.freeze(Messages);
+        Object.freeze(Regex);
+    }
+
+    // Ensure the condition is true, otherwise throw an error.
+    // This is only to have a better contract semantic, i.e. another safety net
+    // to catch a logic error. The condition shall be fulfilled in normal case.
+    // Do NOT use this to enforce a certain condition on any user input.
+
+    function assert(condition, message) {
+        if (!condition) {
+            throw new Error('ASSERT: ' + message);
+        }
+    }
+
+    function sliceSource(from, to) {
+        return source.slice(from, to);
+    }
+
+    if (typeof 'esprima'[0] === 'undefined') {
+        sliceSource = function sliceArraySource(from, to) {
+            return source.slice(from, to).join('');
+        };
+    }
+
+    function isDecimalDigit(ch) {
+        return '0123456789'.indexOf(ch) >= 0;
+    }
+
+    function isHexDigit(ch) {
+        return '0123456789abcdefABCDEF'.indexOf(ch) >= 0;
+    }
+
+    function isOctalDigit(ch) {
+        return '01234567'.indexOf(ch) >= 0;
+    }
+
+
+    // 7.2 White Space
+
+    function isWhiteSpace(ch) {
+        return (ch === ' ') || (ch === '\u0009') || (ch === '\u000B') ||
+            (ch === '\u000C') || (ch === '\u00A0') ||
+            (ch.charCodeAt(0) >= 0x1680 &&
+             '\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\uFEFF'.indexOf(ch) >= 0);
+    }
+
+    // 7.3 Line Terminators
+
+    function isLineTerminator(ch) {
+        return (ch === '\n' || ch === '\r' || ch === '\u2028' || ch === '\u2029');
+    }
+
+    // 7.6 Identifier Names and Identifiers
+
+    function isIdentifierStart(ch) {
+        return (ch === '$') || (ch === '_') || (ch === '\\') ||
+            (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
+            ((ch.charCodeAt(0) >= 0x80) && Regex.NonAsciiIdentifierStart.test(ch));
+    }
+
+    function isIdentifierPart(ch) {
+        return (ch === '$') || (ch === '_') || (ch === '\\') ||
+            (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
+            ((ch >= '0') && (ch <= '9')) ||
+            ((ch.charCodeAt(0) >= 0x80) && Regex.NonAsciiIdentifierPart.test(ch));
+    }
+
+    // 7.6.1.2 Future Reserved Words
+
+    function isFutureReservedWord(id) {
+        switch (id) {
+
+        // Future reserved words.
+        case 'class':
+        case 'enum':
+        case 'export':
+        case 'extends':
+        case 'import':
+        case 'super':
+            return true;
+        }
+
+        return false;
+    }
+
+    function isStrictModeReservedWord(id) {
+        switch (id) {
+
+        // Strict Mode reserved words.
+        case 'implements':
+        case 'interface':
+        case 'package':
+        case 'private':
+        case 'protected':
+        case 'public':
+        case 'static':
+        case 'yield':
+        case 'let':
+            return true;
+        }
+
+        return false;
+    }
+
+    function isRestrictedWord(id) {
+        return id === 'eval' || id === 'arguments';
+    }
+
+    // 7.6.1.1 Keywords
+
+    function isKeyword(id) {
+        var keyword = false;
+        switch (id.length) {
+        case 2:
+            keyword = (id === 'if') || (id === 'in') || (id === 'do');
+            break;
+        case 3:
+            keyword = (id === 'var') || (id === 'for') || (id === 'new') || (id === 'try');
+            break;
+        case 4:
+            keyword = (id === 'this') || (id === 'else') || (id === 'case') || (id === 'void') || (id === 'with');
+            break;
+        case 5:
+            keyword = (id === 'while') || (id === 'break') || (id === 'catch') || (id === 'throw');
+            break;
+        case 6:
+            keyword = (id === 'return') || (id === 'typeof') || (id === 'delete') || (id === 'switch');
+            break;
+        case 7:
+            keyword = (id === 'default') || (id === 'finally');
+            break;
+        case 8:
+            keyword = (id === 'function') || (id === 'continue') || (id === 'debugger');
+            break;
+        case 10:
+            keyword = (id === 'instanceof');
+            break;
+        }
+
+        if (keyword) {
+            return true;
+        }
+
+        switch (id) {
+        // Future reserved words.
+        // 'const' is specialized as Keyword in V8.
+        case 'const':
+            return true;
+
+        // For compatiblity to SpiderMonkey and ES.next
+        case 'yield':
+        case 'let':
+            return true;
+        }
+
+        if (strict && isStrictModeReservedWord(id)) {
+            return true;
+        }
+
+        return isFutureReservedWord(id);
+    }
+
+    // Return the next character and move forward.
+
+    function nextChar() {
+        var ch;
+        if (index < length) {
+            ch = source[index];
+            index += 1;
+        }
+        return ch;
+    }
+
+    // 7.4 Comments
+
+    function skipComment() {
+        var ch, blockComment, lineComment;
+
+        blockComment = false;
+        lineComment = false;
+
+        while (index < length) {
+            ch = source[index];
+
+            if (lineComment) {
+                ch = nextChar();
+                if (isLineTerminator(ch)) {
+                    lineComment = false;
+                    if (ch === '\r' && source[index] === '\n') {
+                        index += 1;
+                    }
+                    lineNumber += 1;
+                    lineStart = index;
+                }
+            } else if (blockComment) {
+                if (isLineTerminator(ch)) {
+                    if (ch === '\r' && source[index + 1] === '\n') {
+                        index += 1;
+                    }
+                    lineNumber += 1;
+                    index += 1;
+                    lineStart = index;
+                    if (index >= length) {
+                        throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+                    }
+                } else {
+                    ch = nextChar();
+                    if (index >= length) {
+                        throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+                    }
+                    if (ch === '*') {
+                        ch = source[index];
+                        if (ch === '/') {
+                            index += 1;
+                            blockComment = false;
+                        }
+                    }
+                }
+            } else if (ch === '/') {
+                ch = source[index + 1];
+                if (ch === '/') {
+                    index += 2;
+                    lineComment = true;
+                } else if (ch === '*') {
+                    index += 2;
+                    blockComment = true;
+                    if (index >= length) {
+                        throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+                    }
+                } else {
+                    break;
+                }
+            } else if (isWhiteSpace(ch)) {
+                index += 1;
+            } else if (isLineTerminator(ch)) {
+                index += 1;
+                if (ch ===  '\r' && source[index] === '\n') {
+                    index += 1;
+                }
+                lineNumber += 1;
+                lineStart = index;
+            } else {
+                break;
+            }
+        }
+    }
+
+    function scanHexEscape(prefix) {
+        var i, len, ch, code = 0;
+
+        len = (prefix === 'u') ? 4 : 2;
+        for (i = 0; i < len; i += 1) {
+            if (index < length && isHexDigit(source[index])) {
+                ch = nextChar();
+                code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase());
+            } else {
+                return '';
+            }
+        }
+        return String.fromCharCode(code);
+    }
+
+    function scanIdentifier() {
+        var ch, start, id, restore;
+
+        ch = source[index];
+        if (!isIdentifierStart(ch)) {
+            return;
+        }
+
+        start = index;
+        if (ch === '\\') {
+            index += 1;
+            if (source[index] !== 'u') {
+                return;
+            }
+            index += 1;
+            restore = index;
+            ch = scanHexEscape('u');
+            if (ch) {
+                if (ch === '\\' || !isIdentifierStart(ch)) {
+                    return;
+                }
+                id = ch;
+            } else {
+                index = restore;
+                id = 'u';
+            }
+        } else {
+            id = nextChar();
+        }
+
+        while (index < length) {
+            ch = source[index];
+            if (!isIdentifierPart(ch)) {
+                break;
+            }
+            if (ch === '\\') {
+                index += 1;
+                if (source[index] !== 'u') {
+                    return;
+                }
+                index += 1;
+                restore = index;
+                ch = scanHexEscape('u');
+                if (ch) {
+                    if (ch === '\\' || !isIdentifierPart(ch)) {
+                        return;
+                    }
+                    id += ch;
+                } else {
+                    index = restore;
+                    id += 'u';
+                }
+            } else {
+                id += nextChar();
+            }
+        }
+
+        // There is no keyword or literal with only one character.
+        // Thus, it must be an identifier.
+        if (id.length === 1) {
+            return {
+                type: Token.Identifier,
+                value: id,
+                lineNumber: lineNumber,
+                lineStart: lineStart,
+                range: [start, index]
+            };
+        }
+
+        if (isKeyword(id)) {
+            return {
+                type: Token.Keyword,
+                value: id,
+                lineNumber: lineNumber,
+                lineStart: lineStart,
+                range: [start, index]
+            };
+        }
+
+        // 7.8.1 Null Literals
+
+        if (id === 'null') {
+            return {
+                type: Token.NullLiteral,
+                value: id,
+                lineNumber: lineNumber,
+                lineStart: lineStart,
+                range: [start, index]
+            };
+        }
+
+        // 7.8.2 Boolean Literals
+
+        if (id === 'true' || id === 'false') {
+            return {
+                type: Token.BooleanLiteral,
+                value: id,
+                lineNumber: lineNumber,
+                lineStart: lineStart,
+                range: [start, index]
+            };
+        }
+
+        return {
+            type: Token.Identifier,
+            value: id,
+            lineNumber: lineNumber,
+            lineStart: lineStart,
+            range: [start, index]
+        };
+    }
+
+    // 7.7 Punctuators
+
+    function scanPunctuator() {
+        var start = index,
+            ch1 = source[index],
+            ch2,
+            ch3,
+            ch4;
+
+        // Check for most common single-character punctuators.
+
+        if (ch1 === ';' || ch1 === '{' || ch1 === '}') {
+            index += 1;
+            return {
+                type: Token.Punctuator,
+                value: ch1,
+                lineNumber: lineNumber,
+                lineStart: lineStart,
+                range: [start, index]
+            };
+        }
+
+        if (ch1 === ',' || ch1 === '(' || ch1 === ')') {
+            index += 1;
+            return {
+                type: Token.Punctuator,
+                value: ch1,
+                lineNumber: lineNumber,
+                lineStart: lineStart,
+                range: [start, index]
+            };
+        }
+
+        // Dot (.) can also start a floating-point number, hence the need
+        // to check the next character.
+
+        ch2 = source[index + 1];
+        if (ch1 === '.' && !isDecimalDigit(ch2)) {
+            return {
+                type: Token.Punctuator,
+                value: nextChar(),
+                lineNumber: lineNumber,
+                lineStart: lineStart,
+                range: [start, index]
+            };
+        }
+
+        // Peek more characters.
+
+        ch3 = source[index + 2];
+        ch4 = source[index + 3];
+
+        // 4-character punctuator: >>>=
+
+        if (ch1 === '>' && ch2 === '>' && ch3 === '>') {
+            if (ch4 === '=') {
+                index += 4;
+                return {
+                    type: Token.Punctuator,
+                    value: '>>>=',
+                    lineNumber: lineNumber,
+                    lineStart: lineStart,
+                    range: [start, index]
+                };
+            }
+        }
+
+        // 3-character punctuators: === !== >>> <<= >>=
+
+        if (ch1 === '=' && ch2 === '=' && ch3 === '=') {
+            index += 3;
+            return {
+                type: Token.Punctuator,
+                value: '===',
+                lineNumber: lineNumber,
+                lineStart: lineStart,
+                range: [start, index]
+            };
+        }
+
+        if (ch1 === '!' && ch2 === '=' && ch3 === '=') {
+            index += 3;
+            return {
+                type: Token.Punctuator,
+                value: '!==',
+                lineNumber: lineNumber,
+                lineStart: lineStart,
+                range: [start, index]
+            };
+        }
+
+        if (ch1 === '>' && ch2 === '>' && ch3 === '>') {
+            index += 3;
+            return {
+                type: Token.Punctuator,
+                value: '>>>',
+                lineNumber: lineNumber,
+                lineStart: lineStart,
+                range: [start, index]
+            };
+        }
+
+        if (ch1 === '<' && ch2 === '<' && ch3 === '=') {
+            index += 3;
+            return {
+                type: Token.Punctuator,
+                value: '<<=',
+                lineNumber: lineNumber,
+                lineStart: lineStart,
+                range: [start, index]
+            };
+        }
+
+        if (ch1 === '>' && ch2 === '>' && ch3 === '=') {
+            index += 3;
+            return {
+                type: Token.Punctuator,
+                value: '>>=',
+                lineNumber: lineNumber,
+                lineStart: lineStart,
+                range: [start, index]
+            };
+        }
+
+        // 2-character punctuators: <= >= == != ++ -- << >> && ||
+        // += -= *= %= &= |= ^= /=
+
+        if (ch2 === '=') {
+            if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) {
+                index += 2;
+                return {
+                    type: Token.Punctuator,
+                    value: ch1 + ch2,
+                    lineNumber: lineNumber,
+                    lineStart: lineStart,
+                    range: [start, index]
+                };
+            }
+        }
+
+        if (ch1 === ch2 && ('+-<>&|'.indexOf(ch1) >= 0)) {
+            if ('+-<>&|'.indexOf(ch2) >= 0) {
+                index += 2;
+                return {
+                    type: Token.Punctuator,
+                    value: ch1 + ch2,
+                    lineNumber: lineNumber,
+                    lineStart: lineStart,
+                    range: [start, index]
+                };
+            }
+        }
+
+        // The remaining 1-character punctuators.
+
+        if ('[]<>+-*%&|^!~?:=/'.indexOf(ch1) >= 0) {
+            return {
+                type: Token.Punctuator,
+                value: nextChar(),
+                lineNumber: lineNumber,
+                lineStart: lineStart,
+                range: [start, index]
+            };
+        }
+    }
+
+    // 7.8.3 Numeric Literals
+
+    function scanNumericLiteral() {
+        var number, start, ch;
+
+        ch = source[index];
+        assert(isDecimalDigit(ch) || (ch === '.'),
+            'Numeric literal must start with a decimal digit or a decimal point');
+
+        start = index;
+        number = '';
+        if (ch !== '.') {
+            number = nextChar();
+            ch = source[index];
+
+            // Hex number starts with '0x'.
+            // Octal number starts with '0'.
+            if (number === '0') {
+                if (ch === 'x' || ch === 'X') {
+                    number += nextChar();
+                    while (index < length) {
+                        ch = source[index];
+                        if (!isHexDigit(ch)) {
+                            break;
+                        }
+                        number += nextChar();
+                    }
+
+                    if (number.length <= 2) {
+                        // only 0x
+                        throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+                    }
+
+                    if (index < length) {
+                        ch = source[index];
+                        if (isIdentifierStart(ch)) {
+                            throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+                        }
+                    }
+                    return {
+                        type: Token.NumericLiteral,
+                        value: parseInt(number, 16),
+                        lineNumber: lineNumber,
+                        lineStart: lineStart,
+                        range: [start, index]
+                    };
+                } else if (isOctalDigit(ch)) {
+                    number += nextChar();
+                    while (index < length) {
+                        ch = source[index];
+                        if (!isOctalDigit(ch)) {
+                            break;
+                        }
+                        number += nextChar();
+                    }
+
+                    if (index < length) {
+                        ch = source[index];
+                        if (isIdentifierStart(ch) || isDecimalDigit(ch)) {
+                            throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+                        }
+                    }
+                    return {
+                        type: Token.NumericLiteral,
+                        value: parseInt(number, 8),
+                        octal: true,
+                        lineNumber: lineNumber,
+                        lineStart: lineStart,
+                        range: [start, index]
+                    };
+                }
+
+                // decimal number starts with '0' such as '09' is illegal.
+                if (isDecimalDigit(ch)) {
+                    throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+                }
+            }
+
+            while (index < length) {
+                ch = source[index];
+                if (!isDecimalDigit(ch)) {
+                    break;
+                }
+                number += nextChar();
+            }
+        }
+
+        if (ch === '.') {
+            number += nextChar();
+            while (index < length) {
+                ch = source[index];
+                if (!isDecimalDigit(ch)) {
+                    break;
+                }
+                number += nextChar();
+            }
+        }
+
+        if (ch === 'e' || ch === 'E') {
+            number += nextChar();
+
+            ch = source[index];
+            if (ch === '+' || ch === '-') {
+                number += nextChar();
+            }
+
+            ch = source[index];
+            if (isDecimalDigit(ch)) {
+                number += nextChar();
+                while (index < length) {
+                    ch = source[index];
+                    if (!isDecimalDigit(ch)) {
+                        break;
+                    }
+                    number += nextChar();
+                }
+            } else {
+                ch = 'character ' + ch;
+                if (index >= length) {
+                    ch = '<end>';
+                }
+                throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+            }
+        }
+
+        if (index < length) {
+            ch = source[index];
+            if (isIdentifierStart(ch)) {
+                throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+            }
+        }
+
+        return {
+            type: Token.NumericLiteral,
+            value: parseFloat(number),
+            lineNumber: lineNumber,
+            lineStart: lineStart,
+            range: [start, index]
+        };
+    }
+
+    // 7.8.4 String Literals
+
+    function scanStringLiteral() {
+        var str = '', quote, start, ch, code, unescaped, restore, octal = false;
+
+        quote = source[index];
+        assert((quote === '\'' || quote === '"'),
+            'String literal must starts with a quote');
+
+        start = index;
+        index += 1;
+
+        while (index < length) {
+            ch = nextChar();
+
+            if (ch === quote) {
+                quote = '';
+                break;
+            } else if (ch === '\\') {
+                ch = nextChar();
+                if (!isLineTerminator(ch)) {
+                    switch (ch) {
+                    case 'n':
+                        str += '\n';
+                        break;
+                    case 'r':
+                        str += '\r';
+                        break;
+                    case 't':
+                        str += '\t';
+                        break;
+                    case 'u':
+                    case 'x':
+                        restore = index;
+                        unescaped = scanHexEscape(ch);
+                        if (unescaped) {
+                            str += unescaped;
+                        } else {
+                            index = restore;
+                            str += ch;
+                        }
+                        break;
+                    case 'b':
+                        str += '\b';
+                        break;
+                    case 'f':
+                        str += '\f';
+                        break;
+                    case 'v':
+                        str += '\v';
+                        break;
+
+                    default:
+                        if (isOctalDigit(ch)) {
+                            code = '01234567'.indexOf(ch);
+
+                            // \0 is not octal escape sequence
+                            if (code !== 0) {
+                                octal = true;
+                            }
+
+                            if (index < length && isOctalDigit(source[index])) {
+                                octal = true;
+                                code = code * 8 + '01234567'.indexOf(nextChar());
+
+                                // 3 digits are only allowed when string starts
+                                // with 0, 1, 2, 3
+                                if ('0123'.indexOf(ch) >= 0 &&
+                                        index < length &&
+                                        isOctalDigit(source[index])) {
+                                    code = code * 8 + '01234567'.indexOf(nextChar());
+                                }
+                            }
+                            str += String.fromCharCode(code);
+                        } else {
+                            str += ch;
+                        }
+                        break;
+                    }
+                } else {
+                    lineNumber += 1;
+                    if (ch ===  '\r' && source[index] === '\n') {
+                        index += 1;
+                    }
+                }
+            } else if (isLineTerminator(ch)) {
+                break;
+            } else {
+                str += ch;
+            }
+        }
+
+        if (quote !== '') {
+            throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+        }
+
+        return {
+            type: Token.StringLiteral,
+            value: str,
+            octal: octal,
+            lineNumber: lineNumber,
+            lineStart: lineStart,
+            range: [start, index]
+        };
+    }
+
+    function scanRegExp() {
+        var str = '', ch, start, pattern, flags, value, classMarker = false, restore;
+
+        buffer = null;
+        skipComment();
+
+        start = index;
+        ch = source[index];
+        assert(ch === '/', 'Regular expression literal must start with a slash');
+        str = nextChar();
+
+        while (index < length) {
+            ch = nextChar();
+            str += ch;
+            if (classMarker) {
+                if (ch === ']') {
+                    classMarker = false;
+                }
+            } else {
+                if (ch === '\\') {
+                    str += nextChar();
+                }
+                if (ch === '/') {
+                    break;
+                }
+                if (ch === '[') {
+                    classMarker = true;
+                }
+                if (isLineTerminator(ch)) {
+                    throwError({}, Messages.UnterminatedRegExp);
+                }
+            }
+        }
+
+        if (str.length === 1) {
+            throwError({}, Messages.UnterminatedRegExp);
+        }
+
+        // Exclude leading and trailing slash.
+        pattern = str.substr(1, str.length - 2);
+
+        flags = '';
+        while (index < length) {
+            ch = source[index];
+            if (!isIdentifierPart(ch)) {
+                break;
+            }
+
+            index += 1;
+            if (ch === '\\' && index < length) {
+                ch = source[index];
+                if (ch === 'u') {
+                    index += 1;
+                    restore = index;
+                    ch = scanHexEscape('u');
+                    if (ch) {
+                        flags += ch;
+                        str += '\\u';
+                        for (; restore < index; restore += 1) {
+                            str += source[restore];
+                        }
+                    } else {
+                        index = restore;
+                        flags += 'u';
+                        str += '\\u';
+                    }
+                } else {
+                    str += '\\';
+                }
+            } else {
+                flags += ch;
+                str += ch;
+            }
+        }
+
+        try {
+            value = new RegExp(pattern, flags);
+        } catch (e) {
+            throwError({}, Messages.InvalidRegExp);
+        }
+
+        return {
+            literal: str,
+            value: value,
+            range: [start, index]
+        };
+    }
+
+    function isIdentifierName(token) {
+        return token.type === Token.Identifier ||
+            token.type === Token.Keyword ||
+            token.type === Token.BooleanLiteral ||
+            token.type === Token.NullLiteral;
+    }
+
+    function advance() {
+        var ch, token;
+
+        skipComment();
+
+        if (index >= length) {
+            return {
+                type: Token.EOF,
+                lineNumber: lineNumber,
+                lineStart: lineStart,
+                range: [index, index]
+            };
+        }
+
+        token = scanPunctuator();
+        if (typeof token !== 'undefined') {
+            return token;
+        }
+
+        ch = source[index];
+
+        if (ch === '\'' || ch === '"') {
+            return scanStringLiteral();
+        }
+
+        if (ch === '.' || isDecimalDigit(ch)) {
+            return scanNumericLiteral();
+        }
+
+        token = scanIdentifier();
+        if (typeof token !== 'undefined') {
+            return token;
+        }
+
+        throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+    }
+
+    function lex() {
+        var token;
+
+        if (buffer) {
+            index = buffer.range[1];
+            lineNumber = buffer.lineNumber;
+            lineStart = buffer.lineStart;
+            token = buffer;
+            buffer = null;
+            return token;
+        }
+
+        buffer = null;
+        return advance();
+    }
+
+    function lookahead() {
+        var pos, line, start;
+
+        if (buffer !== null) {
+            return buffer;
+        }
+
+        pos = index;
+        line = lineNumber;
+        start = lineStart;
+        buffer = advance();
+        index = pos;
+        lineNumber = line;
+        lineStart = start;
+
+        return buffer;
+    }
+
+    // Return true if there is a line terminator before the next token.
+
+    function peekLineTerminator() {
+        var pos, line, start, found;
+
+        pos = index;
+        line = lineNumber;
+        start = lineStart;
+        skipComment();
+        found = lineNumber !== line;
+        index = pos;
+        lineNumber = line;
+        lineStart = start;
+
+        return found;
+    }
+
+    // Throw an exception
+
+    function throwError(token, messageFormat) {
+        var error,
+            args = Array.prototype.slice.call(arguments, 2),
+            msg = messageFormat.replace(
+                /%(\d)/g,
+                function (whole, index) {
+                    return args[index] || '';
+                }
+            );
+
+        if (typeof token.lineNumber === 'number') {
+            error = new Error('Line ' + token.lineNumber + ': ' + msg);
+            error.index = token.range[0];
+            error.lineNumber = token.lineNumber;
+            error.column = token.range[0] - lineStart + 1;
+        } else {
+            error = new Error('Line ' + lineNumber + ': ' + msg);
+            error.index = index;
+            error.lineNumber = lineNumber;
+            error.column = index - lineStart + 1;
+        }
+
+        throw error;
+    }
+
+    // Throw an exception because of the token.
+
+    function throwUnexpected(token) {
+        var s;
+
+        if (token.type === Token.EOF) {
+            throwError(token, Messages.UnexpectedEOS);
+        }
+
+        if (token.type === Token.NumericLiteral) {
+            throwError(token, Messages.UnexpectedNumber);
+        }
+
+        if (token.type === Token.StringLiteral) {
+            throwError(token, Messages.UnexpectedString);
+        }
+
+        if (token.type === Token.Identifier) {
+            throwError(token, Messages.UnexpectedIdentifier);
+        }
+
+        if (token.type === Token.Keyword) {
+            if (isFutureReservedWord(token.value)) {
+                throwError(token, Messages.UnexpectedReserved);
+            } else if (strict && isStrictModeReservedWord(token.value)) {
+                throwError(token, Messages.StrictReservedWord);
+            }
+            throwError(token, Messages.UnexpectedToken, token.value);
+        }
+
+        // BooleanLiteral, NullLiteral, or Punctuator.
+        throwError(token, Messages.UnexpectedToken, token.value);
+    }
+
+    // Expect the next token to match the specified punctuator.
+    // If not, an exception will be thrown.
+
+    function expect(value) {
+        var token = lex();
+        if (token.type !== Token.Punctuator || token.value !== value) {
+            throwUnexpected(token);
+        }
+    }
+
+    // Expect the next token to match the specified keyword.
+    // If not, an exception will be thrown.
+
+    function expectKeyword(keyword) {
+        var token = lex();
+        if (token.type !== Token.Keyword || token.value !== keyword) {
+            throwUnexpected(token);
+        }
+    }
+
+    // Return true if the next token matches the specified punctuator.
+
+    function match(value) {
+        var token = lookahead();
+        return token.type === Token.Punctuator && token.value === value;
+    }
+
+    // Return true if the next token matches the specified keyword
+
+    function matchKeyword(keyword) {
+        var token = lookahead();
+        return token.type === Token.Keyword && token.value === keyword;
+    }
+
+    // Return true if the next token is an assignment operator
+
+    function matchAssign() {
+        var token = lookahead(),
+            op = token.value;
+
+        if (token.type !== Token.Punctuator) {
+            return false;
+        }
+        return op === '=' ||
+            op === '*=' ||
+            op === '/=' ||
+            op === '%=' ||
+            op === '+=' ||
+            op === '-=' ||
+            op === '<<=' ||
+            op === '>>=' ||
+            op === '>>>=' ||
+            op === '&=' ||
+            op === '^=' ||
+            op === '|=';
+    }
+
+    function consumeSemicolon() {
+        var token, line;
+
+        // Catch the very common case first.
+        if (source[index] === ';') {
+            lex();
+            return;
+        }
+
+        line = lineNumber;
+        skipComment();
+        if (lineNumber !== line) {
+            return;
+        }
+
+        if (match(';')) {
+            lex();
+            return;
+        }
+
+        token = lookahead();
+        if (token.type !== Token.EOF && !match('}')) {
+            throwUnexpected(token);
+        }
+        return;
+    }
+
+    // Return true if provided expression is LeftHandSideExpression
+
+    function isLeftHandSide(expr) {
+        switch (expr.type) {
+        case 'AssignmentExpression':
+        case 'BinaryExpression':
+        case 'ConditionalExpression':
+        case 'LogicalExpression':
+        case 'SequenceExpression':
+        case 'UnaryExpression':
+        case 'UpdateExpression':
+            return false;
+        }
+        return true;
+    }
+
+    // 11.1.4 Array Initialiser
+
+    function parseArrayInitialiser() {
+        var elements = [],
+            undef;
+
+        expect('[');
+
+        while (!match(']')) {
+            if (match(',')) {
+                lex();
+                elements.push(undef);
+            } else {
+                elements.push(parseAssignmentExpression());
+
+                if (!match(']')) {
+                    expect(',');
+                }
+            }
+        }
+
+        expect(']');
+
+        return {
+            type: Syntax.ArrayExpression,
+            elements: elements
+        };
+    }
+
+    // 11.1.5 Object Initialiser
+
+    function parsePropertyFunction(param, first) {
+        var previousStrict, body;
+
+        previousStrict = strict;
+        body = parseFunctionSourceElements();
+        if (first && strict && isRestrictedWord(param[0].name)) {
+            throwError(first, Messages.StrictParamName);
+        }
+        strict = previousStrict;
+
+        return {
+            type: Syntax.FunctionExpression,
+            id: null,
+            params: param,
+            body: body
+        };
+    }
+
+    function parseObjectPropertyKey() {
+        var token = lex(),
+            key;
+
+        switch (token.type) {
+
+        case Token.StringLiteral:
+        case Token.NumericLiteral:
+            if (strict && token.octal) {
+                throwError(token, Messages.StrictOctalLiteral);
+            }
+            key = createLiteral(token);
+            break;
+
+        case Token.Identifier:
+        case Token.Keyword:
+        case Token.BooleanLiteral:
+        case Token.NullLiteral:
+            key = {
+                type: Syntax.Identifier,
+                name: token.value
+            };
+            break;
+
+        default:
+            // Unreachable, since parseObjectProperty() will not call this
+            // function with any other type of token.
+        }
+
+        return key;
+    }
+
+    function parseObjectProperty() {
+        var token, property, key, id, param;
+
+        token = lookahead();
+
+        switch (token.type) {
+
+        case Token.Identifier:
+            id = parseObjectPropertyKey();
+
+            // Property Assignment: Getter and Setter.
+
+            if (token.value === 'get' && !match(':')) {
+                key = parseObjectPropertyKey();
+                expect('(');
+                expect(')');
+                property = {
+                    type: Syntax.Property,
+                    key: key,
+                    value: parsePropertyFunction([]),
+                    kind: 'get'
+                };
+            } else if (token.value === 'set' && !match(':')) {
+                key = parseObjectPropertyKey();
+                expect('(');
+                token = lookahead();
+                if (token.type !== Token.Identifier) {
+                    throwUnexpected(lex());
+                }
+                param = [ parseVariableIdentifier() ];
+                expect(')');
+                property = {
+                    type: Syntax.Property,
+                    key: key,
+                    value: parsePropertyFunction(param, token),
+                    kind: 'set'
+                };
+            } else {
+                expect(':');
+                property = {
+                    type: Syntax.Property,
+                    key: id,
+                    value: parseAssignmentExpression(),
+                    kind: 'init'
+                };
+            }
+            break;
+
+        case Token.Keyword:
+        case Token.BooleanLiteral:
+        case Token.NullLiteral:
+        case Token.StringLiteral:
+        case Token.NumericLiteral:
+            key = parseObjectPropertyKey();
+            expect(':');
+            property = {
+                type: Syntax.Property,
+                key: key,
+                value: parseAssignmentExpression(),
+                kind: 'init'
+            };
+            break;
+
+        default:
+            throwUnexpected(token);
+        }
+
+        return property;
+    }
+
+    function parseObjectInitialiser() {
+        var token, properties = [], property, name, kind, map = {}, toString = String;
+
+        expect('{');
+
+        while (!match('}')) {
+            property = parseObjectProperty();
+
+            if (property.key.type === Syntax.Identifier) {
+                name = property.key.name;
+            } else {
+                name = toString(property.key.value);
+            }
+            kind = (property.kind === 'init') ? PropertyKind.Data : (property.kind === 'get') ? PropertyKind.Get : PropertyKind.Set;
+            if (Object.prototype.hasOwnProperty.call(map, name)) {
+                if (map[name] === PropertyKind.Data) {
+                    if (strict && kind === PropertyKind.Data) {
+                        throwError({}, Messages.StrictDuplicateProperty);
+                    } else if (kind !== PropertyKind.Data) {
+                        throwError({}, Messages.AccessorDataProperty);
+                    }
+                } else {
+                    if (kind === PropertyKind.Data) {
+                        throwError({}, Messages.AccessorDataProperty);
+                    } else if (map[name] & kind) {
+                        throwError({}, Messages.AccessorGetSet);
+                    }
+                }
+                map[name] |= kind;
+            } else {
+                map[name] = kind;
+            }
+
+            properties.push(property);
+
+            if (!match('}')) {
+                expect(',');
+            }
+        }
+
+        expect('}');
+
+        return {
+            type: Syntax.ObjectExpression,
+            properties: properties
+        };
+    }
+
+    // 11.1 Primary Expressions
+
+    function parsePrimaryExpression() {
+        var expr,
+            token = lookahead(),
+            type = token.type;
+
+        if (type === Token.Identifier) {
+            return {
+                type: Syntax.Identifier,
+                name: lex().value
+            };
+        }
+
+        if (type === Token.StringLiteral || type === Token.NumericLiteral) {
+            if (strict && token.octal) {
+                throwError(token, Messages.StrictOctalLiteral);
+            }
+            return createLiteral(lex());
+        }
+
+        if (type === Token.Keyword) {
+            if (matchKeyword('this')) {
+                lex();
+                return {
+                    type: Syntax.ThisExpression
+                };
+            }
+
+            if (matchKeyword('function')) {
+                return parseFunctionExpression();
+            }
+        }
+
+        if (type === Token.BooleanLiteral) {
+            lex();
+            token.value = (token.value === 'true');
+            return createLiteral(token);
+        }
+
+        if (type === Token.NullLiteral) {
+            lex();
+            token.value = null;
+            return createLiteral(token);
+        }
+
+        if (match('[')) {
+            return parseArrayInitialiser();
+        }
+
+        if (match('{')) {
+            return parseObjectInitialiser();
+        }
+
+        if (match('(')) {
+            lex();
+            lastParenthesized = expr = parseExpression();
+            expect(')');
+            return expr;
+        }
+
+        if (match('/') || match('/=')) {
+            return createLiteral(scanRegExp());
+        }
+
+        return throwUnexpected(lex());
+    }
+
+    // 11.2 Left-Hand-Side Expressions
+
+    function parseArguments() {
+        var args = [];
+
+        expect('(');
+
+        if (!match(')')) {
+            while (index < length) {
+                args.push(parseAssignmentExpression());
+                if (match(')')) {
+                    break;
+                }
+                expect(',');
+            }
+        }
+
+        expect(')');
+
+        return args;
+    }
+
+    function parseNonComputedProperty() {
+        var token = lex();
+
+        if (!isIdentifierName(token)) {
+            throwUnexpected(token);
+        }
+
+        return {
+            type: Syntax.Identifier,
+            name: token.value
+        };
+    }
+
+    function parseNonComputedMember(object) {
+        return {
+            type: Syntax.MemberExpression,
+            computed: false,
+            object: object,
+            property: parseNonComputedProperty()
+        };
+    }
+
+    function parseComputedMember(object) {
+        var property, expr;
+
+        expect('[');
+        property = parseExpression();
+        expr = {
+            type: Syntax.MemberExpression,
+            computed: true,
+            object: object,
+            property: property
+        };
+        expect(']');
+        return expr;
+    }
+
+    function parseCallMember(object) {
+        return {
+            type: Syntax.CallExpression,
+            callee: object,
+            'arguments': parseArguments()
+        };
+    }
+
+    function parseNewExpression() {
+        var expr;
+
+        expectKeyword('new');
+
+        expr = {
+            type: Syntax.NewExpression,
+            callee: parseLeftHandSideExpression(),
+            'arguments': []
+        };
+
+        if (match('(')) {
+            expr['arguments'] = parseArguments();
+        }
+
+        return expr;
+    }
+
+    function parseLeftHandSideExpressionAllowCall() {
+        var useNew, expr;
+
+        useNew = matchKeyword('new');
+        expr = useNew ? parseNewExpression() : parsePrimaryExpression();
+
+        while (index < length) {
+            if (match('.')) {
+                lex();
+                expr = parseNonComputedMember(expr);
+            } else if (match('[')) {
+                expr = parseComputedMember(expr);
+            } else if (match('(')) {
+                expr = parseCallMember(expr);
+            } else {
+                break;
+            }
+        }
+
+        return expr;
+    }
+
+    function parseLeftHandSideExpression() {
+        var useNew, expr;
+
+        useNew = matchKeyword('new');
+        expr = useNew ? parseNewExpression() : parsePrimaryExpression();
+
+        while (index < length) {
+            if (match('.')) {
+                lex();
+                expr = parseNonComputedMember(expr);
+            } else if (match('[')) {
+                expr = parseComputedMember(expr);
+            } else {
+                break;
+            }
+        }
+
+        return expr;
+    }
+
+    // 11.3 Postfix Expressions
+
+    function parsePostfixExpression() {
+        var expr = parseLeftHandSideExpressionAllowCall();
+
+        if ((match('++') || match('--')) && !peekLineTerminator()) {
+            // 11.3.1, 11.3.2
+            if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
+                throwError({}, Messages.StrictLHSPostfix);
+            }
+            expr = {
+                type: Syntax.UpdateExpression,
+                operator: lex().value,
+                argument: expr,
+                prefix: false
+            };
+        }
+
+        return expr;
+    }
+
+    // 11.4 Unary Operators
+
+    function parseUnaryExpression() {
+        var token, expr;
+
+        if (match('++') || match('--')) {
+            token = lex();
+            expr = parseUnaryExpression();
+            // 11.4.4, 11.4.5
+            if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
+                throwError({}, Messages.StrictLHSPrefix);
+            }
+            expr = {
+                type: Syntax.UpdateExpression,
+                operator: token.value,
+                argument: expr,
+                prefix: true
+            };
+            return expr;
+        }
+
+        if (match('+') || match('-') || match('~') || match('!')) {
+            expr = {
+                type: Syntax.UnaryExpression,
+                operator: lex().value,
+                argument: parseUnaryExpression()
+            };
+            return expr;
+        }
+
+        if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) {
+            expr = {
+                type: Syntax.UnaryExpression,
+                operator: lex().value,
+                argument: parseUnaryExpression()
+            };
+            if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) {
+                throwError({}, Messages.StrictDelete);
+            }
+            return expr;
+        }
+
+        return parsePostfixExpression();
+    }
+
+    // 11.5 Multiplicative Operators
+
+    function parseMultiplicativeExpression() {
+        var expr = parseUnaryExpression();
+
+        while (match('*') || match('/') || match('%')) {
+            expr = {
+                type: Syntax.BinaryExpression,
+                operator: lex().value,
+                left: expr,
+                right: parseUnaryExpression()
+            };
+        }
+
+        return expr;
+    }
+
+    // 11.6 Additive Operators
+
+    function parseAdditiveExpression() {
+        var expr = parseMultiplicativeExpression();
+
+        while (match('+') || match('-')) {
+            expr = {
+                type: Syntax.BinaryExpression,
+                operator: lex().value,
+                left: expr,
+                right: parseMultiplicativeExpression()
+            };
+        }
+
+        return expr;
+    }
+
+    // 11.7 Bitwise Shift Operators
+
+    function parseShiftExpression() {
+        var expr = parseAdditiveExpression();
+
+        while (match('<<') || match('>>') || match('>>>')) {
+            expr = {
+                type: Syntax.BinaryExpression,
+                operator: lex().value,
+                left: expr,
+                right: parseAdditiveExpression()
+            };
+        }
+
+        return expr;
+    }
+    // 11.8 Relational Operators
+
+    function parseRelationalExpression() {
+        var expr, previousAllowIn;
+
+        previousAllowIn = allowIn;
+        allowIn = true;
+        expr = parseShiftExpression();
+        allowIn = previousAllowIn;
+
+        if (match('<') || match('>') || match('<=') || match('>=')) {
+            expr = {
+                type: Syntax.BinaryExpression,
+                operator: lex().value,
+                left: expr,
+                right: parseRelationalExpression()
+            };
+        } else if (allowIn && matchKeyword('in')) {
+            lex();
+            expr = {
+                type: Syntax.BinaryExpression,
+                operator: 'in',
+                left: expr,
+                right: parseRelationalExpression()
+            };
+        } else if (matchKeyword('instanceof')) {
+            lex();
+            expr = {
+                type: Syntax.BinaryExpression,
+                operator: 'instanceof',
+                left: expr,
+                right: parseRelationalExpression()
+            };
+        }
+
+        return expr;
+    }
+
+    // 11.9 Equality Operators
+
+    function parseEqualityExpression() {
+        var expr = parseRelationalExpression();
+
+        while (match('==') || match('!=') || match('===') || match('!==')) {
+            expr = {
+                type: Syntax.BinaryExpression,
+                operator: lex().value,
+                left: expr,
+                right: parseRelationalExpression()
+            };
+        }
+
+        return expr;
+    }
+
+    // 11.10 Binary Bitwise Operators
+
+    function parseBitwiseANDExpression() {
+        var expr = parseEqualityExpression();
+
+        while (match('&')) {
+            lex();
+            expr = {
+                type: Syntax.BinaryExpression,
+                operator: '&',
+                left: expr,
+                right: parseEqualityExpression()
+            };
+        }
+
+        return expr;
+    }
+
+    function parseBitwiseORExpression() {
+        var expr = parseBitwiseANDExpression();
+
+        while (match('|')) {
+            lex();
+            expr = {
+                type: Syntax.BinaryExpression,
+                operator: '|',
+                left: expr,
+                right: parseBitwiseANDExpression()
+            };
+        }
+
+        return expr;
+    }
+
+    function parseBitwiseXORExpression() {
+        var expr = parseBitwiseORExpression();
+
+        while (match('^')) {
+            lex();
+            expr = {
+                type: Syntax.BinaryExpression,
+                operator: '^',
+                left: expr,
+                right: parseBitwiseORExpression()
+            };
+        }
+
+        return expr;
+    }
+
+    // 11.11 Binary Logical Operators
+
+    function parseLogicalANDExpression() {
+        var expr = parseBitwiseXORExpression();
+
+        while (match('&&')) {
+            lex();
+            expr = {
+                type: Syntax.LogicalExpression,
+                operator: '&&',
+                left: expr,
+                right: parseBitwiseXORExpression()
+            };
+        }
+
+        return expr;
+    }
+
+    function parseLogicalORExpression() {
+        var expr = parseLogicalANDExpression();
+
+        while (match('||')) {
+            lex();
+            expr = {
+                type: Syntax.LogicalExpression,
+                operator: '||',
+                left: expr,
+                right: parseLogicalANDExpression()
+            };
+        }
+
+        return expr;
+    }
+
+    // 11.12 Conditional Operator
+
+    function parseConditionalExpression() {
+        var expr, previousAllowIn, consequent;
+
+        expr = parseLogicalORExpression();
+
+        if (match('?')) {
+            lex();
+            previousAllowIn = allowIn;
+            allowIn = true;
+            consequent = parseAssignmentExpression();
+            allowIn = previousAllowIn;
+            expect(':');
+
+            expr = {
+                type: Syntax.ConditionalExpression,
+                test: expr,
+                consequent: consequent,
+                alternate: parseAssignmentExpression()
+            };
+        }
+
+        return expr;
+    }
+
+    // 11.13 Assignment Operators
+
+    function parseAssignmentExpression() {
+        var expr;
+
+        expr = parseConditionalExpression();
+
+        if (matchAssign()) {
+            // LeftHandSideExpression
+            if (lastParenthesized !== expr && !isLeftHandSide(expr)) {
+                throwError({}, Messages.InvalidLHSInAssignment);
+            }
+
+            // 11.13.1
+            if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
+                throwError({}, Messages.StrictLHSAssignment);
+            }
+
+            expr = {
+                type: Syntax.AssignmentExpression,
+                operator: lex().value,
+                left: expr,
+                right: parseAssignmentExpression()
+            };
+        }
+
+        return expr;
+    }
+
+    // 11.14 Comma Operator
+
+    function parseExpression() {
+        var expr = parseAssignmentExpression();
+
+        if (match(',')) {
+            expr = {
+                type: Syntax.SequenceExpression,
+                expressions: [ expr ]
+            };
+
+            while (index < length) {
+                if (!match(',')) {
+                    break;
+                }
+                lex();
+                expr.expressions.push(parseAssignmentExpression());
+            }
+
+        }
+        return expr;
+    }
+
+    // 12.1 Block
+
+    function parseStatementList() {
+        var list = [],
+            statement;
+
+        while (index < length) {
+            if (match('}')) {
+                break;
+            }
+            statement = parseSourceElement();
+            if (typeof statement === 'undefined') {
+                break;
+            }
+            list.push(statement);
+        }
+
+        return list;
+    }
+
+    function parseBlock() {
+        var block;
+
+        expect('{');
+
+        block = parseStatementList();
+
+        expect('}');
+
+        return {
+            type: Syntax.BlockStatement,
+            body: block
+        };
+    }
+
+    // 12.2 Variable Statement
+
+    function parseVariableIdentifier() {
+        var token = lex();
+
+        if (token.type !== Token.Identifier) {
+            throwUnexpected(token);
+        }
+
+        return {
+            type: Syntax.Identifier,
+            name: token.value
+        };
+    }
+
+    function parseVariableDeclaration(kind) {
+        var id = parseVariableIdentifier(),
+            init = null;
+
+        // 12.2.1
+        if (strict && isRestrictedWord(id.name)) {
+            throwError({}, Messages.StrictVarName);
+        }
+
+        if (kind === 'const') {
+            expect('=');
+            init = parseAssignmentExpression();
+        } else if (match('=')) {
+            lex();
+            init = parseAssignmentExpression();
+        }
+
+        return {
+            type: Syntax.VariableDeclarator,
+            id: id,
+            init: init
+        };
+    }
+
+    function parseVariableDeclarationList(kind) {
+        var list = [];
+
+        while (index < length) {
+            list.push(parseVariableDeclaration(kind));
+            if (!match(',')) {
+                break;
+            }
+            lex();
+        }
+
+        return list;
+    }
+
+    function parseVariableStatement() {
+        var declarations;
+
+        expectKeyword('var');
+
+        declarations = parseVariableDeclarationList();
+
+        consumeSemicolon();
+
+        return {
+            type: Syntax.VariableDeclaration,
+            declarations: declarations,
+            kind: 'var'
+        };
+    }
+
+    // kind may be `const` or `let`
+    // Both are experimental and not in the specification yet.
+    // see http://wiki.ecmascript.org/doku.php?id=harmony:const
+    // and http://wiki.ecmascript.org/doku.php?id=harmony:let
+    function parseConstLetDeclaration(kind) {
+        var declarations;
+
+        expectKeyword(kind);
+
+        declarations = parseVariableDeclarationList(kind);
+
+        consumeSemicolon();
+
+        return {
+            type: Syntax.VariableDeclaration,
+            declarations: declarations,
+            kind: kind
+        };
+    }
+
+    // 12.3 Empty Statement
+
+    function parseEmptyStatement() {
+        expect(';');
+
+        return {
+            type: Syntax.EmptyStatement
+        };
+    }
+
+    // 12.4 Expression Statement
+
+    function parseExpressionStatement() {
+        var expr = parseExpression();
+
+        consumeSemicolon();
+
+        return {
+            type: Syntax.ExpressionStatement,
+            expression: expr
+        };
+    }
+
+    // 12.5 If statement
+
+    function parseIfStatement() {
+        var test, consequent, alternate;
+
+        expectKeyword('if');
+
+        expect('(');
+
+        test = parseExpression();
+
+        expect(')');
+
+        consequent = parseStatement();
+
+        if (matchKeyword('else')) {
+            lex();
+            alternate = parseStatement();
+        } else {
+            alternate = null;
+        }
+
+        return {
+            type: Syntax.IfStatement,
+            test: test,
+            consequent: consequent,
+            alternate: alternate
+        };
+    }
+
+    // 12.6 Iteration Statements
+
+    function parseDoWhileStatement() {
+        var body, test, oldInIteration;
+
+        expectKeyword('do');
+
+        oldInIteration = inIteration;
+        inIteration = true;
+
+        body = parseStatement();
+
+        inIteration = oldInIteration;
+
+        expectKeyword('while');
+
+        expect('(');
+
+        test = parseExpression();
+
+        expect(')');
+
+        if (match(';')) {
+            lex();
+        }
+
+        return {
+            type: Syntax.DoWhileStatement,
+            body: body,
+            test: test
+        };
+    }
+
+    function parseWhileStatement() {
+        var test, body, oldInIteration;
+
+        expectKeyword('while');
+
+        expect('(');
+
+        test = parseExpression();
+
+        expect(')');
+
+        oldInIteration = inIteration;
+        inIteration = true;
+
+        body = parseStatement();
+
+        inIteration = oldInIteration;
+
+        return {
+            type: Syntax.WhileStatement,
+            test: test,
+            body: body
+        };
+    }
+
+    function parseForVariableDeclaration() {
+        var token = lex();
+
+        return {
+            type: Syntax.VariableDeclaration,
+            declarations: parseVariableDeclarationList(),
+            kind: token.value
+        };
+    }
+
+    function parseForStatement() {
+        var init, test, update, left, right, body, oldInIteration;
+
+        init = test = update = null;
+
+        expectKeyword('for');
+
+        expect('(');
+
+        if (match(';')) {
+            lex();
+        } else {
+            if (matchKeyword('var') || matchKeyword('let')) {
+                allowIn = false;
+                init = parseForVariableDeclaration();
+                allowIn = true;
+
+                if (init.declarations.length === 1 && matchKeyword('in')) {
+                    lex();
+                    left = init;
+                    right = parseExpression();
+                    init = null;
+                }
+            } else {
+                allowIn = false;
+                init = parseExpression();
+                allowIn = true;
+
+                if (matchKeyword('in')) {
+                    // LeftHandSideExpression
+                    if (matchKeyword('in') && (lastParenthesized !== init && !isLeftHandSide(init))) {
+                        throwError({}, Messages.InvalidLHSInForIn);
+                    }
+                    lex();
+                    left = init;
+                    right = parseExpression();
+                    init = null;
+                }
+            }
+
+            if (typeof left === 'undefined') {
+                expect(';');
+            }
+        }
+
+        if (typeof left === 'undefined') {
+
+            if (!match(';')) {
+                test = parseExpression();
+            }
+            expect(';');
+
+            if (!match(')')) {
+                update = parseExpression();
+            }
+        }
+
+        expect(')');
+
+        oldInIteration = inIteration;
+        inIteration = true;
+
+        body = parseStatement();
+
+        inIteration = oldInIteration;
+
+        if (typeof left === 'undefined') {
+            return {
+                type: Syntax.ForStatement,
+                init: init,
+                test: test,
+                update: update,
+                body: body
+            };
+        }
+
+        return {
+            type: Syntax.ForInStatement,
+            left: left,
+            right: right,
+            body: body,
+            each: false
+        };
+    }
+
+    // 12.7 The continue statement
+
+    function parseContinueStatement() {
+        var token, label = null;
+
+        expectKeyword('continue');
+
+        // Optimize the most common form: 'continue;'.
+        if (source[index] === ';') {
+            lex();
+            
+            if (!inIteration) {
+                throwError({}, Messages.IllegalContinue);
+            }
+
+            return {
+                type: Syntax.ContinueStatement,
+                label: null
+            };
+        }
+
+        if (peekLineTerminator()) {
+            if (!inIteration) {
+                throwError({}, Messages.IllegalContinue);
+            }
+
+            return {
+                type: Syntax.ContinueStatement,
+                label: null
+            };
+        }
+
+        token = lookahead();
+        if (token.type === Token.Identifier) {
+            label = parseVariableIdentifier();
+
+            if (!Object.prototype.hasOwnProperty.call(labelSet, label.name)) {
+                throwError({}, Messages.UnknownLabel, label.name);
+            }
+        }
+
+        consumeSemicolon();
+
+        if (label === null && !inIteration) {
+            throwError({}, Messages.IllegalContinue);
+        }
+
+        return {
+            type: Syntax.ContinueStatement,
+            label: label
+        };
+    }
+
+    // 12.8 The break statement
+
+    function parseBreakStatement() {
+        var token, label = null;
+
+        expectKeyword('break');
+
+        // Optimize the most common form: 'break;'.
+        if (source[index] === ';') {
+            lex();
+            
+            if (!(inIteration || inSwitch)) {
+                throwError({}, Messages.IllegalBreak);
+            }
+
+            return {
+                type: Syntax.BreakStatement,
+                label: null
+            };
+        }
+
+        if (peekLineTerminator()) {
+            if (!(inIteration || inSwitch)) {
+                throwError({}, Messages.IllegalBreak);
+            }
+
+            return {
+                type: Syntax.BreakStatement,
+                label: null
+            };
+        }
+
+        token = lookahead();
+        if (token.type === Token.Identifier) {
+            label = parseVariableIdentifier();
+
+            if (!Object.prototype.hasOwnProperty.call(labelSet, label.name)) {
+                throwError({}, Messages.UnknownLabel, label.name);
+            }
+        }
+
+        consumeSemicolon();
+
+        if (label === null && !(inIteration || inSwitch)) {
+            throwError({}, Messages.IllegalBreak);
+        }
+
+        return {
+            type: Syntax.BreakStatement,
+            label: label
+        };
+    }
+
+    // 12.9 The return statement
+
+    function parseReturnStatement() {
+        var token, argument = null;
+
+        expectKeyword('return');
+
+        if (!inFunctionBody) {
+            throwError({}, Messages.IllegalReturn);
+        }
+
+        // 'return' followed by a space and an identifier is very common.
+        if (source[index] === ' ') {
+            if (isIdentifierStart(source[index + 1])) {
+                argument = parseExpression();
+                consumeSemicolon();
+                return {
+                    type: Syntax.ReturnStatement,
+                    argument: argument
+                };
+            }
+        }
+
+        if (peekLineTerminator()) {
+            return {
+                type: Syntax.ReturnStatement,
+                argument: null
+            };
+        }
+
+        if (!match(';')) {
+            token = lookahead();
+            if (!match('}') && token.type !== Token.EOF) {
+                argument = parseExpression();
+            }
+        }
+
+        consumeSemicolon();
+
+        return {
+            type: Syntax.ReturnStatement,
+            argument: argument
+        };
+    }
+
+    // 12.10 The with statement
+
+    function parseWithStatement() {
+        var object, body;
+
+        if (strict) {
+            throwError({}, Messages.StrictModeWith);
+        }
+
+        expectKeyword('with');
+
+        expect('(');
+
+        object = parseExpression();
+
+        expect(')');
+
+        body = parseStatement();
+
+        return {
+            type: Syntax.WithStatement,
+            object: object,
+            body: body
+        };
+    }
+
+    // 12.10 The swith statement
+
+    function parseSwitchCase(test) {
+        var consequent = [],
+            statement;
+
+        while (index < length) {
+            if (match('}') || matchKeyword('default') || matchKeyword('case')) {
+                break;
+            }
+            statement = parseStatement();
+            if (typeof statement === 'undefined') {
+                break;
+            }
+            consequent.push(statement);
+        }
+
+        return {
+            type: Syntax.SwitchCase,
+            test: test,
+            consequent: consequent
+        };
+    }
+
+    function parseSwitchStatement() {
+        var discriminant, cases, test, oldInSwitch;
+
+        expectKeyword('switch');
+
+        expect('(');
+
+        discriminant = parseExpression();
+
+        expect(')');
+
+        expect('{');
+
+        if (match('}')) {
+            lex();
+            return {
+                type: Syntax.SwitchStatement,
+                discriminant: discriminant
+            };
+        }
+
+        cases = [];
+
+        oldInSwitch = inSwitch;
+        inSwitch = true;
+
+        while (index < length) {
+            if (match('}')) {
+                break;
+            }
+
+            if (matchKeyword('default')) {
+                lex();
+                test = null;
+            } else {
+                expectKeyword('case');
+                test = parseExpression();
+            }
+            expect(':');
+
+            cases.push(parseSwitchCase(test));
+        }
+
+        inSwitch = oldInSwitch;
+
+        expect('}');
+
+        return {
+            type: Syntax.SwitchStatement,
+            discriminant: discriminant,
+            cases: cases
+        };
+    }
+
+    // 12.13 The throw statement
+
+    function parseThrowStatement() {
+        var argument;
+
+        expectKeyword('throw');
+
+        if (peekLineTerminator()) {
+            throwError({}, Messages.NewlineAfterThrow);
+        }
+
+        argument = parseExpression();
+
+        consumeSemicolon();
+
+        return {
+            type: Syntax.ThrowStatement,
+            argument: argument
+        };
+    }
+
+    // 12.14 The try statement
+
+    function parseCatchClause() {
+        var param;
+
+        expectKeyword('catch');
+
+        expect('(');
+        if (!match(')')) {
+            param = parseExpression();
+            // 12.14.1
+            if (strict && param.type === Syntax.Identifier && isRestrictedWord(param.name)) {
+                throwError({}, Messages.StrictCatchVariable);
+            }
+        }
+        expect(')');
+
+        return {
+            type: Syntax.CatchClause,
+            param: param,
+            guard: null,
+            body: parseBlock()
+        };
+    }
+
+    function parseTryStatement() {
+        var block, handlers = [], finalizer = null;
+
+        expectKeyword('try');
+
+        block = parseBlock();
+
+        if (matchKeyword('catch')) {
+            handlers.push(parseCatchClause());
+        }
+
+        if (matchKeyword('finally')) {
+            lex();
+            finalizer = parseBlock();
+        }
+
+        if (handlers.length === 0 && !finalizer) {
+            throwError({}, Messages.NoCatchOrFinally);
+        }
+
+        return {
+            type: Syntax.TryStatement,
+            block: block,
+            handlers: handlers,
+            finalizer: finalizer
+        };
+    }
+
+    // 12.15 The debugger statement
+
+    function parseDebuggerStatement() {
+        expectKeyword('debugger');
+
+        consumeSemicolon();
+
+        return {
+            type: Syntax.DebuggerStatement
+        };
+    }
+
+    // 12 Statements
+
+    function parseStatement() {
+        var token = lookahead(),
+            expr,
+            labeledBody;
+
+        if (token.type === Token.EOF) {
+            throwUnexpected(token);
+        }
+
+        if (token.type === Token.Punctuator) {
+            switch (token.value) {
+            case ';':
+                return parseEmptyStatement();
+            case '{':
+                return parseBlock();
+            case '(':
+                return parseExpressionStatement();
+            default:
+                break;
+            }
+        }
+
+        if (token.type === Token.Keyword) {
+            switch (token.value) {
+            case 'break':
+                return parseBreakStatement();
+            case 'continue':
+                return parseContinueStatement();
+            case 'debugger':
+                return parseDebuggerStatement();
+            case 'do':
+                return parseDoWhileStatement();
+            case 'for':
+                return parseForStatement();
+            case 'function':
+                return parseFunctionDeclaration();
+            case 'if':
+                return parseIfStatement();
+            case 'return':
+                return parseReturnStatement();
+            case 'switch':
+                return parseSwitchStatement();
+            case 'throw':
+                return parseThrowStatement();
+            case 'try':
+                return parseTryStatement();
+            case 'var':
+                return parseVariableStatement();
+            case 'while':
+                return parseWhileStatement();
+            case 'with':
+                return parseWithStatement();
+            default:
+                break;
+            }
+        }
+
+        expr = parseExpression();
+
+        // 12.12 Labelled Statements
+        if ((expr.type === Syntax.Identifier) && match(':')) {
+            lex();
+
+            if (Object.prototype.hasOwnProperty.call(labelSet, expr.name)) {
+                throwError({}, Messages.Redeclaration, 'Label', expr.name);
+            }
+
+            labelSet[expr.name] = true;
+            labeledBody = parseStatement();
+            delete labelSet[expr.name];
+
+            return {
+                type: Syntax.LabeledStatement,
+                label: expr,
+                body: labeledBody
+            };
+        }
+
+        consumeSemicolon();
+
+        return {
+            type: Syntax.ExpressionStatement,
+            expression: expr
+        };
+    }
+
+    // 13 Function Definition
+
+    function parseFunctionSourceElements() {
+        var sourceElement, sourceElements = [], token, directive, firstRestricted, oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody;
+
+        expect('{');
+
+        while (index < length) {
+            token = lookahead();
+            if (token.type !== Token.StringLiteral) {
+                break;
+            }
+
+            sourceElement = parseSourceElement();
+            sourceElements.push(sourceElement);
+            if (sourceElement.expression.type !== Syntax.Literal) {
+                // this is not directive
+                break;
+            }
+            directive = sliceSource(token.range[0] + 1, token.range[1] - 1);
+            if (directive === 'use strict') {
+                strict = true;
+                if (firstRestricted) {
+                    throwError(firstRestricted, Messages.StrictOctalLiteral);
+                }
+            } else {
+                if (!firstRestricted && token.octal) {
+                    firstRestricted = token;
+                }
+            }
+        }
+
+        oldLabelSet = labelSet;
+        oldInIteration = inIteration;
+        oldInSwitch = inSwitch;
+        oldInFunctionBody = inFunctionBody;
+
+        labelSet = {};
+        inIteration = false;
+        inSwitch = false;
+        inFunctionBody = true;
+
+        while (index < length) {
+            if (match('}')) {
+                break;
+            }
+            sourceElement = parseSourceElement();
+            if (typeof sourceElement === 'undefined') {
+                break;
+            }
+            sourceElements.push(sourceElement);
+        }
+
+        expect('}');
+
+        labelSet = oldLabelSet;
+        inIteration = oldInIteration;
+        inSwitch = oldInSwitch;
+        inFunctionBody = oldInFunctionBody;
+
+        return {
+            type: Syntax.BlockStatement,
+            body: sourceElements
+        };
+    }
+
+    function parseFunctionDeclaration() {
+        var id, param, params = [], body, token, firstRestricted, message, previousStrict, paramSet;
+
+        expectKeyword('function');
+        token = lookahead();
+        id = parseVariableIdentifier();
+        if (strict) {
+            if (isRestrictedWord(token.value)) {
+                throwError(token, Messages.StrictFunctionName);
+            }
+        } else {
+            if (isRestrictedWord(token.value)) {
+                firstRestricted = token;
+                message = Messages.StrictFunctionName;
+            } else if (isStrictModeReservedWord(token.value)) {
+                firstRestricted = token;
+                message = Messages.StrictReservedWord;
+            }
+        }
+
+        expect('(');
+
+        if (!match(')')) {
+            paramSet = {};
+            while (index < length) {
+                token = lookahead();
+                param = parseVariableIdentifier();
+                if (strict) {
+                    if (isRestrictedWord(token.value)) {
+                        throwError(token, Messages.StrictParamName);
+                    }
+                    if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) {
+                        throwError(token, Messages.StrictParamDupe);
+                    }
+                } else if (!firstRestricted) {
+                    if (isRestrictedWord(token.value)) {
+                        firstRestricted = token;
+                        message = Messages.StrictParamName;
+                    } else if (isStrictModeReservedWord(token.value)) {
+                        firstRestricted = token;
+                        message = Messages.StrictReservedWord;
+                    } else if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) {
+                        firstRestricted = token;
+                        message = Messages.StrictParamDupe;
+                    }
+                }
+                params.push(param);
+                paramSet[param.name] = true;
+                if (match(')')) {
+                    break;
+                }
+                expect(',');
+            }
+        }
+
+        expect(')');
+
+        previousStrict = strict;
+        body = parseFunctionSourceElements();
+        if (strict && firstRestricted) {
+            throwError(firstRestricted, message);
+        }
+        strict = previousStrict;
+
+        return {
+            type: Syntax.FunctionDeclaration,
+            id: id,
+            params: params,
+            body: body
+        };
+    }
+
+    function parseFunctionExpression() {
+        var token, id = null, firstRestricted, message, param, params = [], body, previousStrict, paramSet;
+
+        expectKeyword('function');
+
+        if (!match('(')) {
+            token = lookahead();
+            id = parseVariableIdentifier();
+            if (strict) {
+                if (isRestrictedWord(token.value)) {
+                    throwError(token, Messages.StrictFunctionName);
+                }
+            } else {
+                if (isRestrictedWord(token.value)) {
+                    firstRestricted = token;
+                    message = Messages.StrictFunctionName;
+                } else if (isStrictModeReservedWord(token.value)) {
+                    firstRestricted = token;
+                    message = Messages.StrictReservedWord;
+                }
+            }
+        }
+
+        expect('(');
+
+        if (!match(')')) {
+            paramSet = {};
+            while (index < length) {
+                token = lookahead();
+                param = parseVariableIdentifier();
+                if (strict) {
+                    if (isRestrictedWord(token.value)) {
+                        throwError(token, Messages.StrictParamName);
+                    }
+                    if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) {
+                        throwError(token, Messages.StrictParamDupe);
+                    }
+                } else if (!firstRestricted) {
+                    if (isRestrictedWord(token.value)) {
+                        firstRestricted = token;
+                        message = Messages.StrictParamName;
+                    } else if (isStrictModeReservedWord(token.value)) {
+                        firstRestricted = token;
+                        message = Messages.StrictReservedWord;
+                    } else if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) {
+                        firstRestricted = token;
+                        message = Messages.StrictParamDupe;
+                    }
+                }
+                params.push(param);
+                paramSet[param.name] = true;
+                if (match(')')) {
+                    break;
+                }
+                expect(',');
+            }
+        }
+
+        expect(')');
+
+        previousStrict = strict;
+        body = parseFunctionSourceElements();
+        if (strict && firstRestricted) {
+            throwError(firstRestricted, message);
+        }
+        strict = previousStrict;
+
+        return {
+            type: Syntax.FunctionExpression,
+            id: id,
+            params: params,
+            body: body
+        };
+    }
+
+    // 14 Program
+
+    function parseSourceElement() {
+        var token = lookahead();
+
+        if (token.type === Token.Keyword) {
+            switch (token.value) {
+            case 'const':
+            case 'let':
+                return parseConstLetDeclaration(token.value);
+            case 'function':
+                return parseFunctionDeclaration();
+            default:
+                return parseStatement();
+            }
+        }
+
+        if (token.type !== Token.EOF) {
+            return parseStatement();
+        }
+    }
+
+    function parseSourceElements() {
+        var sourceElement, sourceElements = [], token, directive, firstRestricted;
+
+        while (index < length) {
+            token = lookahead();
+            if (token.type !== Token.StringLiteral) {
+                break;
+            }
+
+            sourceElement = parseSourceElement();
+            sourceElements.push(sourceElement);
+            if (sourceElement.expression.type !== Syntax.Literal) {
+                // this is not directive
+                break;
+            }
+            directive = sliceSource(token.range[0] + 1, token.range[1] - 1);
+            if (directive === 'use strict') {
+                strict = true;
+                if (firstRestricted) {
+                    throwError(firstRestricted, Messages.StrictOctalLiteral);
+                }
+            } else {
+                if (!firstRestricted && token.octal) {
+                    firstRestricted = token;
+                }
+            }
+        }
+
+        while (index < length) {
+            sourceElement = parseSourceElement();
+            if (typeof sourceElement === 'undefined') {
+                break;
+            }
+            sourceElements.push(sourceElement);
+        }
+        return sourceElements;
+    }
+
+    function parseProgram() {
+        var program;
+        strict = false;
+        program = {
+            type: Syntax.Program,
+            body: parseSourceElements()
+        };
+        return program;
+    }
+
+    // The following functions are needed only when the option to preserve
+    // the comments is active.
+
+    function addComment(start, end, type, value) {
+        if (typeof start !== 'number') {
+            return;
+        }
+
+        // Because the way the actual token is scanned, often the comments
+        // (if any) are skipped twice during the lexical analysis.
+        // Thus, we need to skip adding a comment if the comment array already
+        // handled it.
+        if (extra.comments.length > 0) {
+            if (extra.comments[extra.comments.length - 1].range[1] > start) {
+                return;
+            }
+        }
+
+        extra.comments.push({
+            range: [start, end],
+            type: type,
+            value: value
+        });
+    }
+
+    function scanComment() {
+        var comment, ch, start, blockComment, lineComment;
+
+        comment = '';
+        blockComment = false;
+        lineComment = false;
+
+        while (index < length) {
+            ch = source[index];
+
+            if (lineComment) {
+                ch = nextChar();
+                if (isLineTerminator(ch)) {
+                    lineComment = false;
+                    addComment(start, index - 1, 'Line', comment);
+                    if (ch === '\r' && source[index] === '\n') {
+                        index += 1;
+                    }
+                    lineNumber += 1;
+                    lineStart = index;
+                    comment = '';
+                } else {
+                    comment += ch;
+                }
+            } else if (blockComment) {
+                if (isLineTerminator(ch)) {
+                    if (ch === '\r' && source[index + 1] === '\n') {
+                        index += 1;
+                    }
+                    lineNumber += 1;
+                    index += 1;
+                    lineStart = index;
+                    if (index >= length) {
+                        throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+                    }
+                } else {
+                    ch = nextChar();
+                    if (index >= length) {
+                        throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+                    }
+                    comment += ch;
+                    if (ch === '*') {
+                        ch = source[index];
+                        if (ch === '/') {
+                            comment = comment.substr(0, comment.length - 1);
+                            blockComment = false;
+                            index += 1;
+                            addComment(start, index - 1, 'Block', comment);
+                            comment = '';
+                        }
+                    }
+                }
+            } else if (ch === '/') {
+                ch = source[index + 1];
+                if (ch === '/') {
+                    start = index;
+                    index += 2;
+                    lineComment = true;
+                } else if (ch === '*') {
+                    start = index;
+                    index += 2;
+                    blockComment = true;
+                    if (index >= length) {
+                        throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+                    }
+                } else {
+                    break;
+                }
+            } else if (isWhiteSpace(ch)) {
+                index += 1;
+            } else if (isLineTerminator(ch)) {
+                index += 1;
+                if (ch ===  '\r' && source[index] === '\n') {
+                    index += 1;
+                }
+                lineNumber += 1;
+                lineStart = index;
+            } else {
+                break;
+            }
+        }
+
+        addComment(start, index, (blockComment) ? 'Block' : 'Line', comment);
+    }
+
+    function collectToken() {
+        var token = extra.advance(),
+            range,
+            value;
+
+        if (token.type !== Token.EOF) {
+            range = [token.range[0], token.range[1] - 1];
+            value = sliceSource(token.range[0], token.range[1]);
+            extra.tokens.push({
+                type: TokenName[token.type],
+                value: value,
+                range: range
+            });
+        }
+
+        return token;
+    }
+
+    function collectRegex() {
+        var pos, regex, token;
+
+        skipComment();
+
+        pos = index;
+        regex = extra.scanRegExp();
+
+        // Pop the previous token, which is likely '/' or '/='
+        if (extra.tokens.length > 0) {
+            token = extra.tokens[extra.tokens.length - 1];
+            if (token.range[0] === pos && token.type === 'Punctuator') {
+                if (token.value === '/' || token.value === '/=') {
+                    extra.tokens.pop();
+                }
+            }
+        }
+
+        extra.tokens.push({
+            type: 'RegularExpression',
+            value: regex.literal,
+            range: [pos, index - 1]
+        });
+
+        return regex;
+    }
+
+    function createLiteral(token) {
+        return {
+            type: Syntax.Literal,
+            value: token.value
+        };
+    }
+
+    function createRawLiteral(token) {
+        return {
+            type: Syntax.Literal,
+            value: token.value,
+            raw: sliceSource(token.range[0], token.range[1])
+        };
+    }
+
+    function wrapTrackingFunction(range, loc) {
+
+        return function (parseFunction) {
+
+            function isBinary(node) {
+                return node.type === Syntax.LogicalExpression ||
+                    node.type === Syntax.BinaryExpression;
+            }
+
+            function visit(node) {
+                if (range) {
+                    if (isBinary(node.left) && (typeof node.left.range === 'undefined')) {
+                        visit(node.left);
+                    }
+                    if (isBinary(node.right) && (typeof node.right.range === 'undefined')) {
+                        visit(node.right);
+                    }
+
+                    // Expression enclosed in brackets () already has the correct range.
+                    if (typeof node.range === 'undefined') {
+                        node.range = [node.left.range[0], node.right.range[1]];
+                    }
+                }
+
+                if (loc) {
+                    if (isBinary(node.left) && (typeof node.left.loc === 'undefined')) {
+                        visit(node.left);
+                    }
+                    if (isBinary(node.right) && (typeof node.right.loc === 'undefined')) {
+                        visit(node.right);
+                    }
+
+                    if (typeof node.loc === 'undefined') {
+                        node.loc = {
+                            start: node.left.loc.start,
+                            end: node.right.loc.end
+                        };
+                    }
+                }
+            }
+
+            return function () {
+                var node, rangeInfo, locInfo;
+
+                skipComment();
+                rangeInfo = [index, 0];
+                locInfo = {
+                    start: {
+                        line: lineNumber,
+                        column: index - lineStart
+                    }
+                };
+
+                node = parseFunction.apply(null, arguments);
+                if (typeof node !== 'undefined') {
+
+                    if (range) {
+                        rangeInfo[1] = index - 1;
+                        node.range = rangeInfo;
+                    }
+
+                    if (loc) {
+                        locInfo.end = {
+                            line: lineNumber,
+                            column: index - lineStart
+                        };
+                        node.loc = locInfo;
+                    }
+
+                    if (isBinary(node)) {
+                        visit(node);
+                    }
+
+                    if (node.type === Syntax.MemberExpression) {
+                        if (typeof node.object.range !== 'undefined') {
+                            node.range[0] = node.object.range[0];
+                        }
+                        if (typeof node.object.loc !== 'undefined') {
+                            node.loc.start = node.object.loc.start;
+                        }
+                    }
+                    return node;
+                }
+            };
+
+        };
+    }
+
+    function patch() {
+
+        var wrapTracking;
+
+        if (extra.comments) {
+            extra.skipComment = skipComment;
+            skipComment = scanComment;
+        }
+
+        if (extra.raw) {
+            extra.createLiteral = createLiteral;
+            createLiteral = createRawLiteral;
+        }
+
+        if (extra.range || extra.loc) {
+
+            wrapTracking = wrapTrackingFunction(extra.range, extra.loc);
+
+            extra.parseAdditiveExpression = parseAdditiveExpression;
+            extra.parseAssignmentExpression = parseAssignmentExpression;
+            extra.parseBitwiseANDExpression = parseBitwiseANDExpression;
+            extra.parseBitwiseORExpression = parseBitwiseORExpression;
+            extra.parseBitwiseXORExpression = parseBitwiseXORExpression;
+            extra.parseBlock = parseBlock;
+            extra.parseFunctionSourceElements = parseFunctionSourceElements;
+            extra.parseCallMember = parseCallMember;
+            extra.parseCatchClause = parseCatchClause;
+            extra.parseComputedMember = parseComputedMember;
+            extra.parseConditionalExpression = parseConditionalExpression;
+            extra.parseConstLetDeclaration = parseConstLetDeclaration;
+            extra.parseEqualityExpression = parseEqualityExpression;
+            extra.parseExpression = parseExpression;
+            extra.parseForVariableDeclaration = parseForVariableDeclaration;
+            extra.parseFunctionDeclaration = parseFunctionDeclaration;
+            extra.parseFunctionExpression = parseFunctionExpression;
+            extra.parseLogicalANDExpression = parseLogicalANDExpression;
+            extra.parseLogicalORExpression = parseLogicalORExpression;
+            extra.parseMultiplicativeExpression = parseMultiplicativeExpression;
+            extra.parseNewExpression = parseNewExpression;
+            extra.parseNonComputedMember = parseNonComputedMember;
+            extra.parseNonComputedProperty = parseNonComputedProperty;
+            extra.parseObjectProperty = parseObjectProperty;
+            extra.parseObjectPropertyKey = parseObjectPropertyKey;
+            extra.parsePostfixExpression = parsePostfixExpression;
+            extra.parsePrimaryExpression = parsePrimaryExpression;
+            extra.parseProgram = parseProgram;
+            extra.parsePropertyFunction = parsePropertyFunction;
+            extra.parseRelationalExpression = parseRelationalExpression;
+            extra.parseStatement = parseStatement;
+            extra.parseShiftExpression = parseShiftExpression;
+            extra.parseSwitchCase = parseSwitchCase;
+            extra.parseUnaryExpression = parseUnaryExpression;
+            extra.parseVariableDeclaration = parseVariableDeclaration;
+            extra.parseVariableIdentifier = parseVariableIdentifier;
+
+            parseAdditiveExpression = wrapTracking(extra.parseAdditiveExpression);
+            parseAssignmentExpression = wrapTracking(extra.parseAssignmentExpression);
+            parseBitwiseANDExpression = wrapTracking(extra.parseBitwiseANDExpression);
+            parseBitwiseORExpression = wrapTracking(extra.parseBitwiseORExpression);
+            parseBitwiseXORExpression = wrapTracking(extra.parseBitwiseXORExpression);
+            parseBlock = wrapTracking(extra.parseBlock);
+            parseFunctionSourceElements = wrapTracking(extra.parseFunctionSourceElements);
+            parseCallMember = wrapTracking(extra.parseCallMember);
+            parseCatchClause = wrapTracking(extra.parseCatchClause);
+            parseComputedMember = wrapTracking(extra.parseComputedMember);
+            parseConditionalExpression = wrapTracking(extra.parseConditionalExpression);
+            parseConstLetDeclaration = wrapTracking(extra.parseConstLetDeclaration);
+            parseEqualityExpression = wrapTracking(extra.parseEqualityExpression);
+            parseExpression = wrapTracking(extra.parseExpression);
+            parseForVariableDeclaration = wrapTracking(extra.parseForVariableDeclaration);
+            parseFunctionDeclaration = wrapTracking(extra.parseFunctionDeclaration);
+            parseFunctionExpression = wrapTracking(extra.parseFunctionExpression);
+            parseLogicalANDExpression = wrapTracking(extra.parseLogicalANDExpression);
+            parseLogicalORExpression = wrapTracking(extra.parseLogicalORExpression);
+            parseMultiplicativeExpression = wrapTracking(extra.parseMultiplicativeExpression);
+            parseNewExpression = wrapTracking(extra.parseNewExpression);
+            parseNonComputedMember = wrapTracking(extra.parseNonComputedMember);
+            parseNonComputedProperty = wrapTracking(extra.parseNonComputedProperty);
+            parseObjectProperty = wrapTracking(extra.parseObjectProperty);
+            parseObjectPropertyKey = wrapTracking(extra.parseObjectPropertyKey);
+            parsePostfixExpression = wrapTracking(extra.parsePostfixExpression);
+            parsePrimaryExpression = wrapTracking(extra.parsePrimaryExpression);
+            parseProgram = wrapTracking(extra.parseProgram);
+            parsePropertyFunction = wrapTracking(extra.parsePropertyFunction);
+            parseRelationalExpression = wrapTracking(extra.parseRelationalExpression);
+            parseStatement = wrapTracking(extra.parseStatement);
+            parseShiftExpression = wrapTracking(extra.parseShiftExpression);
+            parseSwitchCase = wrapTracking(extra.parseSwitchCase);
+            parseUnaryExpression = wrapTracking(extra.parseUnaryExpression);
+            parseVariableDeclaration = wrapTracking(extra.parseVariableDeclaration);
+            parseVariableIdentifier = wrapTracking(extra.parseVariableIdentifier);
+        }
+
+        if (typeof extra.tokens !== 'undefined') {
+            extra.advance = advance;
+            extra.scanRegExp = scanRegExp;
+
+            advance = collectToken;
+            scanRegExp = collectRegex;
+        }
+    }
+
+    function unpatch() {
+        if (typeof extra.skipComment === 'function') {
+            skipComment = extra.skipComment;
+        }
+
+        if (extra.raw) {
+            createLiteral = extra.createLiteral;
+        }
+
+        if (extra.range || extra.loc) {
+            parseAdditiveExpression = extra.parseAdditiveExpression;
+            parseAssignmentExpression = extra.parseAssignmentExpression;
+            parseBitwiseANDExpression = extra.parseBitwiseANDExpression;
+            parseBitwiseORExpression = extra.parseBitwiseORExpression;
+            parseBitwiseXORExpression = extra.parseBitwiseXORExpression;
+            parseBlock = extra.parseBlock;
+            parseFunctionSourceElements = extra.parseFunctionSourceElements;
+            parseCallMember = extra.parseCallMember;
+            parseCatchClause = extra.parseCatchClause;
+            parseComputedMember = extra.parseComputedMember;
+            parseConditionalExpression = extra.parseConditionalExpression;
+            parseConstLetDeclaration = extra.parseConstLetDeclaration;
+            parseEqualityExpression = extra.parseEqualityExpression;
+            parseExpression = extra.parseExpression;
+            parseForVariableDeclaration = extra.parseForVariableDeclaration;
+            parseFunctionDeclaration = extra.parseFunctionDeclaration;
+            parseFunctionExpression = extra.parseFunctionExpression;
+            parseLogicalANDExpression = extra.parseLogicalANDExpression;
+            parseLogicalORExpression = extra.parseLogicalORExpression;
+            parseMultiplicativeExpression = extra.parseMultiplicativeExpression;
+            parseNewExpression = extra.parseNewExpression;
+            parseNonComputedMember = extra.parseNonComputedMember;
+            parseNonComputedProperty = extra.parseNonComputedProperty;
+            parseObjectProperty = extra.parseObjectProperty;
+            parseObjectPropertyKey = extra.parseObjectPropertyKey;
+            parsePrimaryExpression = extra.parsePrimaryExpression;
+            parsePostfixExpression = extra.parsePostfixExpression;
+            parseProgram = extra.parseProgram;
+            parsePropertyFunction = extra.parsePropertyFunction;
+            parseRelationalExpression = extra.parseRelationalExpression;
+            parseStatement = extra.parseStatement;
+            parseShiftExpression = extra.parseShiftExpression;
+            parseSwitchCase = extra.parseSwitchCase;
+            parseUnaryExpression = extra.parseUnaryExpression;
+            parseVariableDeclaration = extra.parseVariableDeclaration;
+            parseVariableIdentifier = extra.parseVariableIdentifier;
+        }
+
+        if (typeof extra.scanRegExp === 'function') {
+            advance = extra.advance;
+            scanRegExp = extra.scanRegExp;
+        }
+    }
+
+    function stringToArray(str) {
+        var length = str.length,
+            result = [],
+            i;
+        for (i = 0; i < length; i += 1) {
+            result[i] = str.charAt(i);
+        }
+        return result;
+    }
+
+    function parse(code, options) {
+        var program, toString;
+
+        toString = String;
+        if (typeof code !== 'string' && !(code instanceof String)) {
+            code = toString(code);
+        }
+
+        source = code;
+        index = 0;
+        lineNumber = (source.length > 0) ? 1 : 0;
+        lineStart = 0;
+        length = source.length;
+        buffer = null;
+        allowIn = true;
+        labelSet = {};
+        inSwitch = false;
+        inIteration = false;
+        lastParenthesized = null;
+        inFunctionBody = false;
+
+        extra = {};
+        if (typeof options !== 'undefined') {
+            extra.range = (typeof options.range === 'boolean') && options.range;
+            extra.loc = (typeof options.loc === 'boolean') && options.loc;
+            extra.raw = (typeof options.raw === 'boolean') && options.raw;
+            if (typeof options.tokens === 'boolean' && options.tokens) {
+                extra.tokens = [];
+            }
+            if (typeof options.comment === 'boolean' && options.comment) {
+                extra.comments = [];
+            }
+        }
+
+        if (length > 0) {
+            if (typeof source[0] === 'undefined') {
+                // Try first to convert to a string. This is good as fast path
+                // for old IE which understands string indexing for string
+                // literals only and not for string object.
+                if (code instanceof String) {
+                    source = code.valueOf();
+                }
+
+                // Force accessing the characters via an array.
+                if (typeof source[0] === 'undefined') {
+                    source = stringToArray(code);
+                }
+            }
+        }
+
+        patch();
+        try {
+            program = parseProgram();
+            if (typeof extra.comments !== 'undefined') {
+                program.comments = extra.comments;
+            }
+            if (typeof extra.tokens !== 'undefined') {
+                program.tokens = extra.tokens;
+            }
+        } catch (e) {
+            throw e;
+        } finally {
+            unpatch();
+            extra = {};
+        }
+
+        return program;
+    }
+
+    // Executes visitor on the object and its children (recursively).
+
+    function traverse(object, visitor, master) {
+        var key, child, parent, path;
+
+        parent = (typeof master === 'undefined') ? [] : master;
+
+        if (visitor.call(null, object, parent) === false) {
+            return;
+        }
+        for (key in object) {
+            if (object.hasOwnProperty(key)) {
+                child = object[key];
+                path = [ object ];
+                path.push(parent);
+                if (typeof child === 'object' && child !== null) {
+                    traverse(child, visitor, path);
+                }
+            }
+        }
+    }
+
+    // Insert a prolog in the body of every function.
+    // It will be in the form of a function call:
+    //
+    //     traceName(object);
+    //
+    // where the object contains the following properties:
+    //
+    //    'name' holds the name of the function
+    //    'lineNumber' holds the starting line number of the function block
+    //    'range' contains the index-based range of the function
+    //
+    // The name of the function represents the associated reference for
+    // the function (deduced on a best-effort basis if it is not
+    // a function declaration).
+    //
+    // If traceName is a function instead of a string, it will be invoked and
+    // the result will be used as the entire prolog. The arguments for the
+    // invocation are the function name, range, and location info.
+
+    function traceFunctionEntrance(traceName) {
+
+        return function (code) {
+            var tree,
+                functionList,
+                param,
+                signature,
+                pos,
+                i;
+
+
+            tree = parse(code, { range: true, loc: true });
+
+            functionList = [];
+            traverse(tree, function (node, path) {
+                var parent;
+                if (node.type === Syntax.FunctionDeclaration) {
+                    functionList.push({
+                        name: node.id.name,
+                        range: node.range,
+                        loc: node.loc,
+                        blockStart: node.body.range[0]
+                    });
+                } else if (node.type === Syntax.FunctionExpression) {
+                    parent = path[0];
+                    if (parent.type === Syntax.AssignmentExpression) {
+                        if (typeof parent.left.range !== 'undefined') {
+                            functionList.push({
+                                name: code.slice(parent.left.range[0],
+                                          parent.left.range[1] + 1),
+                                range: node.range,
+                                loc: node.loc,
+                                blockStart: node.body.range[0]
+                            });
+                        }
+                    } else if (parent.type === Syntax.VariableDeclarator) {
+                        functionList.push({
+                            name: parent.id.name,
+                            range: node.range,
+                            loc: node.loc,
+                            blockStart: node.body.range[0]
+                        });
+                    } else if (parent.type === Syntax.CallExpression) {
+                        functionList.push({
+                            name: parent.id ? parent.id.name : '[Anonymous]',
+                            range: node.range,
+                            loc: node.loc,
+                            blockStart: node.body.range[0]
+                        });
+                    } else if (typeof parent.length === 'number') {
+                        functionList.push({
+                            name: parent.id ? parent.id.name : '[Anonymous]',
+                            range: node.range,
+                            loc: node.loc,
+                            blockStart: node.body.range[0]
+                        });
+                    } else if (typeof parent.key !== 'undefined') {
+                        if (parent.key.type === 'Identifier') {
+                            if (parent.value === node && parent.key.name) {
+                                functionList.push({
+                                    name: parent.key.name,
+                                    range: node.range,
+                                    loc: node.loc,
+                                    blockStart: node.body.range[0]
+                                });
+                            }
+                        }
+                    }
+                }
+            });
+
+            // Insert the instrumentation code from the last entry.
+            // This is to ensure that the range for each entry remains valid)
+            // (it won't shift due to some new inserting string before the range).
+            for (i = functionList.length - 1; i >= 0; i -= 1) {
+                param = {
+                    name: functionList[i].name,
+                    range: functionList[i].range,
+                    loc: functionList[i].loc
+                };
+                if (typeof traceName === 'function') {
+                    signature = traceName.call(null, param);
+                } else {
+                    signature = traceName + '({ ';
+                    signature += 'name: \'' + functionList[i].name + '\', ';
+                    if (typeof functionList[i].loc !== 'undefined') {
+                        signature += 'lineNumber: ' + functionList[i].loc.start.line + ', ';
+                    }
+                    signature += 'range: [' + functionList[i].range[0] + ', ' +
+                        functionList[i].range[1] + '] ';
+                    signature += '});';
+                }
+                pos = functionList[i].blockStart + 1;
+                code = code.slice(0, pos) + '\n' + signature + code.slice(pos, code.length);
+            }
+
+            return code;
+        };
+    }
+
+    function modify(code, modifiers) {
+        var i;
+
+        if (Object.prototype.toString.call(modifiers) === '[object Array]') {
+            for (i = 0; i < modifiers.length; i += 1) {
+                code = modifiers[i].call(null, code);
+            }
+        } else if (typeof modifiers === 'function') {
+            code = modifiers.call(null, code);
+        } else {
+            throw new Error('Wrong use of esprima.modify() function');
+        }
+
+        return code;
+    }
+
+    // Sync with package.json.
+    exports.version = '0.9.9-dev';
+
+    exports.parse = parse;
+
+    exports.modify = modify;
+
+    exports.Tracer = {
+        FunctionEntrance: traceFunctionEntrance
+    };
+
+}(typeof exports === 'undefined' ? (esprima = {}) : exports));
+/* vim: set sw=4 ts=4 et tw=80 : */
diff --git a/assets/style.css b/assets/style.css
new file mode 100644
index 0000000..86efaf0
--- /dev/null
+++ b/assets/style.css
@@ -0,0 +1,52 @@
+* {
+  font-size 12px;
+  font-family:'Trebuchet MS', Arial, Helvetica, sans-serif;
+}
+
+pre {
+  font-family:'Bitstream Vera Sans Mono', Courier, monospace;
+  font-size: 12px;
+  background-color: #EEE;
+  padding:10px;
+  overflow: auto;
+}
+
+#console {
+  -webkit-border-radius: 5px;
+  -moz-border-radius   : 5px;
+  -o-border-radius     : 5px;
+  border-radius        : 5px;
+  border : 1px solid  #C6C6C6;
+  outline: none;
+  padding:10px;
+  display: block;
+  width  : 80%;
+  margin: 10px auto 10px auto;
+}
+
+.invalid {
+  border-color: #fbc2c4 !important;
+}
+
+#output {
+  -webkit-border-radius: 5px;
+  -moz-border-radius   : 5px;
+  -o-border-radius     : 5px;
+  border-radius        : 5px;
+  border : 1px solid  #C6C6C6;
+  width  : 80%;
+  margin : 10px auto 10px auto;
+}
+
+h1, h2, h3, h4, h5, p {
+  text-align: center;
+}
+
+p {
+  color: #849EAA;
+}
+a {
+  text-decoration: none;
+  color: #4183C4;
+}
+
diff --git a/demo/index.html b/demo/index.html
new file mode 100644
index 0000000..e25c485
--- /dev/null
+++ b/demo/index.html
@@ -0,0 +1,71 @@
+<!DOCTYPE HTML>
+<html lang="en">
+<head>
+	<meta charset="UTF-8">
+	<title>JS code generator demo: JS → AST → JS</title>
+  <link rel="stylesheet" href="../assets/style.css" type="text/css" />
+  <script src='../assets/esprima.js'></script>
+  <script src='../escodegen.js'></script>
+  <script type="text/javascript">
+function $D(elm) {
+  var range = document.createRange();
+  range.selectNodeContents(elm);
+  range.deleteContents();
+  range.detach();
+}
+function $T(mes) {
+  return document.createTextNode(mes);
+}
+function hasClass (e, name){
+  name = name.toLowerCase();
+  var cn = e.className;
+  if (!cn) return false;
+  var cnlist = cn.toLowerCase().split(/\s+/);
+  for (var i=0,l=cnlist.length;i<l;i++)
+    if(cnlist[i] == name) return true;
+  return false;
+}
+function addClass (e, name){
+  var cn = e.className || '';
+  if(hasClass(e, name)) return;
+  e.className = cn+' '+name;
+}
+function removeClass(e, name){
+  if(!hasClass(e, name)) return;
+  var cn = e.className || '';
+  name = name.toLowerCase();
+  var cnlist = cn.toLowerCase().split(/\s+/);
+  cnlist.splice(cnlist.indexOf(name), 1);
+  e.className = cnlist.join(' ');
+}
+function toggleClass(e, name){
+  (hasClass(e, name))? removeClass(e, name) : addClass(e, name);
+}
+document.addEventListener('DOMContentLoaded', function(ev) {
+  var textarea = document.getElementById("console");
+  var pre = document.getElementById("output");
+  textarea.value = "for(var i=1;i<=100;++i){if(i%15===0){console.log('FizzBuzz')}else if(i%3===0){console.log('Fizz')}else if(i%5===0){console.log('Buzz')}else{console.log(i)}}";
+  function show() {
+    $D(pre);
+    try {
+      removeClass(textarea, "invalid");
+      var AST = esprima.parse(textarea.value);
+      pre.appendChild($T(escodegen.generate(AST)));
+    } catch (e) {
+      addClass(textarea, "invalid")
+      pre.appendChild($T("Invalid"));
+    }
+  }
+  show();
+  textarea.addEventListener("input", show, false);
+}, false);
+  </script>
+</head>
+<body>
+<h1>JS code generator demo: JS → AST → JS</h1>
+<p>using <a href="http://www.esprima.org/">esprima</a> as parser</p>
+<p>and using <a href="https://github.com/Constellation/escodegen">escodegen</a> as code generator</p>
+<textarea id="console" rows="10" cols="30" placeholder="write your code"></textarea>
+<pre id="output"></pre>
+</body>
+</html>
diff --git a/escodegen.js b/escodegen.js
new file mode 100644
index 0000000..b4ea9ad
--- /dev/null
+++ b/escodegen.js
@@ -0,0 +1,843 @@
+/*
+  Copyright (C) 2012 Ariya Hidayat <ar...@gmail.com>
+  Copyright (C) 2012 Mathias Bynens <ma...@qiwi.be>
+  Copyright (C) 2012 Joost-Wim Boekesteijn <jo...@boekesteijn.nl>
+  Copyright (C) 2012 Kris Kowal <kr...@cixar.com>
+  Copyright (C) 2012 Yusuke Suzuki <ut...@gmail.com>
+  Copyright (C) 2012 Arpad Borsos <ar...@googlemail.com>
+  Copyright (C) 2011 Ariya Hidayat <ar...@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 bitwise:true */
+/*global escodegen:true, exports:true, generateStatement: true*/
+
+(function (exports) {
+    'use strict';
+
+    var Syntax,
+        Precedence,
+        BinaryPrecedence,
+        base,
+        indent,
+        extra,
+        parse;
+
+    Syntax = {
+        AssignmentExpression: 'AssignmentExpression',
+        ArrayExpression: 'ArrayExpression',
+        BlockStatement: 'BlockStatement',
+        BinaryExpression: 'BinaryExpression',
+        BreakStatement: 'BreakStatement',
+        CallExpression: 'CallExpression',
+        CatchClause: 'CatchClause',
+        ConditionalExpression: 'ConditionalExpression',
+        ContinueStatement: 'ContinueStatement',
+        DoWhileStatement: 'DoWhileStatement',
+        DebuggerStatement: 'DebuggerStatement',
+        EmptyStatement: 'EmptyStatement',
+        ExpressionStatement: 'ExpressionStatement',
+        ForStatement: 'ForStatement',
+        ForInStatement: 'ForInStatement',
+        FunctionDeclaration: 'FunctionDeclaration',
+        FunctionExpression: 'FunctionExpression',
+        Identifier: 'Identifier',
+        IfStatement: 'IfStatement',
+        Literal: 'Literal',
+        LabeledStatement: 'LabeledStatement',
+        LogicalExpression: 'LogicalExpression',
+        MemberExpression: 'MemberExpression',
+        NewExpression: 'NewExpression',
+        ObjectExpression: 'ObjectExpression',
+        Program: 'Program',
+        Property: 'Property',
+        ReturnStatement: 'ReturnStatement',
+        SequenceExpression: 'SequenceExpression',
+        SwitchStatement: 'SwitchStatement',
+        SwitchCase: 'SwitchCase',
+        ThisExpression: 'ThisExpression',
+        ThrowStatement: 'ThrowStatement',
+        TryStatement: 'TryStatement',
+        UnaryExpression: 'UnaryExpression',
+        UpdateExpression: 'UpdateExpression',
+        VariableDeclaration: 'VariableDeclaration',
+        VariableDeclarator: 'VariableDeclarator',
+        WhileStatement: 'WhileStatement',
+        WithStatement: 'WithStatement'
+    };
+
+    Precedence = {
+        Sequence: 0,
+        Assignment: 1,
+        Conditional: 2,
+        LogicalOR: 3,
+        LogicalAND: 4,
+        LogicalXOR: 5,
+        BitwiseOR: 6,
+        BitwiseAND: 7,
+        Equality: 8,
+        Relational: 9,
+        BitwiseSHIFT: 10,
+        Additive: 11,
+        Multiplicative: 12,
+        Unary: 13,
+        Postfix: 14,
+        Call: 15,
+        New: 16,
+        Member: 17,
+        Primary: 18
+    };
+
+    BinaryPrecedence = {
+        '||': Precedence.LogicalOR,
+        '&&': Precedence.LogicalAND,
+        '^': Precedence.LogicalXOR,
+        '|': Precedence.BitwiseOR,
+        '&': Precedence.BitwiseAND,
+        '==': Precedence.Equality,
+        '!=': Precedence.Equality,
+        '===': Precedence.Equality,
+        '!==': Precedence.Equality,
+        '<': Precedence.Relational,
+        '>': Precedence.Relational,
+        '<=': Precedence.Relational,
+        '>=': Precedence.Relational,
+        'in': Precedence.Relational,
+        'instanceof': Precedence.Relational,
+        '<<': Precedence.BitwiseSHIFT,
+        '>>': Precedence.BitwiseSHIFT,
+        '>>>': Precedence.BitwiseSHIFT,
+        '+': Precedence.Additive,
+        '-': Precedence.Additive,
+        '*': Precedence.Multiplicative,
+        '%': Precedence.Multiplicative,
+        '/': Precedence.Multiplicative
+    };
+
+    if (typeof Object.freeze === 'function') {
+        Object.freeze(Syntax);
+        Object.freeze(Precedence);
+        Object.freeze(BinaryPrecedence);
+    }
+
+    function unicodeEscape(ch) {
+        var result, i;
+        result = ch.charCodeAt(0).toString(16);
+        for (i = result.length; i < 4; i += 1) {
+            result = '0' + result;
+        }
+        return '\\u' + result;
+    }
+
+    function stringToArray(str) {
+        var length = str.length,
+            result = [],
+            i;
+        for (i = 0; i < length; i += 1) {
+            result[i] = str.charAt(i);
+        }
+        return result;
+    }
+
+    function escapeString(str) {
+        var result = '', i, len, ch;
+
+        if (typeof str[0] === 'undefined') {
+            str = stringToArray(str);
+        }
+
+        for (i = 0, len = str.length; i < len; i += 1) {
+            ch = str[i];
+            if ('\'\\\b\f\n\r\t'.indexOf(ch) >= 0) {
+                result += '\\';
+                switch (ch) {
+                case '\'':
+                    result += '\'';
+                    break;
+                case '\\':
+                    result += '\\';
+                    break;
+                case '\b':
+                    result += 'b';
+                    break;
+                case '\f':
+                    result += 'f';
+                    break;
+                case '\n':
+                    result += 'n';
+                    break;
+                case '\r':
+                    result += 'r';
+                    break;
+                case '\t':
+                    result += 't';
+                    break;
+                }
+            } else if (ch < ' ' || ch.charCodeAt(0) >= 0x80) {
+                result += unicodeEscape(ch);
+            } else {
+                result += ch;
+            }
+        }
+
+        return '\'' + result + '\'';
+    }
+
+    function addIndent(stmt) {
+        return base + stmt;
+    }
+
+    function parenthesize(text, current, should) {
+        return (current < should) ?  '(' + text + ')' : text;
+    }
+
+    function maybeBlock(stmt, suffix) {
+        var previousBase, result;
+
+        if (stmt.type === Syntax.BlockStatement) {
+            result = ' ' + generateStatement(stmt);
+            if (suffix) {
+                return result + ' ';
+            }
+            return result;
+        }
+
+        if (stmt.type === Syntax.EmptyStatement) {
+            result = ';';
+        } else {
+            previousBase = base;
+            base += indent;
+            result = '\n' + addIndent(generateStatement(stmt));
+            base = previousBase;
+        }
+
+        if (suffix) {
+            return result + '\n' + addIndent('');
+        }
+        return result;
+    }
+
+    function generateFunctionBody(node) {
+        var result, i, len;
+        result = '(';
+        for (i = 0, len = node.params.length; i < len; i += 1) {
+            result += node.params[i].name;
+            if ((i + 1) < len) {
+                result += ', ';
+            }
+        }
+        return result + ')' + maybeBlock(node.body);
+    }
+
+    function generateExpression(expr, precedence) {
+        var result, currentPrecedence, previousBase, i, len, raw;
+
+        if (!precedence) {
+            precedence = Precedence.Sequence;
+        }
+
+        switch (expr.type) {
+        case Syntax.SequenceExpression:
+            result = '';
+            for (i = 0, len = expr.expressions.length; i < len; i += 1) {
+                result += generateExpression(expr.expressions[i], Precedence.Assignment);
+                if ((i + 1) < len) {
+                    result += ', ';
+                }
+            }
+            result = parenthesize(result, Precedence.Sequence, precedence);
+            break;
+
+        case Syntax.AssignmentExpression:
+            result = parenthesize(
+                generateExpression(expr.left, Precedence.Call) + ' ' + expr.operator + ' ' +
+                    generateExpression(expr.right, Precedence.Assignment),
+                Precedence.Assignment,
+                precedence
+            );
+            break;
+
+        case Syntax.ConditionalExpression:
+            result = parenthesize(
+                generateExpression(expr.test, Precedence.LogicalOR) + ' ? ' +
+                    generateExpression(expr.consequent, Precedence.Assignment) + ' : ' +
+                    generateExpression(expr.alternate, Precedence.Assignment),
+                Precedence.Conditional,
+                precedence
+            );
+            break;
+
+        case Syntax.LogicalExpression:
+        case Syntax.BinaryExpression:
+            currentPrecedence = BinaryPrecedence[expr.operator];
+
+            result = generateExpression(expr.left, currentPrecedence) +
+                ' ' + expr.operator + ' ' +
+                generateExpression(expr.right, currentPrecedence + 1);
+            if (expr.operator === 'in') {
+                // TODO parenthesize only in allowIn = false case
+                result = '(' + result + ')';
+            } else {
+                result = parenthesize(result, currentPrecedence, precedence);
+            }
+            break;
+
+        case Syntax.CallExpression:
+            result = '';
+            for (i = 0, len = expr['arguments'].length; i < len; i += 1) {
+                result += generateExpression(expr['arguments'][i], Precedence.Assignment);
+                if ((i + 1) < len) {
+                    result += ', ';
+                }
+            }
+            result = parenthesize(
+                generateExpression(expr.callee, Precedence.Call) + '(' + result + ')',
+                Precedence.Call,
+                precedence
+            );
+            break;
+
+        case Syntax.NewExpression:
+            result = '';
+            for (i = 0, len = expr['arguments'].length; i < len; i += 1) {
+                result += generateExpression(expr['arguments'][i], Precedence.Assignment);
+                if ((i + 1) < len) {
+                    result += ', ';
+                }
+            }
+            result = parenthesize(
+                'new ' + generateExpression(expr.callee, Precedence.New) + '(' + result + ')',
+                Precedence.New,
+                precedence
+            );
+            break;
+
+        case Syntax.MemberExpression:
+            result = generateExpression(expr.object, Precedence.Call);
+            if (expr.computed) {
+                result += '[' + generateExpression(expr.property) + ']';
+            } else {
+                if (expr.object.type === Syntax.Literal && typeof expr.object.value === 'number') {
+                    if (result.indexOf('.') < 0) {
+                        if (!/[eExX]/.test(result) && !(result.length >= 2 && result[0] === '0')) {
+                            result += '.';
+                        }
+                    }
+                }
+                result += '.' + expr.property.name;
+            }
+            result = parenthesize(result, Precedence.Member, precedence);
+            break;
+
+        case Syntax.UnaryExpression:
+            result = expr.operator;
+            if (result.length > 2) {
+                result += ' ';
+            }
+            result = parenthesize(
+                result + generateExpression(expr.argument, Precedence.Unary +
+                    (
+                        expr.argument.type === Syntax.UnaryExpression &&
+                        expr.operator.length < 3 &&
+                        expr.argument.operator === expr.operator ? 1 : 0
+                    )
+                    ),
+                Precedence.Unary,
+                precedence
+            );
+            break;
+
+        case Syntax.UpdateExpression:
+            if (expr.prefix) {
+                result = parenthesize(
+                    expr.operator +
+                        generateExpression(expr.argument, Precedence.Unary),
+                    Precedence.Unary,
+                    precedence
+                );
+            } else {
+                result = parenthesize(
+                    generateExpression(expr.argument, Precedence.Postfix) +
+                        expr.operator,
+                    Precedence.Postfix,
+                    precedence
+                );
+            }
+            break;
+
+        case Syntax.FunctionExpression:
+            result = 'function ';
+            if (expr.id) {
+                result += expr.id.name;
+            }
+            result += generateFunctionBody(expr);
+            break;
+
+        case Syntax.ArrayExpression:
+            if (!expr.elements.length) {
+                result = '[]';
+                break;
+            }
+            result = '[\n';
+            previousBase = base;
+            base += indent;
+            for (i = 0, len = expr.elements.length; i < len; i += 1) {
+                if (!expr.elements[i]) {
+                    result += addIndent('');
+                    if ((i + 1) === len) {
+                        result += ',';
+                    }
+                } else {
+                    result += addIndent(generateExpression(expr.elements[i], Precedence.Assignment));
+                }
+                if ((i + 1) < len) {
+                    result += ',\n';
+                }
+            }
+            base = previousBase;
+            result += '\n' + addIndent(']');
+            break;
+
+        case Syntax.Property:
+            if (expr.kind === 'get' || expr.kind === 'set') {
+                result = expr.kind + ' ' + generateExpression(expr.key) +
+                    generateFunctionBody(expr.value);
+            } else {
+                result = generateExpression(expr.key) + ': ' +
+                    generateExpression(expr.value, Precedence.Assignment);
+            }
+            break;
+
+        case Syntax.ObjectExpression:
+            if (!expr.properties.length) {
+                result = '{}';
+                break;
+            }
+            result = '{\n';
+            previousBase = base;
+            base += indent;
+            for (i = 0, len = expr.properties.length; i < len; i += 1) {
+                result += addIndent(generateExpression(expr.properties[i]));
+                if ((i + 1) < len) {
+                    result += ',\n';
+                }
+            }
+            base = previousBase;
+            result += '\n' + addIndent('}');
+            break;
+
+        case Syntax.ThisExpression:
+            result = 'this';
+            break;
+
+        case Syntax.Identifier:
+            result = expr.name;
+            break;
+
+        case Syntax.Literal:
+            if (expr.hasOwnProperty('raw') && parse) {
+                try {
+                    raw = parse(expr.raw).body[0].expression;
+                    if (raw.type === Syntax.Literal) {
+                        if (raw.value === expr.value) {
+                            result = expr.raw;
+                            break;
+                        }
+                    }
+                } catch (e) {
+                    // not use raw property
+                }
+            }
+
+            if (expr.value === null) {
+                result = 'null';
+                break;
+            }
+
+            if (typeof expr.value === 'string') {
+                result = escapeString(expr.value);
+                break;
+            }
+
+            if (typeof expr.value === 'number' && expr.value === Infinity) {
+                // Infinity is variable
+                result = '1e+1000';
+                break;
+            }
+
+            result = expr.value.toString();
+            break;
+
+        default:
+            break;
+        }
+
+        if (result === undefined) {
+            throw new Error('Unknown expression type: ' + expr.type);
+        }
+        return result;
+    }
+
+    function generateStatement(stmt) {
+        var i, len, result, previousBase;
+
+        switch (stmt.type) {
+        case Syntax.BlockStatement:
+            result = '{\n';
+
+            previousBase = base;
+            base += indent;
+            for (i = 0, len = stmt.body.length; i < len; i += 1) {
+                result += addIndent(generateStatement(stmt.body[i])) + '\n';
+            }
+            base = previousBase;
+
+            result += addIndent('}');
+            break;
+
+        case Syntax.BreakStatement:
+            if (stmt.label) {
+                result = 'break ' + stmt.label.name + ';';
+            } else {
+                result = 'break;';
+            }
+            break;
+
+        case Syntax.ContinueStatement:
+            if (stmt.label) {
+                result = 'continue ' + stmt.label.name + ';';
+            } else {
+                result = 'continue;';
+            }
+            break;
+
+        case Syntax.DoWhileStatement:
+            result = 'do' + maybeBlock(stmt.body, true) + 'while (' + generateExpression(stmt.test) + ');';
+            break;
+
+        case Syntax.CatchClause:
+            previousBase = base;
+            base += indent;
+            result = ' catch (' + generateExpression(stmt.param) + ')';
+            base = previousBase;
+            result += maybeBlock(stmt.body);
+            break;
+
+        case Syntax.DebuggerStatement:
+            result = 'debugger;';
+            break;
+
+        case Syntax.EmptyStatement:
+            result = ';';
+            break;
+
+        case Syntax.ExpressionStatement:
+            result = generateExpression(stmt.expression);
+            // 12.4 '{', 'function' is not allowed in this position.
+            // wrap espression with parentheses
+            if (result[0] === '{' || result.indexOf('function ') === 0) {
+                result = '(' + result + ');';
+            } else {
+                result += ';';
+            }
+            break;
+
+        case Syntax.VariableDeclarator:
+            if (stmt.init) {
+                result = stmt.id.name + ' = ' + generateExpression(stmt.init, Precedence.Assignment);
+            } else {
+                result = stmt.id.name;
+            }
+            break;
+
+        case Syntax.VariableDeclaration:
+            result = stmt.kind + ' ';
+            // special path for
+            // var x = function () {
+            // };
+            if (stmt.declarations.length === 1 && stmt.declarations[0].init &&
+                    stmt.declarations[0].init.type === Syntax.FunctionExpression) {
+                result += generateStatement(stmt.declarations[0]);
+            } else {
+                previousBase = base;
+                base += indent;
+                for (i = 0, len = stmt.declarations.length; i < len; i += 1) {
+                    result += generateStatement(stmt.declarations[i]);
+                    if ((i + 1) < len) {
+                        result += ', ';
+                    }
+                }
+                base = previousBase;
+            }
+            result += ';';
+            break;
+
+        case Syntax.ThrowStatement:
+            result = 'throw ' + generateExpression(stmt.argument) + ';';
+            break;
+
+        case Syntax.TryStatement:
+            result = 'try' + maybeBlock(stmt.block);
+            for (i = 0, len = stmt.handlers.length; i < len; i += 1) {
+                result += generateStatement(stmt.handlers[i]);
+            }
+            if (stmt.finalizer) {
+                result += ' finally' + maybeBlock(stmt.finalizer);
+            }
+            break;
+
+        case Syntax.SwitchStatement:
+            previousBase = base;
+            base += indent;
+            result = 'switch (' + generateExpression(stmt.discriminant) + ') {\n';
+            base = previousBase;
+            if (stmt.cases) {
+                for (i = 0, len = stmt.cases.length; i < len; i += 1) {
+                    result += addIndent(generateStatement(stmt.cases[i])) + '\n';
+                }
+            }
+            result += addIndent('}');
+            break;
+
+        case Syntax.SwitchCase:
+            previousBase = base;
+            base += indent;
+            if (stmt.test) {
+                result = 'case ' + generateExpression(stmt.test) + ':';
+            } else {
+                result = 'default:';
+            }
+
+            i = 0;
+            len = stmt.consequent.length;
+            if (len && stmt.consequent[0].type === Syntax.BlockStatement) {
+                result += maybeBlock(stmt.consequent[0]);
+                i = 1;
+            }
+
+            for (; i < len; i += 1) {
+                result += '\n' + addIndent(generateStatement(stmt.consequent[i]));
+            }
+
+            base = previousBase;
+            break;
+
+        case Syntax.IfStatement:
+            if (stmt.alternate) {
+                if (stmt.alternate.type === Syntax.IfStatement) {
+                    previousBase = base;
+                    base += indent;
+                    result = 'if (' +  generateExpression(stmt.test) + ')';
+                    base = previousBase;
+                    result += maybeBlock(stmt.consequent, true) + 'else ' + generateStatement(stmt.alternate);
+                } else {
+                    previousBase = base;
+                    base += indent;
+                    result = 'if (' + generateExpression(stmt.test) + ')';
+                    base = previousBase;
+                    result += maybeBlock(stmt.consequent, true) + 'else' + maybeBlock(stmt.alternate);
+                }
+            } else {
+                previousBase = base;
+                base += indent;
+                result = 'if (' + generateExpression(stmt.test) + ')';
+                base = previousBase;
+                result += maybeBlock(stmt.consequent);
+            }
+            break;
+
+        case Syntax.ForStatement:
+            previousBase = base;
+            base += indent;
+            result = 'for (';
+            if (stmt.init) {
+                if (stmt.init.type === Syntax.VariableDeclaration) {
+                    result += generateStatement(stmt.init);
+                } else {
+                    result += generateExpression(stmt.init) + ';';
+                }
+            } else {
+                result += ';';
+            }
+
+            if (stmt.test) {
+                result += ' ' + generateExpression(stmt.test) + ';';
+            } else {
+                result += ';';
+            }
+
+            if (stmt.update) {
+                result += ' ' + generateExpression(stmt.update) + ')';
+            } else {
+                result += ')';
+            }
+            base = previousBase;
+
+            result += maybeBlock(stmt.body);
+            break;
+
+        case Syntax.ForInStatement:
+            result = 'for (';
+            if (stmt.left.type === Syntax.VariableDeclaration) {
+                previousBase = base;
+                base += indent + indent;
+                result += stmt.left.kind + ' ' + generateStatement(stmt.left.declarations[0]);
+                base = previousBase;
+            } else {
+                previousBase = base;
+                base += indent;
+                result += generateExpression(stmt.left, Precedence.Call);
+                base = previousBase;
+            }
+
+            previousBase = base;
+            base += indent;
+            result += ' in ' + generateExpression(stmt.right) + ')';
+            base = previousBase;
+            result += maybeBlock(stmt.body);
+            break;
+
+        case Syntax.LabeledStatement:
+            result = stmt.label.name + ':' + maybeBlock(stmt.body);
+            break;
+
+        case Syntax.Program:
+            result = '';
+            for (i = 0, len = stmt.body.length; i < len; i += 1) {
+                result += generateStatement(stmt.body[i]);
+                if ((i + 1) < len) {
+                    result += '\n';
+                }
+            }
+            break;
+
+        case Syntax.FunctionDeclaration:
+            result = 'function ';
+            if (stmt.id) {
+                result += stmt.id.name;
+            }
+            result += generateFunctionBody(stmt);
+            break;
+
+        case Syntax.ReturnStatement:
+            if (stmt.argument) {
+                result = 'return ' + generateExpression(stmt.argument) + ';';
+            } else {
+                result = 'return;';
+            }
+            break;
+
+        case Syntax.WhileStatement:
+            previousBase = base;
+            base += indent;
+            result = 'while (' + generateExpression(stmt.test) + ')';
+            base = previousBase;
+            result += maybeBlock(stmt.body);
+            break;
+
+        case Syntax.WithStatement:
+            previousBase = base;
+            base += indent;
+            result = 'with (' + generateExpression(stmt.object) + ')';
+            base = previousBase;
+            result += maybeBlock(stmt.body);
+            break;
+
+        default:
+            break;
+        }
+
+        if (result === undefined) {
+            throw new Error('Unknown statement type: ' + stmt.type);
+        }
+        return result;
+    }
+
+    function generate(node, options) {
+        if (typeof options !== 'undefined') {
+            base = options.base || '';
+            indent = options.indent || '    ';
+            parse = options.parse;
+        } else {
+            base = '';
+            indent = '    ';
+            parse = null;
+        }
+
+        switch (node.type) {
+        case Syntax.BlockStatement:
+        case Syntax.BreakStatement:
+        case Syntax.CatchClause:
+        case Syntax.ContinueStatement:
+        case Syntax.DoWhileStatement:
+        case Syntax.DebuggerStatement:
+        case Syntax.EmptyStatement:
+        case Syntax.ExpressionStatement:
+        case Syntax.ForStatement:
+        case Syntax.ForInStatement:
+        case Syntax.FunctionDeclaration:
+        case Syntax.IfStatement:
+        case Syntax.LabeledStatement:
+        case Syntax.Program:
+        case Syntax.ReturnStatement:
+        case Syntax.SwitchStatement:
+        case Syntax.SwitchCase:
+        case Syntax.ThrowStatement:
+        case Syntax.TryStatement:
+        case Syntax.VariableDeclaration:
+        case Syntax.VariableDeclarator:
+        case Syntax.WhileStatement:
+        case Syntax.WithStatement:
+            return generateStatement(node);
+
+        case Syntax.AssignmentExpression:
+        case Syntax.ArrayExpression:
+        case Syntax.BinaryExpression:
+        case Syntax.CallExpression:
+        case Syntax.ConditionalExpression:
+        case Syntax.FunctionExpression:
+        case Syntax.Identifier:
+        case Syntax.Literal:
+        case Syntax.LogicalExpression:
+        case Syntax.MemberExpression:
+        case Syntax.NewExpression:
+        case Syntax.ObjectExpression:
+        case Syntax.Property:
+        case Syntax.SequenceExpression:
+        case Syntax.ThisExpression:
+        case Syntax.UnaryExpression:
+        case Syntax.UpdateExpression:
+            return generateExpression(node);
+
+        default:
+            break;
+        }
+        throw new Error('Unknown node type: ' + node.type);
+    }
+
+    // Sync with package.json.
+    exports.version = '0.0.3-dev';
+
+    exports.generate = generate;
+
+}(typeof exports === 'undefined' ? (escodegen = {}) : exports));
+/* vim: set sw=4 ts=4 et tw=80 : */


[couchdb-escodegen] 05/11: script upgrade

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch gh-pages
in repository https://gitbox.apache.org/repos/asf/couchdb-escodegen.git

commit 590f4f89abadf2a3f091b9a783bbfcaf5f7baea7
Author: Constellation <ut...@gmail.com>
AuthorDate: Thu Jun 7 15:57:29 2012 +0900

    script upgrade
---
 assets/esprima.js | 1364 ++++++++++++++++++++++++++++++++++++-----------------
 escodegen.js      |  781 ++++++++++++++++++++++++++----
 2 files changed, 1636 insertions(+), 509 deletions(-)

diff --git a/assets/esprima.js b/assets/esprima.js
index 8a11eba..5fee256 100644
--- a/assets/esprima.js
+++ b/assets/esprima.js
@@ -28,14 +28,15 @@
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
-/*jslint bitwise:true */
+/*jslint bitwise:true plusplus:true */
 /*global esprima:true, exports:true,
 throwError: true, createLiteral: true, generateStatement: true,
 parseAssignmentExpression: true, parseBlock: true, parseExpression: true,
 parseFunctionDeclaration: true, parseFunctionExpression: true,
 parseFunctionSourceElements: true, parseVariableIdentifier: true,
+parseImportSpecifier: true,
 parseLeftHandSideExpression: true,
-parseStatement: true, parseSourceElement: true */
+parseStatement: true, parseSourceElement: true, parseModuleBlock: true */
 
 (function (exports) {
     'use strict';
@@ -47,19 +48,14 @@ parseStatement: true, parseSourceElement: true */
         Messages,
         Regex,
         source,
-        allowIn,
-        lastParenthesized,
         strict,
         index,
         lineNumber,
         lineStart,
         length,
         buffer,
-        extra,
-        labelSet,
-        inIteration,
-        inSwitch,
-        inFunctionBody;
+        state,
+        extra;
 
     Token = {
         BooleanLiteral: 1,
@@ -85,6 +81,7 @@ parseStatement: true, parseSourceElement: true */
     Syntax = {
         AssignmentExpression: 'AssignmentExpression',
         ArrayExpression: 'ArrayExpression',
+        ArrayPattern: 'ArrayPattern',
         BlockStatement: 'BlockStatement',
         BinaryExpression: 'BinaryExpression',
         BreakStatement: 'BreakStatement',
@@ -95,21 +92,32 @@ parseStatement: true, parseSourceElement: true */
         DoWhileStatement: 'DoWhileStatement',
         DebuggerStatement: 'DebuggerStatement',
         EmptyStatement: 'EmptyStatement',
+        ExportSpecifier: 'ExportSpecifier',
+        ExportSpecifierSet: 'ExportSpecifierSet',
+        ExportDeclaration: 'ExportDeclaration',
         ExpressionStatement: 'ExpressionStatement',
         ForStatement: 'ForStatement',
         ForInStatement: 'ForInStatement',
+        ForOfStatement: 'ForOfStatement',
         FunctionDeclaration: 'FunctionDeclaration',
         FunctionExpression: 'FunctionExpression',
+        Glob: 'Glob',
         Identifier: 'Identifier',
         IfStatement: 'IfStatement',
+        ImportDeclaration: 'ImportDeclaration',
+        ImportSpecifier: 'ImportSpecifier',
         Literal: 'Literal',
         LabeledStatement: 'LabeledStatement',
         LogicalExpression: 'LogicalExpression',
         MemberExpression: 'MemberExpression',
+        ModuleDeclaration: 'ModuleDeclaration',
         NewExpression: 'NewExpression',
         ObjectExpression: 'ObjectExpression',
+        ObjectPattern: 'ObjectPattern',
+        Path:  'Path',
         Program: 'Program',
         Property: 'Property',
+        ProtoExpression: 'ProtoExpression',
         ReturnStatement: 'ReturnStatement',
         SequenceExpression: 'SequenceExpression',
         SwitchStatement: 'SwitchStatement',
@@ -140,6 +148,7 @@ parseStatement: true, parseSourceElement: true */
         UnexpectedReserved:  'Unexpected reserved word',
         UnexpectedEOS:  'Unexpected end of input',
         NewlineAfterThrow:  'Illegal newline after throw',
+        NewlineAfterModule:  'Illegal newline after module',
         InvalidRegExp: 'Invalid regular expression',
         UnterminatedRegExp:  'Invalid regular expression: missing /',
         InvalidLHSInAssignment:  'Invalid left-hand side in assignment',
@@ -164,7 +173,8 @@ parseStatement: true, parseSourceElement: true */
         StrictLHSAssignment:  'Assignment to eval or arguments is not allowed in strict mode',
         StrictLHSPostfix:  'Postfix increment/decrement may not have eval or arguments operand in strict mode',
         StrictLHSPrefix:  'Prefix increment/decrement may not have eval or arguments operand in strict mode',
-        StrictReservedWord:  'Use of future reserved word in strict mode'
+        StrictReservedWord:  'Use of future reserved word in strict mode',
+        NoFromAfterImport: 'Missing from after import'
     };
 
     // See also tools/generate-unicode-regex.py.
@@ -173,15 +183,6 @@ parseStatement: true, parseSourceElement: true */
         NonAsciiIdentifierPart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0300-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u0483-\u0487\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u05d0-\u05ea\u05f0-\u05f2\u0610-\u061a\u0620-\u0669\u066e-\u06d3\u06d5-\u06dc\u06df-\u06e8\u06ea-\u06fc\u06ff\u0710-\u074a\u074d-\u07b1\u07c0-\u07f5\u07fa\u08 [...]
     };
 
-    if (typeof Object.freeze === 'function') {
-        Object.freeze(Token);
-        Object.freeze(TokenName);
-        Object.freeze(Syntax);
-        Object.freeze(PropertyKind);
-        Object.freeze(Messages);
-        Object.freeze(Regex);
-    }
-
     // Ensure the condition is true, otherwise throw an error.
     // This is only to have a better contract semantic, i.e. another safety net
     // to catch a logic error. The condition shall be fulfilled in normal case.
@@ -338,18 +339,18 @@ parseStatement: true, parseSourceElement: true */
             return true;
         }
 
+        // Harmony
+        if (id === 'module') {
+            return true;
+        }
+
         return isFutureReservedWord(id);
     }
 
     // Return the next character and move forward.
 
     function nextChar() {
-        var ch;
-        if (index < length) {
-            ch = source[index];
-            index += 1;
-        }
-        return ch;
+        return source[index++];
     }
 
     // 7.4 Comments
@@ -368,18 +369,18 @@ parseStatement: true, parseSourceElement: true */
                 if (isLineTerminator(ch)) {
                     lineComment = false;
                     if (ch === '\r' && source[index] === '\n') {
-                        index += 1;
+                        ++index;
                     }
-                    lineNumber += 1;
+                    ++lineNumber;
                     lineStart = index;
                 }
             } else if (blockComment) {
                 if (isLineTerminator(ch)) {
                     if (ch === '\r' && source[index + 1] === '\n') {
-                        index += 1;
+                        ++index;
                     }
-                    lineNumber += 1;
-                    index += 1;
+                    ++lineNumber;
+                    ++index;
                     lineStart = index;
                     if (index >= length) {
                         throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
@@ -392,7 +393,7 @@ parseStatement: true, parseSourceElement: true */
                     if (ch === '*') {
                         ch = source[index];
                         if (ch === '/') {
-                            index += 1;
+                            ++index;
                             blockComment = false;
                         }
                     }
@@ -412,13 +413,13 @@ parseStatement: true, parseSourceElement: true */
                     break;
                 }
             } else if (isWhiteSpace(ch)) {
-                index += 1;
+                ++index;
             } else if (isLineTerminator(ch)) {
-                index += 1;
+                ++index;
                 if (ch ===  '\r' && source[index] === '\n') {
-                    index += 1;
+                    ++index;
                 }
-                lineNumber += 1;
+                ++lineNumber;
                 lineStart = index;
             } else {
                 break;
@@ -430,7 +431,7 @@ parseStatement: true, parseSourceElement: true */
         var i, len, ch, code = 0;
 
         len = (prefix === 'u') ? 4 : 2;
-        for (i = 0; i < len; i += 1) {
+        for (i = 0; i < len; ++i) {
             if (index < length && isHexDigit(source[index])) {
                 ch = nextChar();
                 code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase());
@@ -451,11 +452,11 @@ parseStatement: true, parseSourceElement: true */
 
         start = index;
         if (ch === '\\') {
-            index += 1;
+            ++index;
             if (source[index] !== 'u') {
                 return;
             }
-            index += 1;
+            ++index;
             restore = index;
             ch = scanHexEscape('u');
             if (ch) {
@@ -477,11 +478,11 @@ parseStatement: true, parseSourceElement: true */
                 break;
             }
             if (ch === '\\') {
-                index += 1;
+                ++index;
                 if (source[index] !== 'u') {
                     return;
                 }
-                index += 1;
+                ++index;
                 restore = index;
                 ch = scanHexEscape('u');
                 if (ch) {
@@ -565,7 +566,7 @@ parseStatement: true, parseSourceElement: true */
         // Check for most common single-character punctuators.
 
         if (ch1 === ';' || ch1 === '{' || ch1 === '}') {
-            index += 1;
+            ++index;
             return {
                 type: Token.Punctuator,
                 value: ch1,
@@ -576,7 +577,7 @@ parseStatement: true, parseSourceElement: true */
         }
 
         if (ch1 === ',' || ch1 === '(' || ch1 === ')') {
-            index += 1;
+            ++index;
             return {
                 type: Token.Punctuator,
                 value: ch1,
@@ -706,9 +707,31 @@ parseStatement: true, parseSourceElement: true */
             }
         }
 
+        if (ch1 === '<' && ch2 === '|') {
+            index += 2;
+            return {
+                type: Token.Punctuator,
+                value: '<|',
+                lineNumber: lineNumber,
+                lineStart: lineStart,
+                range: [start, index]
+            };
+        }
+
+        if (ch1 === '=' && ch2 === '>') {
+            index += 2;
+            return {
+                type: Token.Punctuator,
+                value: '=>',
+                lineNumber: lineNumber,
+                lineStart: lineStart,
+                range: [start, index]
+            };
+        }
+
         // The remaining 1-character punctuators.
 
-        if ('[]<>+-*%&|^!~?:=/'.indexOf(ch1) >= 0) {
+        if ('[]<>+-*%&|^!~?:=#/'.indexOf(ch1) >= 0) {
             return {
                 type: Token.Punctuator,
                 value: nextChar(),
@@ -722,7 +745,7 @@ parseStatement: true, parseSourceElement: true */
     // 7.8.3 Numeric Literals
 
     function scanNumericLiteral() {
-        var number, start, ch;
+        var number, start, ch, octal;
 
         ch = source[index];
         assert(isDecimalDigit(ch) || (ch === '.'),
@@ -736,6 +759,8 @@ parseStatement: true, parseSourceElement: true */
 
             // Hex number starts with '0x'.
             // Octal number starts with '0'.
+            // Octal number in ES6 starts with '0o'.
+            // Binary number in ES6 starts with '0b'.
             if (number === '0') {
                 if (ch === 'x' || ch === 'X') {
                     number += nextChar();
@@ -765,8 +790,46 @@ parseStatement: true, parseSourceElement: true */
                         lineStart: lineStart,
                         range: [start, index]
                     };
-                } else if (isOctalDigit(ch)) {
-                    number += nextChar();
+                } else if (ch === 'b' || ch === 'B') {
+                    nextChar();
+                    number = '';
+
+                    while (index < length) {
+                        ch = source[index];
+                        if (ch !== '0' && ch !== '1') {
+                            break;
+                        }
+                        number += nextChar();
+                    }
+
+                    if (number.length === 0) {
+                        // only 0b or 0B
+                        throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+                    }
+
+                    if (index < length) {
+                        ch = source[index];
+                        if (isIdentifierStart(ch) || isDecimalDigit(ch)) {
+                            throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+                        }
+                    }
+                    return {
+                        type: Token.NumericLiteral,
+                        value: parseInt(number, 2),
+                        lineNumber: lineNumber,
+                        lineStart: lineStart,
+                        range: [start, index]
+                    };
+                } else if (ch === 'o' || ch === 'O' || isOctalDigit(ch)) {
+                    if (isOctalDigit(ch)) {
+                        octal = true;
+                        number = nextChar();
+                    } else {
+                        octal = false;
+                        nextChar();
+                        number = '';
+                    }
+
                     while (index < length) {
                         ch = source[index];
                         if (!isOctalDigit(ch)) {
@@ -775,16 +838,22 @@ parseStatement: true, parseSourceElement: true */
                         number += nextChar();
                     }
 
+                    if (number.length === 0) {
+                        // only 0o or 0O
+                        throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+                    }
+
                     if (index < length) {
                         ch = source[index];
                         if (isIdentifierStart(ch) || isDecimalDigit(ch)) {
                             throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
                         }
                     }
+
                     return {
                         type: Token.NumericLiteral,
                         value: parseInt(number, 8),
-                        octal: true,
+                        octal: octal,
                         lineNumber: lineNumber,
                         lineStart: lineStart,
                         range: [start, index]
@@ -870,7 +939,7 @@ parseStatement: true, parseSourceElement: true */
             'String literal must starts with a quote');
 
         start = index;
-        index += 1;
+        ++index;
 
         while (index < length) {
             ch = nextChar();
@@ -940,9 +1009,9 @@ parseStatement: true, parseSourceElement: true */
                         break;
                     }
                 } else {
-                    lineNumber += 1;
+                    ++lineNumber;
                     if (ch ===  '\r' && source[index] === '\n') {
-                        index += 1;
+                        ++index;
                     }
                 }
             } else if (isLineTerminator(ch)) {
@@ -986,15 +1055,17 @@ parseStatement: true, parseSourceElement: true */
                 }
             } else {
                 if (ch === '\\') {
-                    str += nextChar();
-                }
-                if (ch === '/') {
+                    ch = nextChar();
+                    // ECMA-262 7.8.5
+                    if (isLineTerminator(ch)) {
+                        throwError({}, Messages.UnterminatedRegExp);
+                    }
+                    str += ch;
+                } else if (ch === '/') {
                     break;
-                }
-                if (ch === '[') {
+                } else if (ch === '[') {
                     classMarker = true;
-                }
-                if (isLineTerminator(ch)) {
+                } else if (isLineTerminator(ch)) {
                     throwError({}, Messages.UnterminatedRegExp);
                 }
             }
@@ -1014,17 +1085,17 @@ parseStatement: true, parseSourceElement: true */
                 break;
             }
 
-            index += 1;
+            ++index;
             if (ch === '\\' && index < length) {
                 ch = source[index];
                 if (ch === 'u') {
-                    index += 1;
+                    ++index;
                     restore = index;
                     ch = scanHexEscape('u');
                     if (ch) {
                         flags += ch;
                         str += '\\u';
-                        for (; restore < index; restore += 1) {
+                        for (; restore < index; ++restore) {
                             str += source[restore];
                         }
                     } else {
@@ -1176,6 +1247,20 @@ parseStatement: true, parseSourceElement: true */
         throw error;
     }
 
+    function throwErrorTolerant() {
+        var error;
+        try {
+            throwError.apply(null, arguments);
+        } catch (e) {
+            if (extra.errors) {
+                extra.errors.push(e);
+            } else {
+                throw e;
+            }
+        }
+    }
+
+
     // Throw an exception because of the token.
 
     function throwUnexpected(token) {
@@ -1244,6 +1329,14 @@ parseStatement: true, parseSourceElement: true */
         return token.type === Token.Keyword && token.value === keyword;
     }
 
+
+    // Return true if the next token matches the specified contextual keyword
+
+    function matchContextualKeyword(keyword) {
+        var token = lookahead();
+        return token.type === Token.Identifier && token.value === keyword;
+    }
+
     // Return true if the next token is an assignment operator
 
     function matchAssign() {
@@ -1339,6 +1432,12 @@ parseStatement: true, parseSourceElement: true */
         };
     }
 
+    function parseSealedArrayInitialiser() {
+        var result = parseArrayInitialiser();
+        result.sealed = true;
+        return result;
+    }
+
     // 11.1.5 Object Initialiser
 
     function parsePropertyFunction(param, first) {
@@ -1359,61 +1458,85 @@ parseStatement: true, parseSourceElement: true */
         };
     }
 
+    function parsePropertyMethodFunction() {
+        var token, previousStrict, param, params, paramSet, method;
+
+        previousStrict = strict;
+        strict = true;
+        params = [];
+
+        expect('(');
+
+        if (!match(')')) {
+            paramSet = {};
+            while (index < length) {
+                token = lookahead();
+                param = parseVariableIdentifier();
+                if (isRestrictedWord(token.value)) {
+                    throwError(token, Messages.StrictParamName);
+                }
+                if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) {
+                    throwError(token, Messages.StrictParamDupe);
+                }
+                params.push(param);
+                paramSet[param.name] = true;
+                if (match(')')) {
+                    break;
+                }
+                expect(',');
+            }
+        }
+
+        expect(')');
+
+        method = parsePropertyFunction(params);
+
+        strict = previousStrict;
+
+        return method;
+    }
+
     function parseObjectPropertyKey() {
-        var token = lex(),
-            key;
+        var token = lex();
 
-        switch (token.type) {
+        // Note: This function is called only from parseObjectProperty(), where
+        // EOF and Punctuator tokens are already filtered out.
 
-        case Token.StringLiteral:
-        case Token.NumericLiteral:
+        if (token.type === Token.StringLiteral || token.type === Token.NumericLiteral) {
             if (strict && token.octal) {
                 throwError(token, Messages.StrictOctalLiteral);
             }
-            key = createLiteral(token);
-            break;
-
-        case Token.Identifier:
-        case Token.Keyword:
-        case Token.BooleanLiteral:
-        case Token.NullLiteral:
-            key = {
-                type: Syntax.Identifier,
-                name: token.value
-            };
-            break;
-
-        default:
-            // Unreachable, since parseObjectProperty() will not call this
-            // function with any other type of token.
+            return createLiteral(token);
         }
 
-        return key;
+        return {
+            type: Syntax.Identifier,
+            name: token.value
+        };
     }
 
     function parseObjectProperty() {
-        var token, property, key, id, param;
+        var token, key, id, param;
 
         token = lookahead();
 
-        switch (token.type) {
+        if (token.type === Token.Identifier) {
 
-        case Token.Identifier:
             id = parseObjectPropertyKey();
 
             // Property Assignment: Getter and Setter.
 
-            if (token.value === 'get' && !match(':')) {
+            if (token.value === 'get' && !(match(':') || match('('))) {
                 key = parseObjectPropertyKey();
                 expect('(');
                 expect(')');
-                property = {
+                return {
                     type: Syntax.Property,
                     key: key,
                     value: parsePropertyFunction([]),
                     kind: 'get'
                 };
-            } else if (token.value === 'set' && !match(':')) {
+            } else if (token.value === 'set' && !(match(':') || match('('))) {
                 key = parseObjectPropertyKey();
                 expect('(');
                 token = lookahead();
@@ -1422,43 +1545,69 @@ parseStatement: true, parseSourceElement: true */
                 }
                 param = [ parseVariableIdentifier() ];
                 expect(')');
-                property = {
+                return {
                     type: Syntax.Property,
                     key: key,
                     value: parsePropertyFunction(param, token),
                     kind: 'set'
                 };
             } else {
-                expect(':');
-                property = {
+                if (match(':')) {
+                    lex();
+                    return {
+                        type: Syntax.Property,
+                        key: id,
+                        value: parseAssignmentExpression(),
+                        kind: 'init'
+                    };
+                } else if (match('(')) {
+                    return {
+                        type: Syntax.Property,
+                        key: id,
+                        value: parsePropertyMethodFunction(),
+                        kind: 'init',
+                        method: true
+                    };
+                } else {
+                    return {
+                        type: Syntax.Property,
+                        key: id,
+                        value: id,
+                        kind: 'init',
+                        shorthand: true
+                    };
+                }
+            }
+        } else if (token.type === Token.EOF || token.type === Token.Punctuator) {
+            throwUnexpected(token);
+        } else {
+            key = parseObjectPropertyKey();
+            if (match(':')) {
+                lex();
+                return {
                     type: Syntax.Property,
-                    key: id,
+                    key: key,
                     value: parseAssignmentExpression(),
                     kind: 'init'
                 };
+            } else if (match('(')) {
+                return {
+                    type: Syntax.Property,
+                    key: key,
+                    value: parsePropertyMethodFunction(),
+                    kind: 'init',
+                    method: true
+                };
+            } else {
+                return {
+                    type: Syntax.Property,
+                    key: key,
+                    value: key,
+                    kind: 'init',
+                    shorthand: true
+                };
             }
-            break;
-
-        case Token.Keyword:
-        case Token.BooleanLiteral:
-        case Token.NullLiteral:
-        case Token.StringLiteral:
-        case Token.NumericLiteral:
-            key = parseObjectPropertyKey();
-            expect(':');
-            property = {
-                type: Syntax.Property,
-                key: key,
-                value: parseAssignmentExpression(),
-                kind: 'init'
-            };
-            break;
-
-        default:
-            throwUnexpected(token);
         }
-
-        return property;
     }
 
     function parseObjectInitialiser() {
@@ -1478,7 +1627,7 @@ parseStatement: true, parseSourceElement: true */
             if (Object.prototype.hasOwnProperty.call(map, name)) {
                 if (map[name] === PropertyKind.Data) {
                     if (strict && kind === PropertyKind.Data) {
-                        throwError({}, Messages.StrictDuplicateProperty);
+                        throwErrorTolerant({}, Messages.StrictDuplicateProperty);
                     } else if (kind !== PropertyKind.Data) {
                         throwError({}, Messages.AccessorDataProperty);
                     }
@@ -1509,6 +1658,12 @@ parseStatement: true, parseSourceElement: true */
         };
     }
 
+    function parseSealedObjectInitialiser() {
+        var result = parseObjectInitialiser();
+        result.sealed = true;
+        return result;
+    }
+
     // 11.1 Primary Expressions
 
     function parsePrimaryExpression() {
@@ -1525,7 +1680,7 @@ parseStatement: true, parseSourceElement: true */
 
         if (type === Token.StringLiteral || type === Token.NumericLiteral) {
             if (strict && token.octal) {
-                throwError(token, Messages.StrictOctalLiteral);
+                throwErrorTolerant(token, Messages.StrictOctalLiteral);
             }
             return createLiteral(lex());
         }
@@ -1565,7 +1720,7 @@ parseStatement: true, parseSourceElement: true */
 
         if (match('(')) {
             lex();
-            lastParenthesized = expr = parseExpression();
+            state.lastParenthesized = expr = parseExpression();
             expect(')');
             return expr;
         }
@@ -1574,6 +1729,17 @@ parseStatement: true, parseSourceElement: true */
             return createLiteral(scanRegExp());
         }
 
+        if (match('#')) {
+            lex();
+            if (match('[')) {
+                return parseSealedArrayInitialiser();
+            }
+
+            if (match('{')) {
+                return parseSealedObjectInitialiser();
+            }
+        }
+
         return throwUnexpected(lex());
     }
 
@@ -1662,6 +1828,57 @@ parseStatement: true, parseSourceElement: true */
         return expr;
     }
 
+    function parseTriangleLiteral() {
+        var expr,
+            token = lookahead(),
+            type = token.type;
+
+        if (type === Token.StringLiteral || type === Token.NumericLiteral) {
+            if (strict && token.octal) {
+                throwErrorTolerant(token, Messages.StrictOctalLiteral);
+            }
+            return createLiteral(lex());
+        }
+
+        if (type === Token.Keyword) {
+            if (matchKeyword('function')) {
+                return parseFunctionExpression();
+            }
+        }
+
+        if (type === Token.BooleanLiteral) {
+            lex();
+            token.value = (token.value === 'true');
+            return createLiteral(token);
+        }
+
+        if (match('[')) {
+            return parseArrayInitialiser();
+        }
+
+        if (match('{')) {
+            return parseObjectInitialiser();
+        }
+
+        if (match('/') || match('/=')) {
+            return createLiteral(scanRegExp());
+        }
+
+        // ArrowFunctionExpression
+        expr = parseExpression();
+
+        return parseArrowFunctionExpression(expr);
+    }
+
+    function parseProtoExpression(proto) {
+        expect('<|');
+        return {
+            type: Syntax.ProtoExpression,
+            proto: proto,
+            literal: parseTriangleLiteral()
+        };
+    }
+
     function parseLeftHandSideExpressionAllowCall() {
         var useNew, expr;
 
@@ -1674,6 +1891,8 @@ parseStatement: true, parseSourceElement: true */
                 expr = parseNonComputedMember(expr);
             } else if (match('[')) {
                 expr = parseComputedMember(expr);
+            } else if (match('<|')) {
+                expr = parseProtoExpression(expr);
             } else if (match('(')) {
                 expr = parseCallMember(expr);
             } else {
@@ -1696,6 +1915,8 @@ parseStatement: true, parseSourceElement: true */
                 expr = parseNonComputedMember(expr);
             } else if (match('[')) {
                 expr = parseComputedMember(expr);
+            } else if (match('<|')) {
+                expr = parseProtoExpression(expr);
             } else {
                 break;
             }
@@ -1762,7 +1983,7 @@ parseStatement: true, parseSourceElement: true */
                 argument: parseUnaryExpression()
             };
             if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) {
-                throwError({}, Messages.StrictDelete);
+                throwErrorTolerant({}, Messages.StrictDelete);
             }
             return expr;
         }
@@ -1825,10 +2046,10 @@ parseStatement: true, parseSourceElement: true */
     function parseRelationalExpression() {
         var expr, previousAllowIn;
 
-        previousAllowIn = allowIn;
-        allowIn = true;
+        previousAllowIn = state.allowIn;
+        state.allowIn = true;
         expr = parseShiftExpression();
-        allowIn = previousAllowIn;
+        state.allowIn = previousAllowIn;
 
         if (match('<') || match('>') || match('<=') || match('>=')) {
             expr = {
@@ -1837,7 +2058,7 @@ parseStatement: true, parseSourceElement: true */
                 left: expr,
                 right: parseRelationalExpression()
             };
-        } else if (allowIn && matchKeyword('in')) {
+        } else if (state.allowIn && matchKeyword('in')) {
             lex();
             expr = {
                 type: Syntax.BinaryExpression,
@@ -1863,7 +2084,7 @@ parseStatement: true, parseSourceElement: true */
     function parseEqualityExpression() {
         var expr = parseRelationalExpression();
 
-        while (match('==') || match('!=') || match('===') || match('!==')) {
+        while ((!peekLineTerminator() && (matchContextualKeyword('is') || matchContextualKeyword('isnt'))) || match('==') || match('!=') || match('===') || match('!==')) {
             expr = {
                 type: Syntax.BinaryExpression,
                 operator: lex().value,
@@ -1968,10 +2189,10 @@ parseStatement: true, parseSourceElement: true */
 
         if (match('?')) {
             lex();
-            previousAllowIn = allowIn;
-            allowIn = true;
+            previousAllowIn = state.allowIn;
+            state.allowIn = true;
             consequent = parseAssignmentExpression();
-            allowIn = previousAllowIn;
+            state.allowIn = previousAllowIn;
             expect(':');
 
             expr = {
@@ -1987,6 +2208,81 @@ parseStatement: true, parseSourceElement: true */
 
     // 11.13 Assignment Operators
 
+    function reinterpretAsAssignmentBindingPattern(expr) {
+        var i, len, property, element;
+
+        if (expr.sealed) {
+            throwError({}, Messages.InvalidLHSInAssignment);
+        }
+
+        if (expr.type === Syntax.ObjectExpression) {
+            expr.type = Syntax.ObjectPattern;
+            for (i = 0, len = expr.properties.length; i < len; i += 1) {
+                property = expr.properties[i];
+                if (property.kind !== 'init') {
+                    throwError({}, Messages.InvalidLHSInAssignment);
+                }
+                reinterpretAsAssignmentBindingPattern(property.value);
+            }
+        } else if (expr.type === Syntax.ArrayExpression) {
+            expr.type = Syntax.ArrayPattern;
+            for (i = 0, len = expr.elements.length; i < len; i += 1) {
+                element = expr.elements[i];
+                if (element) {
+                    reinterpretAsAssignmentBindingPattern(element);
+                }
+            }
+        } else if (expr.type === Syntax.Identifier) {
+            if (isRestrictedWord(expr.name)) {
+                throwError({}, Messages.InvalidLHSInAssignment);
+            }
+        } else {
+            if (expr.type !== Syntax.MemberExpression && expr.type !== Syntax.CallExpression && expr.type !== Syntax.NewExpression) {
+                throwError({}, Messages.InvalidLHSInAssignment);
+            }
+        }
+    }
+
+    function reinterpretAsCoverFormalsList(expr) {
+        if (state.lastParenthesized !== expr) {
+            if (expr.type === Syntax.Identifier) {
+                // e => ConciseBody style
+                return [ expr ];
+            }
+            throwError({}, Messages.InvalidCoverFormalsList);
+        }
+
+        if (expr.type === Syntax.Identifier) {
+            // (e) => ConciseBody style
+            return [ expr ];
+        }
+
+        if (expr.type !== Syntax.SequenceExpression) {
+            throwError({}, Messages.InvalidCoverFormalsList);
+        }
+
+        return expr;
+    }
+
+    function parseArrowFunctionExpression(expr) {
+        var params, previousStrict;
+
+        params = reinterpretAsCoverFormalsList(expr);
+
+        expect('=>');
+
+        previousStrict = strict;
+        strict = true;
+        expr = {
+            type: Syntax.ArrowFunctionExpression,
+            params: params,
+            body: parseConciseBody()
+        };
+        strict = previousStrict;
+
+        return expr;
+    }
+
     function parseAssignmentExpression() {
         var expr;
 
@@ -1994,7 +2290,7 @@ parseStatement: true, parseSourceElement: true */
 
         if (matchAssign()) {
             // LeftHandSideExpression
-            if (lastParenthesized !== expr && !isLeftHandSide(expr)) {
+            if (state.lastParenthesized !== expr && !isLeftHandSide(expr)) {
                 throwError({}, Messages.InvalidLHSInAssignment);
             }
 
@@ -2003,12 +2299,20 @@ parseStatement: true, parseSourceElement: true */
                 throwError({}, Messages.StrictLHSAssignment);
             }
 
+            // ES.next draf 11.13 Runtime Semantics step 1
+            if (expr.type === Syntax.ObjectExpression || expr.type === Syntax.ArrayExpression) {
+                reinterpretAsAssignmentBindingPattern(expr);
+            }
+
             expr = {
                 type: Syntax.AssignmentExpression,
                 operator: lex().value,
                 left: expr,
                 right: parseAssignmentExpression()
             };
+        } else if (match('=>')) {
+            lex();
+            return parseArrowFunctionExpression(expr);
         }
 
         return expr;
@@ -2093,7 +2397,7 @@ parseStatement: true, parseSourceElement: true */
 
         // 12.2.1
         if (strict && isRestrictedWord(id.name)) {
-            throwError({}, Messages.StrictVarName);
+            throwErrorTolerant({}, Messages.StrictVarName);
         }
 
         if (kind === 'const') {
@@ -2161,17 +2465,255 @@ parseStatement: true, parseSourceElement: true */
         };
     }
 
-    // 12.3 Empty Statement
+    // http://wiki.ecmascript.org/doku.php?id=harmony:modules
 
-    function parseEmptyStatement() {
-        expect(';');
+    function parsePath() {
+        var result, id;
 
-        return {
-            type: Syntax.EmptyStatement
+        result = {
+            type: Syntax.Path,
+            body: []
         };
-    }
 
-    // 12.4 Expression Statement
+        while (true) {
+            id = parseVariableIdentifier();
+            result.body.push(id);
+            if (!match('.')) {
+                break;
+            }
+            lex();
+        }
+
+        return result;
+    }
+
+    function parseGlob() {
+        expect('*');
+        return {
+            type: Syntax.Glob
+        };
+    }
+
+    function parseModuleDeclaration() {
+        var id, token, declaration;
+
+        expectKeyword('module');
+
+        if (peekLineTerminator()) {
+            throwError({}, Messages.NewlineAfterModule);
+        }
+
+        id = parseVariableIdentifier();
+
+        if (match('{')) {
+            return {
+                type: Syntax.ModuleDeclaration,
+                id: id,
+                body: parseModuleBlock()
+            };
+        }
+
+        expect('=');
+
+        token = lookahead();
+        if (token.type === Token.StringLiteral) {
+            declaration = {
+                type: Syntax.ModuleDeclaration,
+                id: id,
+                from: parsePrimaryExpression()
+            };
+        } else {
+            declaration = {
+                type: Syntax.ModuleDeclaration,
+                id: id,
+                from: parsePath()
+            };
+        }
+
+        consumeSemicolon();
+
+        return declaration;
+    }
+
+    function parseExportSpecifierSetProperty() {
+        var specifier;
+
+        specifier = {
+            type: Syntax.ExportSpecifier,
+            id: parseVariableIdentifier(),
+            from: null
+        };
+
+        if (match(':')) {
+            lex();
+            specifier.from = parsePath();
+        }
+
+        return specifier;
+    }
+
+    function parseExportSpecifier() {
+        var specifier, specifiers;
+
+        if (match('{')) {
+            lex();
+            specifiers = [];
+
+            do {
+                specifiers.push(parseExportSpecifierSetProperty());
+            } while (match(',') && lex());
+
+            expect('}');
+
+            return {
+                type: Syntax.ExportSpecifierSet,
+                specifiers: specifiers
+            };
+        }
+
+        if (match('*')) {
+            specifier = {
+                type: Syntax.ExportSpecifier,
+                id: parseGlob(),
+                from: null
+            };
+
+            if (matchContextualKeyword('from')) {
+                lex();
+                specifier.from = parsePath();
+            }
+        } else {
+            specifier = {
+                type: Syntax.ExportSpecifier,
+                id: parseVariableIdentifier(),
+                from: null
+            };
+        }
+        return specifier;
+    }
+
+    function parseExportDeclaration() {
+        var id, token, declaration, specifiers;
+
+        expectKeyword('export');
+
+        token = lookahead();
+
+        if (token.type === Token.Keyword) {
+            switch (token.value) {
+            case 'function':
+                return {
+                    type: Syntax.ExportDeclaration,
+                    declaration: parseFunctionDeclaration()
+                };
+            case 'module':
+                return {
+                    type: Syntax.ExportDeclaration,
+                    declaration: parseModuleDeclaration()
+                };
+            case 'let':
+            case 'const':
+                return {
+                    type: Syntax.ExportDeclaration,
+                    declaration: parseConstLetDeclaration(token.value)
+                };
+            case 'var':
+                return {
+                    type: Syntax.ExportDeclaration,
+                    declaration: parseStatement()
+                };
+            }
+            throwUnexpected(lex());
+        }
+
+        specifiers = [ parseExportSpecifier() ];
+        if (match(',')) {
+            while (index < length) {
+                if (!match(',')) {
+                    break;
+                }
+                lex();
+                specifiers.push(parseExportSpecifier());
+            }
+        }
+
+        consumeSemicolon();
+
+        return {
+            type: Syntax.ExportDeclaration,
+            specifiers: specifiers
+        };
+    }
+
+    function parseImportDeclaration() {
+        var specifiers, from;
+
+        expectKeyword('import');
+
+        if (match('*')) {
+            specifiers = [parseGlob()];
+        } else if (match('{')) {
+            lex();
+            specifiers = [];
+
+            do {
+                specifiers.push(parseImportSpecifier());
+            } while (match(',') && lex());
+
+            expect('}');
+        } else {
+            specifiers = [parseVariableIdentifier()];
+        }
+
+        if (!matchContextualKeyword('from')) {
+            throwError({}, Messages.NoFromAfterImport);
+        }
+
+        lex();
+
+        if (lookahead().type === Token.StringLiteral) {
+            from = parsePrimaryExpression();
+        } else {
+            from = parsePath();
+        }
+
+        consumeSemicolon();
+
+        return {
+            type: Syntax.ImportDeclaration,
+            specifiers: specifiers,
+            from: from
+        };
+    }
+
+    function parseImportSpecifier() {
+        var specifier;
+
+        specifier = {
+            type: Syntax.ImportSpecifier,
+            id: parseVariableIdentifier(),
+            from: null
+        };
+
+        if (match(':')) {
+            lex();
+            specifier.from = parsePath();
+        }
+
+        return specifier;
+    }
+
+    // 12.3 Empty Statement
+
+    function parseEmptyStatement() {
+        expect(';');
+
+        return {
+            type: Syntax.EmptyStatement
+        };
+    }
+
+    // 12.4 Expression Statement
 
     function parseExpressionStatement() {
         var expr = parseExpression();
@@ -2221,12 +2763,12 @@ parseStatement: true, parseSourceElement: true */
 
         expectKeyword('do');
 
-        oldInIteration = inIteration;
-        inIteration = true;
+        oldInIteration = state.inIteration;
+        state.inIteration = true;
 
         body = parseStatement();
 
-        inIteration = oldInIteration;
+        state.inIteration = oldInIteration;
 
         expectKeyword('while');
 
@@ -2258,12 +2800,12 @@ parseStatement: true, parseSourceElement: true */
 
         expect(')');
 
-        oldInIteration = inIteration;
-        inIteration = true;
+        oldInIteration = state.inIteration;
+        state.inIteration = true;
 
         body = parseStatement();
 
-        inIteration = oldInIteration;
+        state.inIteration = oldInIteration;
 
         return {
             type: Syntax.WhileStatement,
@@ -2283,7 +2825,7 @@ parseStatement: true, parseSourceElement: true */
     }
 
     function parseForStatement() {
-        var init, test, update, left, right, body, oldInIteration;
+        var init, test, update, left, right, body, operator, oldInIteration, i, len;
 
         init = test = update = null;
 
@@ -2294,28 +2836,38 @@ parseStatement: true, parseSourceElement: true */
         if (match(';')) {
             lex();
         } else {
-            if (matchKeyword('var') || matchKeyword('let')) {
-                allowIn = false;
+            if (matchKeyword('var') || matchKeyword('let') || matchKeyword('const')) {
+                state.allowIn = false;
                 init = parseForVariableDeclaration();
-                allowIn = true;
-
-                if (init.declarations.length === 1 && matchKeyword('in')) {
-                    lex();
-                    left = init;
-                    right = parseExpression();
-                    init = null;
+                state.allowIn = true;
+
+                if (init.declarations.length === 1) {
+                    if (matchKeyword('in') || matchContextualKeyword('of')) {
+                        operator = lookahead();
+                        if (!((operator.value === 'in' || init.kind !== 'var') && init.declarations[0].init)) {
+                            lex();
+                            left = init;
+                            right = parseExpression();
+                            init = null;
+                        }
+                    }
                 }
             } else {
-                allowIn = false;
+                state.allowIn = false;
                 init = parseExpression();
-                allowIn = true;
+                state.allowIn = true;
 
-                if (matchKeyword('in')) {
+                if (matchContextualKeyword('of')) {
+                    operator = lex();
+                    left = init;
+                    right = parseExpression();
+                    init = null;
+                } else if (matchKeyword('in')) {
                     // LeftHandSideExpression
-                    if (matchKeyword('in') && (lastParenthesized !== init && !isLeftHandSide(init))) {
+                    if (matchKeyword('in') && (state.lastParenthesized !== init && !isLeftHandSide(init))) {
                         throwError({}, Messages.InvalidLHSInForIn);
                     }
-                    lex();
+                    operator = lex();
                     left = init;
                     right = parseExpression();
                     init = null;
@@ -2341,12 +2893,12 @@ parseStatement: true, parseSourceElement: true */
 
         expect(')');
 
-        oldInIteration = inIteration;
-        inIteration = true;
+        oldInIteration = state.inIteration;
+        state.inIteration = true;
 
         body = parseStatement();
 
-        inIteration = oldInIteration;
+        state.inIteration = oldInIteration;
 
         if (typeof left === 'undefined') {
             return {
@@ -2358,13 +2910,23 @@ parseStatement: true, parseSourceElement: true */
             };
         }
 
-        return {
-            type: Syntax.ForInStatement,
-            left: left,
-            right: right,
-            body: body,
-            each: false
-        };
+        if (operator.value === 'in') {
+            return {
+                type: Syntax.ForInStatement,
+                left: left,
+                right: right,
+                body: body,
+                each: false
+            };
+        } else {
+            return {
+                type: Syntax.ForOfStatement,
+                left: left,
+                right: right,
+                body: body,
+                each: false
+            };
+        }
     }
 
     // 12.7 The continue statement
@@ -2377,8 +2939,8 @@ parseStatement: true, parseSourceElement: true */
         // Optimize the most common form: 'continue;'.
         if (source[index] === ';') {
             lex();
-            
-            if (!inIteration) {
+
+            if (!state.inIteration) {
                 throwError({}, Messages.IllegalContinue);
             }
 
@@ -2389,7 +2951,7 @@ parseStatement: true, parseSourceElement: true */
         }
 
         if (peekLineTerminator()) {
-            if (!inIteration) {
+            if (!state.inIteration) {
                 throwError({}, Messages.IllegalContinue);
             }
 
@@ -2403,14 +2965,14 @@ parseStatement: true, parseSourceElement: true */
         if (token.type === Token.Identifier) {
             label = parseVariableIdentifier();
 
-            if (!Object.prototype.hasOwnProperty.call(labelSet, label.name)) {
+            if (!Object.prototype.hasOwnProperty.call(state.labelSet, label.name)) {
                 throwError({}, Messages.UnknownLabel, label.name);
             }
         }
 
         consumeSemicolon();
 
-        if (label === null && !inIteration) {
+        if (label === null && !state.inIteration) {
             throwError({}, Messages.IllegalContinue);
         }
 
@@ -2430,8 +2992,8 @@ parseStatement: true, parseSourceElement: true */
         // Optimize the most common form: 'break;'.
         if (source[index] === ';') {
             lex();
-            
-            if (!(inIteration || inSwitch)) {
+
+            if (!(state.inIteration || state.inSwitch)) {
                 throwError({}, Messages.IllegalBreak);
             }
 
@@ -2442,7 +3004,7 @@ parseStatement: true, parseSourceElement: true */
         }
 
         if (peekLineTerminator()) {
-            if (!(inIteration || inSwitch)) {
+            if (!(state.inIteration || state.inSwitch)) {
                 throwError({}, Messages.IllegalBreak);
             }
 
@@ -2456,14 +3018,14 @@ parseStatement: true, parseSourceElement: true */
         if (token.type === Token.Identifier) {
             label = parseVariableIdentifier();
 
-            if (!Object.prototype.hasOwnProperty.call(labelSet, label.name)) {
+            if (!Object.prototype.hasOwnProperty.call(state.labelSet, label.name)) {
                 throwError({}, Messages.UnknownLabel, label.name);
             }
         }
 
         consumeSemicolon();
 
-        if (label === null && !(inIteration || inSwitch)) {
+        if (label === null && !(state.inIteration || state.inSwitch)) {
             throwError({}, Messages.IllegalBreak);
         }
 
@@ -2480,8 +3042,8 @@ parseStatement: true, parseSourceElement: true */
 
         expectKeyword('return');
 
-        if (!inFunctionBody) {
-            throwError({}, Messages.IllegalReturn);
+        if (!state.inFunctionBody) {
+            throwErrorTolerant({}, Messages.IllegalReturn);
         }
 
         // 'return' followed by a space and an identifier is very common.
@@ -2524,7 +3086,7 @@ parseStatement: true, parseSourceElement: true */
         var object, body;
 
         if (strict) {
-            throwError({}, Messages.StrictModeWith);
+            throwErrorTolerant({}, Messages.StrictModeWith);
         }
 
         expectKeyword('with');
@@ -2546,10 +3108,20 @@ parseStatement: true, parseSourceElement: true */
 
     // 12.10 The swith statement
 
-    function parseSwitchCase(test) {
-        var consequent = [],
+    function parseSwitchCase() {
+        var test,
+            consequent = [],
             statement;
 
+        if (matchKeyword('default')) {
+            lex();
+            test = null;
+        } else {
+            expectKeyword('case');
+            test = parseExpression();
+        }
+        expect(':');
+
         while (index < length) {
             if (match('}') || matchKeyword('default') || matchKeyword('case')) {
                 break;
@@ -2569,7 +3141,7 @@ parseStatement: true, parseSourceElement: true */
     }
 
     function parseSwitchStatement() {
-        var discriminant, cases, test, oldInSwitch;
+        var discriminant, cases, oldInSwitch;
 
         expectKeyword('switch');
 
@@ -2591,27 +3163,17 @@ parseStatement: true, parseSourceElement: true */
 
         cases = [];
 
-        oldInSwitch = inSwitch;
-        inSwitch = true;
+        oldInSwitch = state.inSwitch;
+        state.inSwitch = true;
 
         while (index < length) {
             if (match('}')) {
                 break;
             }
-
-            if (matchKeyword('default')) {
-                lex();
-                test = null;
-            } else {
-                expectKeyword('case');
-                test = parseExpression();
-            }
-            expect(':');
-
-            cases.push(parseSwitchCase(test));
+            cases.push(parseSwitchCase());
         }
 
-        inSwitch = oldInSwitch;
+        state.inSwitch = oldInSwitch;
 
         expect('}');
 
@@ -2655,7 +3217,7 @@ parseStatement: true, parseSourceElement: true */
             param = parseExpression();
             // 12.14.1
             if (strict && param.type === Syntax.Identifier && isRestrictedWord(param.name)) {
-                throwError({}, Messages.StrictCatchVariable);
+                throwErrorTolerant({}, Messages.StrictCatchVariable);
             }
         }
         expect(')');
@@ -2773,13 +3335,13 @@ parseStatement: true, parseSourceElement: true */
         if ((expr.type === Syntax.Identifier) && match(':')) {
             lex();
 
-            if (Object.prototype.hasOwnProperty.call(labelSet, expr.name)) {
+            if (Object.prototype.hasOwnProperty.call(state.labelSet, expr.name)) {
                 throwError({}, Messages.Redeclaration, 'Label', expr.name);
             }
 
-            labelSet[expr.name] = true;
+            state.labelSet[expr.name] = true;
             labeledBody = parseStatement();
-            delete labelSet[expr.name];
+            delete state.labelSet[expr.name];
 
             return {
                 type: Syntax.LabeledStatement,
@@ -2799,7 +3361,8 @@ parseStatement: true, parseSourceElement: true */
     // 13 Function Definition
 
     function parseFunctionSourceElements() {
-        var sourceElement, sourceElements = [], token, directive, firstRestricted, oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody;
+        var sourceElement, sourceElements = [], token, directive, firstRestricted,
+            oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody;
 
         expect('{');
 
@@ -2828,15 +3391,15 @@ parseStatement: true, parseSourceElement: true */
             }
         }
 
-        oldLabelSet = labelSet;
-        oldInIteration = inIteration;
-        oldInSwitch = inSwitch;
-        oldInFunctionBody = inFunctionBody;
+        oldLabelSet = state.labelSet;
+        oldInIteration = state.inIteration;
+        oldInSwitch = state.inSwitch;
+        oldInFunctionBody = state.inFunctionBody;
 
-        labelSet = {};
-        inIteration = false;
-        inSwitch = false;
-        inFunctionBody = true;
+        state.labelSet = {};
+        state.inIteration = false;
+        state.inSwitch = false;
+        state.inFunctionBody = true;
 
         while (index < length) {
             if (match('}')) {
@@ -2851,10 +3414,10 @@ parseStatement: true, parseSourceElement: true */
 
         expect('}');
 
-        labelSet = oldLabelSet;
-        inIteration = oldInIteration;
-        inSwitch = oldInSwitch;
-        inFunctionBody = oldInFunctionBody;
+        state.labelSet = oldLabelSet;
+        state.inIteration = oldInIteration;
+        state.inSwitch = oldInSwitch;
+        state.inFunctionBody = oldInFunctionBody;
 
         return {
             type: Syntax.BlockStatement,
@@ -3031,7 +3594,24 @@ parseStatement: true, parseSourceElement: true */
         }
     }
 
-    function parseSourceElements() {
+    function parseProgramElement() {
+        var token = lookahead();
+
+        if (token.type === Token.Keyword) {
+            switch (token.value) {
+            case 'module':
+                return parseModuleDeclaration(token.value);
+            case 'export':
+                return parseExportDeclaration();
+            case 'import':
+                return parseImportDeclaration();
+            }
+        }
+
+        return parseSourceElement();
+    }
+
+    function parseProgramElements() {
         var sourceElement, sourceElements = [], token, directive, firstRestricted;
 
         while (index < length) {
@@ -3040,7 +3620,7 @@ parseStatement: true, parseSourceElement: true */
                 break;
             }
 
-            sourceElement = parseSourceElement();
+            sourceElement = parseProgramElement();
             sourceElements.push(sourceElement);
             if (sourceElement.expression.type !== Syntax.Literal) {
                 // this is not directive
@@ -3060,7 +3640,7 @@ parseStatement: true, parseSourceElement: true */
         }
 
         while (index < length) {
-            sourceElement = parseSourceElement();
+            sourceElement = parseProgramElement();
             if (typeof sourceElement === 'undefined') {
                 break;
             }
@@ -3069,12 +3649,49 @@ parseStatement: true, parseSourceElement: true */
         return sourceElements;
     }
 
+    function parseModuleElement() {
+        return parseProgramElement();
+    }
+
+    function parseModuleElements() {
+        var list = [],
+            statement;
+
+        while (index < length) {
+            if (match('}')) {
+                break;
+            }
+            statement = parseModuleElement();
+            if (typeof statement === 'undefined') {
+                break;
+            }
+            list.push(statement);
+        }
+
+        return list;
+    }
+
+    function parseModuleBlock() {
+        var block;
+
+        expect('{');
+
+        block = parseModuleElements();
+
+        expect('}');
+
+        return {
+            type: Syntax.BlockStatement,
+            body: block
+        };
+    }
+
     function parseProgram() {
         var program;
         strict = false;
         program = {
             type: Syntax.Program,
-            body: parseSourceElements()
+            body: parseProgramElements()
         };
         return program;
     }
@@ -3083,9 +3700,7 @@ parseStatement: true, parseSourceElement: true */
     // the comments is active.
 
     function addComment(start, end, type, value) {
-        if (typeof start !== 'number') {
-            return;
-        }
+        assert(typeof start === 'number', 'Comment must have valid position');
 
         // Because the way the actual token is scanned, often the comments
         // (if any) are skipped twice during the lexical analysis.
@@ -3116,13 +3731,17 @@ parseStatement: true, parseSourceElement: true */
 
             if (lineComment) {
                 ch = nextChar();
-                if (isLineTerminator(ch)) {
+                if (index >= length) {
+                    lineComment = false;
+                    comment += ch;
+                    addComment(start, index, 'Line', comment);
+                } else if (isLineTerminator(ch)) {
                     lineComment = false;
-                    addComment(start, index - 1, 'Line', comment);
+                    addComment(start, index, 'Line', comment);
                     if (ch === '\r' && source[index] === '\n') {
-                        index += 1;
+                        ++index;
                     }
-                    lineNumber += 1;
+                    ++lineNumber;
                     lineStart = index;
                     comment = '';
                 } else {
@@ -3131,10 +3750,13 @@ parseStatement: true, parseSourceElement: true */
             } else if (blockComment) {
                 if (isLineTerminator(ch)) {
                     if (ch === '\r' && source[index + 1] === '\n') {
-                        index += 1;
+                        ++index;
+                        comment += '\r\n';
+                    } else {
+                        comment += ch;
                     }
-                    lineNumber += 1;
-                    index += 1;
+                    ++lineNumber;
+                    ++index;
                     lineStart = index;
                     if (index >= length) {
                         throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
@@ -3150,8 +3772,8 @@ parseStatement: true, parseSourceElement: true */
                         if (ch === '/') {
                             comment = comment.substr(0, comment.length - 1);
                             blockComment = false;
-                            index += 1;
-                            addComment(start, index - 1, 'Block', comment);
+                            ++index;
+                            addComment(start, index, 'Block', comment);
                             comment = '';
                         }
                     }
@@ -3173,20 +3795,18 @@ parseStatement: true, parseSourceElement: true */
                     break;
                 }
             } else if (isWhiteSpace(ch)) {
-                index += 1;
+                ++index;
             } else if (isLineTerminator(ch)) {
-                index += 1;
+                ++index;
                 if (ch ===  '\r' && source[index] === '\n') {
-                    index += 1;
+                    ++index;
                 }
-                lineNumber += 1;
+                ++lineNumber;
                 lineStart = index;
             } else {
                 break;
             }
         }
-
-        addComment(start, index, (blockComment) ? 'Block' : 'Line', comment);
     }
 
     function collectToken() {
@@ -3195,7 +3815,7 @@ parseStatement: true, parseSourceElement: true */
             value;
 
         if (token.type !== Token.EOF) {
-            range = [token.range[0], token.range[1] - 1];
+            range = [token.range[0], token.range[1]];
             value = sliceSource(token.range[0], token.range[1]);
             extra.tokens.push({
                 type: TokenName[token.type],
@@ -3228,7 +3848,7 @@ parseStatement: true, parseSourceElement: true */
         extra.tokens.push({
             type: 'RegularExpression',
             value: regex.literal,
-            range: [pos, index - 1]
+            range: [pos, index]
         });
 
         return regex;
@@ -3259,34 +3879,21 @@ parseStatement: true, parseSourceElement: true */
             }
 
             function visit(node) {
-                if (range) {
-                    if (isBinary(node.left) && (typeof node.left.range === 'undefined')) {
-                        visit(node.left);
-                    }
-                    if (isBinary(node.right) && (typeof node.right.range === 'undefined')) {
-                        visit(node.right);
-                    }
-
-                    // Expression enclosed in brackets () already has the correct range.
-                    if (typeof node.range === 'undefined') {
-                        node.range = [node.left.range[0], node.right.range[1]];
-                    }
+                if (isBinary(node.left)) {
+                    visit(node.left);
+                }
+                if (isBinary(node.right)) {
+                    visit(node.right);
                 }
 
-                if (loc) {
-                    if (isBinary(node.left) && (typeof node.left.loc === 'undefined')) {
-                        visit(node.left);
-                    }
-                    if (isBinary(node.right) && (typeof node.right.loc === 'undefined')) {
-                        visit(node.right);
-                    }
-
-                    if (typeof node.loc === 'undefined') {
-                        node.loc = {
-                            start: node.left.loc.start,
-                            end: node.right.loc.end
-                        };
-                    }
+                if (range && typeof node.range === 'undefined') {
+                    node.range = [node.left.range[0], node.right.range[1]];
+                }
+                if (loc && typeof node.loc === 'undefined') {
+                    node.loc = {
+                        start: node.left.loc.start,
+                        end: node.right.loc.end
+                    };
                 }
             }
 
@@ -3306,7 +3913,7 @@ parseStatement: true, parseSourceElement: true */
                 if (typeof node !== 'undefined') {
 
                     if (range) {
-                        rangeInfo[1] = index - 1;
+                        rangeInfo[1] = index;
                         node.range = rangeInfo;
                     }
 
@@ -3368,26 +3975,37 @@ parseStatement: true, parseSourceElement: true */
             extra.parseConditionalExpression = parseConditionalExpression;
             extra.parseConstLetDeclaration = parseConstLetDeclaration;
             extra.parseEqualityExpression = parseEqualityExpression;
+            extra.parseExportDeclaration = parseExportDeclaration;
+            extra.parseExportSpecifier = parseExportSpecifier;
+            extra.parseExportSpecifierSetProperty = parseExportSpecifierSetProperty;
             extra.parseExpression = parseExpression;
             extra.parseForVariableDeclaration = parseForVariableDeclaration;
             extra.parseFunctionDeclaration = parseFunctionDeclaration;
             extra.parseFunctionExpression = parseFunctionExpression;
+            extra.parseGlob = parseGlob;
+            extra.parseImportDeclaration = parseImportDeclaration;
+            extra.parseImportSpecifier = parseImportSpecifier;
             extra.parseLogicalANDExpression = parseLogicalANDExpression;
             extra.parseLogicalORExpression = parseLogicalORExpression;
             extra.parseMultiplicativeExpression = parseMultiplicativeExpression;
+            extra.parseModuleDeclaration = parseModuleDeclaration;
+            extra.parseModuleBlock = parseModuleBlock;
             extra.parseNewExpression = parseNewExpression;
             extra.parseNonComputedMember = parseNonComputedMember;
             extra.parseNonComputedProperty = parseNonComputedProperty;
             extra.parseObjectProperty = parseObjectProperty;
             extra.parseObjectPropertyKey = parseObjectPropertyKey;
+            extra.parsePath = parsePath;
             extra.parsePostfixExpression = parsePostfixExpression;
             extra.parsePrimaryExpression = parsePrimaryExpression;
             extra.parseProgram = parseProgram;
             extra.parsePropertyFunction = parsePropertyFunction;
+            extra.parseProtoExpression = parseProtoExpression;
             extra.parseRelationalExpression = parseRelationalExpression;
             extra.parseStatement = parseStatement;
             extra.parseShiftExpression = parseShiftExpression;
             extra.parseSwitchCase = parseSwitchCase;
+            extra.parseTriangleLiteral = parseTriangleLiteral;
             extra.parseUnaryExpression = parseUnaryExpression;
             extra.parseVariableDeclaration = parseVariableDeclaration;
             extra.parseVariableIdentifier = parseVariableIdentifier;
@@ -3404,27 +4022,38 @@ parseStatement: true, parseSourceElement: true */
             parseComputedMember = wrapTracking(extra.parseComputedMember);
             parseConditionalExpression = wrapTracking(extra.parseConditionalExpression);
             parseConstLetDeclaration = wrapTracking(extra.parseConstLetDeclaration);
+            parseExportDeclaration = wrapTracking(parseExportDeclaration);
+            parseExportSpecifier = wrapTracking(parseExportSpecifier);
+            parseExportSpecifierSetProperty = wrapTracking(parseExportSpecifierSetProperty);
             parseEqualityExpression = wrapTracking(extra.parseEqualityExpression);
             parseExpression = wrapTracking(extra.parseExpression);
             parseForVariableDeclaration = wrapTracking(extra.parseForVariableDeclaration);
             parseFunctionDeclaration = wrapTracking(extra.parseFunctionDeclaration);
             parseFunctionExpression = wrapTracking(extra.parseFunctionExpression);
+            parseGlob = wrapTracking(extra.parseGlob);
+            parseImportDeclaration = wrapTracking(extra.parseImportDeclaration);
+            parseImportSpecifier = wrapTracking(extra.parseImportSpecifier);
             parseLogicalANDExpression = wrapTracking(extra.parseLogicalANDExpression);
             parseLogicalORExpression = wrapTracking(extra.parseLogicalORExpression);
             parseMultiplicativeExpression = wrapTracking(extra.parseMultiplicativeExpression);
+            parseModuleDeclaration = wrapTracking(extra.parseModuleDeclaration);
+            parseModuleBlock = wrapTracking(extra.parseModuleBlock);
             parseNewExpression = wrapTracking(extra.parseNewExpression);
             parseNonComputedMember = wrapTracking(extra.parseNonComputedMember);
             parseNonComputedProperty = wrapTracking(extra.parseNonComputedProperty);
             parseObjectProperty = wrapTracking(extra.parseObjectProperty);
             parseObjectPropertyKey = wrapTracking(extra.parseObjectPropertyKey);
+            parsePath = wrapTracking(extra.parsePath);
             parsePostfixExpression = wrapTracking(extra.parsePostfixExpression);
             parsePrimaryExpression = wrapTracking(extra.parsePrimaryExpression);
             parseProgram = wrapTracking(extra.parseProgram);
             parsePropertyFunction = wrapTracking(extra.parsePropertyFunction);
+            parseProtoExpression = wrapTracking(parseProtoExpression);
             parseRelationalExpression = wrapTracking(extra.parseRelationalExpression);
             parseStatement = wrapTracking(extra.parseStatement);
             parseShiftExpression = wrapTracking(extra.parseShiftExpression);
             parseSwitchCase = wrapTracking(extra.parseSwitchCase);
+            parseTriangleLiteral = wrapTracking(extra.parseTriangleLiteral);
             parseUnaryExpression = wrapTracking(extra.parseUnaryExpression);
             parseVariableDeclaration = wrapTracking(extra.parseVariableDeclaration);
             parseVariableIdentifier = wrapTracking(extra.parseVariableIdentifier);
@@ -3462,26 +4091,37 @@ parseStatement: true, parseSourceElement: true */
             parseConditionalExpression = extra.parseConditionalExpression;
             parseConstLetDeclaration = extra.parseConstLetDeclaration;
             parseEqualityExpression = extra.parseEqualityExpression;
+            parseExportDeclaration = extra.parseExportDeclaration;
+            parseExportSpecifier = extra.parseExportSpecifier;
+            parseExportSpecifierSetProperty = extra.parseExportSpecifierSetProperty;
             parseExpression = extra.parseExpression;
             parseForVariableDeclaration = extra.parseForVariableDeclaration;
             parseFunctionDeclaration = extra.parseFunctionDeclaration;
             parseFunctionExpression = extra.parseFunctionExpression;
+            parseGlob = extra.parseGlob;
+            parseImportDeclaration = extra.parseImportDeclaration;
+            parseImportSpecifier = extra.parseImportSpecifier;
             parseLogicalANDExpression = extra.parseLogicalANDExpression;
             parseLogicalORExpression = extra.parseLogicalORExpression;
             parseMultiplicativeExpression = extra.parseMultiplicativeExpression;
+            parseModuleDeclaration = extra.parseModuleDeclaration;
+            parseModuleBlock = extra.parseModuleBlock;
             parseNewExpression = extra.parseNewExpression;
             parseNonComputedMember = extra.parseNonComputedMember;
             parseNonComputedProperty = extra.parseNonComputedProperty;
             parseObjectProperty = extra.parseObjectProperty;
             parseObjectPropertyKey = extra.parseObjectPropertyKey;
-            parsePrimaryExpression = extra.parsePrimaryExpression;
+            parsePath = extra.parsePath;
             parsePostfixExpression = extra.parsePostfixExpression;
+            parsePrimaryExpression = extra.parsePrimaryExpression;
             parseProgram = extra.parseProgram;
             parsePropertyFunction = extra.parsePropertyFunction;
+            parseProtoExpression = extra.parseProtoExpression;
             parseRelationalExpression = extra.parseRelationalExpression;
             parseStatement = extra.parseStatement;
             parseShiftExpression = extra.parseShiftExpression;
             parseSwitchCase = extra.parseSwitchCase;
+            parseTriangleLiteral = extra.parseTriangleLiteral;
             parseUnaryExpression = extra.parseUnaryExpression;
             parseVariableDeclaration = extra.parseVariableDeclaration;
             parseVariableIdentifier = extra.parseVariableIdentifier;
@@ -3497,7 +4137,7 @@ parseStatement: true, parseSourceElement: true */
         var length = str.length,
             result = [],
             i;
-        for (i = 0; i < length; i += 1) {
+        for (i = 0; i < length; ++i) {
             result[i] = str.charAt(i);
         }
         return result;
@@ -3517,12 +4157,14 @@ parseStatement: true, parseSourceElement: true */
         lineStart = 0;
         length = source.length;
         buffer = null;
-        allowIn = true;
-        labelSet = {};
-        inSwitch = false;
-        inIteration = false;
-        lastParenthesized = null;
-        inFunctionBody = false;
+        state = {
+            allowIn: true,
+            labelSet: {},
+            lastParenthesized: null,
+            inFunctionBody: false,
+            inIteration: false,
+            inSwitch: false
+        };
 
         extra = {};
         if (typeof options !== 'undefined') {
@@ -3535,6 +4177,9 @@ parseStatement: true, parseSourceElement: true */
             if (typeof options.comment === 'boolean' && options.comment) {
                 extra.comments = [];
             }
+            if (typeof options.tolerant === 'boolean' && options.tolerant) {
+                extra.errors = [];
+            }
         }
 
         if (length > 0) {
@@ -3562,6 +4207,9 @@ parseStatement: true, parseSourceElement: true */
             if (typeof extra.tokens !== 'undefined') {
                 program.tokens = extra.tokens;
             }
+            if (typeof extra.errors !== 'undefined') {
+                program.errors = extra.errors;
+            }
         } catch (e) {
             throw e;
         } finally {
@@ -3572,173 +4220,31 @@ parseStatement: true, parseSourceElement: true */
         return program;
     }
 
-    // Executes visitor on the object and its children (recursively).
+    // Sync with package.json.
+    exports.version = '1.0.0-dev';
 
-    function traverse(object, visitor, master) {
-        var key, child, parent, path;
+    exports.parse = parse;
 
-        parent = (typeof master === 'undefined') ? [] : master;
+    // Deep copy.
+    exports.Syntax = (function () {
+        var name, types = {};
 
-        if (visitor.call(null, object, parent) === false) {
-            return;
+        if (typeof Object.create === 'function') {
+            types = Object.create(null);
         }
-        for (key in object) {
-            if (object.hasOwnProperty(key)) {
-                child = object[key];
-                path = [ object ];
-                path.push(parent);
-                if (typeof child === 'object' && child !== null) {
-                    traverse(child, visitor, path);
-                }
-            }
-        }
-    }
-
-    // Insert a prolog in the body of every function.
-    // It will be in the form of a function call:
-    //
-    //     traceName(object);
-    //
-    // where the object contains the following properties:
-    //
-    //    'name' holds the name of the function
-    //    'lineNumber' holds the starting line number of the function block
-    //    'range' contains the index-based range of the function
-    //
-    // The name of the function represents the associated reference for
-    // the function (deduced on a best-effort basis if it is not
-    // a function declaration).
-    //
-    // If traceName is a function instead of a string, it will be invoked and
-    // the result will be used as the entire prolog. The arguments for the
-    // invocation are the function name, range, and location info.
-
-    function traceFunctionEntrance(traceName) {
-
-        return function (code) {
-            var tree,
-                functionList,
-                param,
-                signature,
-                pos,
-                i;
-
-
-            tree = parse(code, { range: true, loc: true });
-
-            functionList = [];
-            traverse(tree, function (node, path) {
-                var parent;
-                if (node.type === Syntax.FunctionDeclaration) {
-                    functionList.push({
-                        name: node.id.name,
-                        range: node.range,
-                        loc: node.loc,
-                        blockStart: node.body.range[0]
-                    });
-                } else if (node.type === Syntax.FunctionExpression) {
-                    parent = path[0];
-                    if (parent.type === Syntax.AssignmentExpression) {
-                        if (typeof parent.left.range !== 'undefined') {
-                            functionList.push({
-                                name: code.slice(parent.left.range[0],
-                                          parent.left.range[1] + 1),
-                                range: node.range,
-                                loc: node.loc,
-                                blockStart: node.body.range[0]
-                            });
-                        }
-                    } else if (parent.type === Syntax.VariableDeclarator) {
-                        functionList.push({
-                            name: parent.id.name,
-                            range: node.range,
-                            loc: node.loc,
-                            blockStart: node.body.range[0]
-                        });
-                    } else if (parent.type === Syntax.CallExpression) {
-                        functionList.push({
-                            name: parent.id ? parent.id.name : '[Anonymous]',
-                            range: node.range,
-                            loc: node.loc,
-                            blockStart: node.body.range[0]
-                        });
-                    } else if (typeof parent.length === 'number') {
-                        functionList.push({
-                            name: parent.id ? parent.id.name : '[Anonymous]',
-                            range: node.range,
-                            loc: node.loc,
-                            blockStart: node.body.range[0]
-                        });
-                    } else if (typeof parent.key !== 'undefined') {
-                        if (parent.key.type === 'Identifier') {
-                            if (parent.value === node && parent.key.name) {
-                                functionList.push({
-                                    name: parent.key.name,
-                                    range: node.range,
-                                    loc: node.loc,
-                                    blockStart: node.body.range[0]
-                                });
-                            }
-                        }
-                    }
-                }
-            });
-
-            // Insert the instrumentation code from the last entry.
-            // This is to ensure that the range for each entry remains valid)
-            // (it won't shift due to some new inserting string before the range).
-            for (i = functionList.length - 1; i >= 0; i -= 1) {
-                param = {
-                    name: functionList[i].name,
-                    range: functionList[i].range,
-                    loc: functionList[i].loc
-                };
-                if (typeof traceName === 'function') {
-                    signature = traceName.call(null, param);
-                } else {
-                    signature = traceName + '({ ';
-                    signature += 'name: \'' + functionList[i].name + '\', ';
-                    if (typeof functionList[i].loc !== 'undefined') {
-                        signature += 'lineNumber: ' + functionList[i].loc.start.line + ', ';
-                    }
-                    signature += 'range: [' + functionList[i].range[0] + ', ' +
-                        functionList[i].range[1] + '] ';
-                    signature += '});';
-                }
-                pos = functionList[i].blockStart + 1;
-                code = code.slice(0, pos) + '\n' + signature + code.slice(pos, code.length);
-            }
 
-            return code;
-        };
-    }
-
-    function modify(code, modifiers) {
-        var i;
-
-        if (Object.prototype.toString.call(modifiers) === '[object Array]') {
-            for (i = 0; i < modifiers.length; i += 1) {
-                code = modifiers[i].call(null, code);
+        for (name in Syntax) {
+            if (Syntax.hasOwnProperty(name)) {
+                types[name] = Syntax[name];
             }
-        } else if (typeof modifiers === 'function') {
-            code = modifiers.call(null, code);
-        } else {
-            throw new Error('Wrong use of esprima.modify() function');
         }
 
-        return code;
-    }
-
-    // Sync with package.json.
-    exports.version = '0.9.9-dev';
-
-    exports.parse = parse;
-
-    exports.modify = modify;
+        if (typeof Object.freeze === 'function') {
+            Object.freeze(types);
+        }
 
-    exports.Tracer = {
-        FunctionEntrance: traceFunctionEntrance
-    };
+        return types;
+    }());
 
 }(typeof exports === 'undefined' ? (esprima = {}) : exports));
 /* vim: set sw=4 ts=4 et tw=80 : */
diff --git a/escodegen.js b/escodegen.js
index 0590190..59087f6 100644
--- a/escodegen.js
+++ b/escodegen.js
@@ -1,4 +1,5 @@
 /*
+  Copyright (C) 2012 John Freeman <jf...@gmail.com>
   Copyright (C) 2012 Ariya Hidayat <ar...@gmail.com>
   Copyright (C) 2012 Mathias Bynens <ma...@qiwi.be>
   Copyright (C) 2012 Joost-Wim Boekesteijn <jo...@boekesteijn.nl>
@@ -37,6 +38,9 @@
     var Syntax,
         Precedence,
         BinaryPrecedence,
+        VisitorKeys,
+        VisitorOption,
+        isArray,
         base,
         indent,
         extra,
@@ -139,10 +143,12 @@
             indent: null,
             base: null,
             parse: null,
+            comment: false,
             format: {
                 indent: {
                     style: '    ',
-                    base: 0
+                    base: 0,
+                    adjustMultilineComment: false
                 }
             }
         };
@@ -179,6 +185,42 @@
         return result;
     }
 
+    isArray = Array.isArray;
+    if (!isArray) {
+        isArray = function isArray(array) {
+            return Object.prototype.toString.call(array) === '[object Array]';
+        };
+    }
+
+    function endsWithLineTerminator(value) {
+        return (/(?:\r\n|[\n\r])$/).test(value);
+    }
+
+    function shallowCopy(obj) {
+        var ret = {}, key;
+        for (key in obj) {
+            if (obj.hasOwnProperty(key)) {
+                ret[key] = obj[key];
+            }
+        }
+        return ret;
+    }
+
+    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;
+    }
+
     function updateDeeply(target, override) {
         var key, val;
 
@@ -247,18 +289,71 @@
         return '\'' + result + '\'';
     }
 
+    function isWhiteSpace(ch) {
+        return (ch === ' ') || (ch === '\u0009') || (ch === '\u000B') ||
+            (ch === '\u000C') || (ch === '\u00A0') ||
+            (ch.charCodeAt(0) >= 0x1680 &&
+             '\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\uFEFF'.indexOf(ch) >= 0);
+    }
+
     function addIndent(stmt) {
         return base + stmt;
     }
 
+    function adjustMultilineComment(value) {
+        var array, i, len, line, j, ch, spaces;
+
+        spaces = Number.MAX_VALUE;
+        array = value.split(/\r\n|[\r\n]/);
+
+        // first line doesn't have indentation
+        for (i = 1, len = array.length; i < len; i += 1) {
+            line = array[i];
+            j = 0;
+            while (j < line.length && isWhiteSpace(line[j])) {
+                j += 1;
+            }
+            if (spaces > j) {
+                spaces = j;
+            }
+        }
+
+        if (spaces % 2 === 1) {
+            // /*
+            //  *
+            //  */
+            // If spaces are odd number, above pattern is considered.
+            // We waste 1 space.
+            spaces -= 1;
+        }
+        for (i = 1, len = array.length; i < len; i += 1) {
+            array[i] = addIndent(array[i].slice(spaces));
+        }
+        return array.join('\n');
+    }
+
+    function generateComment(comment) {
+        if (comment.type === 'Line') {
+            // Esprima always produce last line comment with LineTerminator
+            return '//' + comment.value;
+        }
+        if (extra.format.indent.adjustMultilineComment && /[\n\r]/.test(comment.value)) {
+            return adjustMultilineComment('/*' + comment.value + '*/');
+        }
+        return '/*' + comment.value + '*/';
+    }
+
     function parenthesize(text, current, should) {
-        return (current < should) ?  '(' + text + ')' : text;
+        if (current < should) {
+            return '(' + text + ')';
+        }
+        return text;
     }
 
     function maybeBlock(stmt, suffix) {
         var previousBase, result;
 
-        if (stmt.type === Syntax.BlockStatement) {
+        if (stmt.type === Syntax.BlockStatement && (!extra.comment || !stmt.leadingComments)) {
             result = ' ' + generateStatement(stmt);
             if (suffix) {
                 return result + ' ';
@@ -266,7 +361,7 @@
             return result;
         }
 
-        if (stmt.type === Syntax.EmptyStatement) {
+        if (stmt.type === Syntax.EmptyStatement && (!extra.comment || !stmt.leadingComments)) {
             result = ';';
         } else {
             previousBase = base;
@@ -293,18 +388,23 @@
         return result + ')' + maybeBlock(node.body);
     }
 
-    function generateExpression(expr, precedence) {
-        var result, currentPrecedence, previousBase, i, len, raw;
+    function generateExpression(expr, option) {
+        var result, precedence, currentPrecedence, previousBase, i, len, raw, allowIn, allowCall;
 
-        if (!precedence) {
-            precedence = Precedence.Sequence;
-        }
+        precedence = option.precedence;
+        allowIn = option.allowIn;
+        allowCall = option.allowCall;
 
         switch (expr.type) {
         case Syntax.SequenceExpression:
             result = '';
+            allowIn |= (Precedence.Sequence < precedence);
             for (i = 0, len = expr.expressions.length; i < len; i += 1) {
-                result += generateExpression(expr.expressions[i], Precedence.Assignment);
+                result += generateExpression(expr.expressions[i], {
+                    precedence: Precedence.Assignment,
+                    allowIn: allowIn,
+                    allowCall: true
+                });
                 if ((i + 1) < len) {
                     result += ', ';
                 }
@@ -313,19 +413,41 @@
             break;
 
         case Syntax.AssignmentExpression:
+            allowIn |= (Precedence.Assignment < precedence);
             result = parenthesize(
-                generateExpression(expr.left, Precedence.Call) + ' ' + expr.operator + ' ' +
-                    generateExpression(expr.right, Precedence.Assignment),
+                generateExpression(expr.left, {
+                    precedence: Precedence.Call,
+                    allowIn: allowIn,
+                    allowCall: true
+                }) + ' ' + expr.operator + ' ' +
+                    generateExpression(expr.right, {
+                        precedence: Precedence.Assignment,
+                        allowIn: allowIn,
+                        allowCall: true
+                    }),
                 Precedence.Assignment,
                 precedence
             );
             break;
 
         case Syntax.ConditionalExpression:
+            allowIn |= (Precedence.Conditional < precedence);
             result = parenthesize(
-                generateExpression(expr.test, Precedence.LogicalOR) + ' ? ' +
-                    generateExpression(expr.consequent, Precedence.Assignment) + ' : ' +
-                    generateExpression(expr.alternate, Precedence.Assignment),
+                generateExpression(expr.test, {
+                    precedence: Precedence.LogicalOR,
+                    allowIn: allowIn,
+                    allowCall: true
+                }) + ' ? ' +
+                    generateExpression(expr.consequent, {
+                        precedence: Precedence.Assignment,
+                        allowIn: allowIn,
+                        allowCall: true
+                    }) + ' : ' +
+                    generateExpression(expr.alternate, {
+                        precedence: Precedence.Assignment,
+                        allowIn: allowIn,
+                        allowCall: true
+                    }),
                 Precedence.Conditional,
                 precedence
             );
@@ -335,51 +457,91 @@
         case Syntax.BinaryExpression:
             currentPrecedence = BinaryPrecedence[expr.operator];
 
-            result = generateExpression(expr.left, currentPrecedence) +
-                ' ' + expr.operator + ' ' +
-                generateExpression(expr.right, currentPrecedence + 1);
-            if (expr.operator === 'in') {
-                // TODO parenthesize only in allowIn = false case
+            allowIn |= (currentPrecedence < precedence);
+
+            result =
+                generateExpression(expr.left, {
+                    precedence: currentPrecedence,
+                    allowIn: allowIn,
+                    allowCall: true
+                }) + ' ' + expr.operator + ' ' +
+                generateExpression(expr.right, {
+                    precedence: currentPrecedence + 1,
+                    allowIn: allowIn,
+                    allowCall: true
+                });
+
+            if (expr.operator === 'in' && !allowIn) {
                 result = '(' + result + ')';
             } else {
                 result = parenthesize(result, currentPrecedence, precedence);
             }
+
             break;
 
         case Syntax.CallExpression:
-            result = '';
+            result = generateExpression(expr.callee, {
+                precedence: Precedence.Call,
+                allowIn: true,
+                allowCall: true
+            });
+
+            result += '(';
             for (i = 0, len = expr['arguments'].length; i < len; i += 1) {
-                result += generateExpression(expr['arguments'][i], Precedence.Assignment);
+                result += generateExpression(expr['arguments'][i], {
+                    precedence: Precedence.Assignment,
+                    allowIn: true,
+                    allowCall: true
+                });
                 if ((i + 1) < len) {
                     result += ', ';
                 }
             }
-            result = parenthesize(
-                generateExpression(expr.callee, Precedence.Call) + '(' + result + ')',
-                Precedence.Call,
-                precedence
-            );
+            result += ')';
+
+            if (!allowCall) {
+                result = '(' + result + ')';
+            } else {
+                result = parenthesize(result, Precedence.Call, precedence);
+            }
             break;
 
         case Syntax.NewExpression:
-            result = '';
+            result = 'new ' + generateExpression(expr.callee, {
+                precedence: Precedence.New,
+                allowIn: true,
+                allowCall: false
+            });
+
+            result += '(';
             for (i = 0, len = expr['arguments'].length; i < len; i += 1) {
-                result += generateExpression(expr['arguments'][i], Precedence.Assignment);
+                result += generateExpression(expr['arguments'][i], {
+                    precedence: Precedence.Assignment,
+                    allowIn: true,
+                    allowCall: true
+                });
                 if ((i + 1) < len) {
                     result += ', ';
                 }
             }
-            result = parenthesize(
-                'new ' + generateExpression(expr.callee, Precedence.New) + '(' + result + ')',
-                Precedence.New,
-                precedence
-            );
+            result += ')';
+
+            result = parenthesize(result, Precedence.New, precedence);
             break;
 
         case Syntax.MemberExpression:
-            result = generateExpression(expr.object, Precedence.Call);
+            result = generateExpression(expr.object, {
+                precedence: Precedence.Call,
+                allowIn: true,
+                allowCall: allowCall
+            });
+
             if (expr.computed) {
-                result += '[' + generateExpression(expr.property) + ']';
+                result += '[' + generateExpression(expr.property, {
+                    precedence: Precedence.Sequence,
+                    allowIn: true,
+                    allowCall: allowCall
+                }) + ']';
             } else {
                 if (expr.object.type === Syntax.Literal && typeof expr.object.value === 'number') {
                     if (result.indexOf('.') < 0) {
@@ -390,6 +552,7 @@
                 }
                 result += '.' + expr.property.name;
             }
+
             result = parenthesize(result, Precedence.Member, precedence);
             break;
 
@@ -399,13 +562,15 @@
                 result += ' ';
             }
             result = parenthesize(
-                result + generateExpression(expr.argument, Precedence.Unary +
-                    (
+                result + generateExpression(expr.argument, {
+                    precedence: Precedence.Unary + (
                         expr.argument.type === Syntax.UnaryExpression &&
-                        expr.operator.length < 3 &&
-                        expr.argument.operator === expr.operator ? 1 : 0
-                    )
+                            expr.operator.length < 3 &&
+                            expr.argument.operator === expr.operator ? 1 : 0
                     ),
+                    allowIn: true,
+                    allowCall: true
+                }),
                 Precedence.Unary,
                 precedence
             );
@@ -415,14 +580,21 @@
             if (expr.prefix) {
                 result = parenthesize(
                     expr.operator +
-                        generateExpression(expr.argument, Precedence.Unary),
+                        generateExpression(expr.argument, {
+                            precedence: Precedence.Unary,
+                            allowIn: true,
+                            allowCall: true
+                        }),
                     Precedence.Unary,
                     precedence
                 );
             } else {
                 result = parenthesize(
-                    generateExpression(expr.argument, Precedence.Postfix) +
-                        expr.operator,
+                    generateExpression(expr.argument, {
+                        precedence: Precedence.Postfix,
+                        allowIn: true,
+                        allowCall: true
+                    }) + expr.operator,
                     Precedence.Postfix,
                     precedence
                 );
@@ -452,7 +624,11 @@
                         result += ',';
                     }
                 } else {
-                    result += addIndent(generateExpression(expr.elements[i], Precedence.Assignment));
+                    result += addIndent(generateExpression(expr.elements[i], {
+                        precedence: Precedence.Assignment,
+                        allowIn: true,
+                        allowCall: true
+                    }));
                 }
                 if ((i + 1) < len) {
                     result += ',\n';
@@ -464,11 +640,22 @@
 
         case Syntax.Property:
             if (expr.kind === 'get' || expr.kind === 'set') {
-                result = expr.kind + ' ' + generateExpression(expr.key) +
-                    generateFunctionBody(expr.value);
+                result = expr.kind + ' ' + generateExpression(expr.key, {
+                    precedence: Precedence.Sequence,
+                    allowIn: true,
+                    allowCall: true
+                }) + generateFunctionBody(expr.value);
             } else {
-                result = generateExpression(expr.key) + ': ' +
-                    generateExpression(expr.value, Precedence.Assignment);
+                result =
+                    generateExpression(expr.key, {
+                        precedence: Precedence.Sequence,
+                        allowIn: true,
+                        allowCall: true
+                    }) + ': ' + generateExpression(expr.value, {
+                        precedence: Precedence.Assignment,
+                        allowIn: true,
+                        allowCall: true
+                    });
             }
             break;
 
@@ -481,7 +668,11 @@
             previousBase = base;
             base += indent;
             for (i = 0, len = expr.properties.length; i < len; i += 1) {
-                result += addIndent(generateExpression(expr.properties[i]));
+                result += addIndent(generateExpression(expr.properties[i], {
+                    precedence: Precedence.Sequence,
+                    allowIn: true,
+                    allowCall: true
+                }));
                 if ((i + 1) < len) {
                     result += ',\n';
                 }
@@ -542,8 +733,13 @@
         return result;
     }
 
-    function generateStatement(stmt) {
-        var i, len, result, previousBase;
+    function generateStatement(stmt, option) {
+        var i, len, result, previousBase, comment, save, ret, node, allowIn;
+
+        allowIn = true;
+        if (option) {
+            allowIn = option.allowIn;
+        }
 
         switch (stmt.type) {
         case Syntax.BlockStatement:
@@ -576,13 +772,21 @@
             break;
 
         case Syntax.DoWhileStatement:
-            result = 'do' + maybeBlock(stmt.body, true) + 'while (' + generateExpression(stmt.test) + ');';
+            result = 'do' + maybeBlock(stmt.body, true) + 'while (' + generateExpression(stmt.test, {
+                precedence: Precedence.Sequence,
+                allowIn: true,
+                allowCall: true
+            }) + ');';
             break;
 
         case Syntax.CatchClause:
             previousBase = base;
             base += indent;
-            result = ' catch (' + generateExpression(stmt.param) + ')';
+            result = ' catch (' + generateExpression(stmt.param, {
+                precedence: Precedence.Sequence,
+                allowIn: true,
+                allowCall: true
+            }) + ')';
             base = previousBase;
             result += maybeBlock(stmt.body);
             break;
@@ -596,7 +800,11 @@
             break;
 
         case Syntax.ExpressionStatement:
-            result = generateExpression(stmt.expression);
+            result = generateExpression(stmt.expression, {
+                precedence: Precedence.Sequence,
+                allowIn: true,
+                allowCall: true
+            });
             // 12.4 '{', 'function' is not allowed in this position.
             // wrap espression with parentheses
             if (result[0] === '{' || result.indexOf('function ') === 0) {
@@ -608,27 +816,54 @@
 
         case Syntax.VariableDeclarator:
             if (stmt.init) {
-                result = stmt.id.name + ' = ' + generateExpression(stmt.init, Precedence.Assignment);
+                result = stmt.id.name + ' = ' + generateExpression(stmt.init, {
+                    precedence: Precedence.Assignment,
+                    allowIn: allowIn,
+                    allowCall: true
+                });
             } else {
                 result = stmt.id.name;
             }
             break;
 
         case Syntax.VariableDeclaration:
-            result = stmt.kind + ' ';
+            result = stmt.kind;
             // special path for
             // var x = function () {
             // };
             if (stmt.declarations.length === 1 && stmt.declarations[0].init &&
                     stmt.declarations[0].init.type === Syntax.FunctionExpression) {
-                result += generateStatement(stmt.declarations[0]);
+                result += ' ' + generateStatement(stmt.declarations[0], {
+                    allowIn: allowIn
+                });
             } else {
+                // VariableDeclarator is typed as Statement,
+                // but joined with comma (not LineTerminator).
+                // So if comment is attached to target node, we should specialize.
                 previousBase = base;
                 base += indent;
-                for (i = 0, len = stmt.declarations.length; i < len; i += 1) {
-                    result += generateStatement(stmt.declarations[i]);
-                    if ((i + 1) < len) {
-                        result += ', ';
+
+                node = stmt.declarations[0];
+                if (extra.comment && node.leadingComments) {
+                    result += '\n' + addIndent(generateStatement(node, {
+                        allowIn: allowIn
+                    }));
+                } else {
+                    result += ' ' + generateStatement(node, {
+                        allowIn: allowIn
+                    });
+                }
+
+                for (i = 1, len = stmt.declarations.length; i < len; i += 1) {
+                    node = stmt.declarations[i];
+                    if (extra.comment && node.leadingComments) {
+                        result += ',\n' + addIndent(generateStatement(node, {
+                            allowIn: allowIn
+                        }));
+                    } else {
+                        result += ', ' + generateStatement(node, {
+                            allowIn: allowIn
+                        });
                     }
                 }
                 base = previousBase;
@@ -637,7 +872,11 @@
             break;
 
         case Syntax.ThrowStatement:
-            result = 'throw ' + generateExpression(stmt.argument) + ';';
+            result = 'throw ' + generateExpression(stmt.argument, {
+                precedence: Precedence.Sequence,
+                allowIn: true,
+                allowCall: true
+            }) + ';';
             break;
 
         case Syntax.TryStatement:
@@ -653,7 +892,11 @@
         case Syntax.SwitchStatement:
             previousBase = base;
             base += indent;
-            result = 'switch (' + generateExpression(stmt.discriminant) + ') {\n';
+            result = 'switch (' + generateExpression(stmt.discriminant, {
+                precedence: Precedence.Sequence,
+                allowIn: true,
+                allowCall: true
+            }) + ') {\n';
             base = previousBase;
             if (stmt.cases) {
                 for (i = 0, len = stmt.cases.length; i < len; i += 1) {
@@ -667,7 +910,11 @@
             previousBase = base;
             base += indent;
             if (stmt.test) {
-                result = 'case ' + generateExpression(stmt.test) + ':';
+                result = 'case ' + generateExpression(stmt.test, {
+                    precedence: Precedence.Sequence,
+                    allowIn: true,
+                    allowCall: true
+                }) + ':';
             } else {
                 result = 'default:';
             }
@@ -691,20 +938,32 @@
                 if (stmt.alternate.type === Syntax.IfStatement) {
                     previousBase = base;
                     base += indent;
-                    result = 'if (' +  generateExpression(stmt.test) + ')';
+                    result = 'if (' +  generateExpression(stmt.test, {
+                        precedence: Precedence.Sequence,
+                        allowIn: true,
+                        allowCall: true
+                    }) + ')';
                     base = previousBase;
                     result += maybeBlock(stmt.consequent, true) + 'else ' + generateStatement(stmt.alternate);
                 } else {
                     previousBase = base;
                     base += indent;
-                    result = 'if (' + generateExpression(stmt.test) + ')';
+                    result = 'if (' + generateExpression(stmt.test, {
+                        precedence: Precedence.Sequence,
+                        allowIn: true,
+                        allowCall: true
+                    }) + ')';
                     base = previousBase;
                     result += maybeBlock(stmt.consequent, true) + 'else' + maybeBlock(stmt.alternate);
                 }
             } else {
                 previousBase = base;
                 base += indent;
-                result = 'if (' + generateExpression(stmt.test) + ')';
+                result = 'if (' + generateExpression(stmt.test, {
+                    precedence: Precedence.Sequence,
+                    allowIn: true,
+                    allowCall: true
+                }) + ')';
                 base = previousBase;
                 result += maybeBlock(stmt.consequent);
             }
@@ -716,22 +975,36 @@
             result = 'for (';
             if (stmt.init) {
                 if (stmt.init.type === Syntax.VariableDeclaration) {
-                    result += generateStatement(stmt.init);
+                    result += generateStatement(stmt.init, {
+                        allowIn: false
+                    });
                 } else {
-                    result += generateExpression(stmt.init) + ';';
+                    result += generateExpression(stmt.init, {
+                        precedence: Precedence.Sequence,
+                        allowIn: false,
+                        allowCall: true
+                    }) + ';';
                 }
             } else {
                 result += ';';
             }
 
             if (stmt.test) {
-                result += ' ' + generateExpression(stmt.test) + ';';
+                result += ' ' + generateExpression(stmt.test, {
+                    precedence: Precedence.Sequence,
+                    allowIn: true,
+                    allowCall: true
+                }) + ';';
             } else {
                 result += ';';
             }
 
             if (stmt.update) {
-                result += ' ' + generateExpression(stmt.update) + ')';
+                result += ' ' + generateExpression(stmt.update, {
+                    precedence: Precedence.Sequence,
+                    allowIn: true,
+                    allowCall: true
+                }) + ')';
             } else {
                 result += ')';
             }
@@ -745,18 +1018,28 @@
             if (stmt.left.type === Syntax.VariableDeclaration) {
                 previousBase = base;
                 base += indent + indent;
-                result += stmt.left.kind + ' ' + generateStatement(stmt.left.declarations[0]);
+                result += stmt.left.kind + ' ' + generateStatement(stmt.left.declarations[0], {
+                    allowIn: false
+                });
                 base = previousBase;
             } else {
                 previousBase = base;
                 base += indent;
-                result += generateExpression(stmt.left, Precedence.Call);
+                result += generateExpression(stmt.left, {
+                    precedence: Precedence.Call,
+                    allowIn: true,
+                    allowCall: true
+                });
                 base = previousBase;
             }
 
             previousBase = base;
             base += indent;
-            result += ' in ' + generateExpression(stmt.right) + ')';
+            result += ' in ' + generateExpression(stmt.right, {
+                precedence: Precedence.Sequence,
+                allowIn: true,
+                allowCall: true
+            }) + ')';
             base = previousBase;
             result += maybeBlock(stmt.body);
             break;
@@ -785,7 +1068,11 @@
 
         case Syntax.ReturnStatement:
             if (stmt.argument) {
-                result = 'return ' + generateExpression(stmt.argument) + ';';
+                result = 'return ' + generateExpression(stmt.argument, {
+                    precedence: Precedence.Sequence,
+                    allowIn: true,
+                    allowCall: true
+                }) + ';';
             } else {
                 result = 'return;';
             }
@@ -794,7 +1081,11 @@
         case Syntax.WhileStatement:
             previousBase = base;
             base += indent;
-            result = 'while (' + generateExpression(stmt.test) + ')';
+            result = 'while (' + generateExpression(stmt.test, {
+                precedence: Precedence.Sequence,
+                allowIn: true,
+                allowCall: true
+            }) + ')';
             base = previousBase;
             result += maybeBlock(stmt.body);
             break;
@@ -802,7 +1093,11 @@
         case Syntax.WithStatement:
             previousBase = base;
             base += indent;
-            result = 'with (' + generateExpression(stmt.object) + ')';
+            result = 'with (' + generateExpression(stmt.object, {
+                precedence: Precedence.Sequence,
+                allowIn: true,
+                allowCall: true
+            }) + ')';
             base = previousBase;
             result += maybeBlock(stmt.body);
             break;
@@ -814,6 +1109,42 @@
         if (result === undefined) {
             throw new Error('Unknown statement type: ' + stmt.type);
         }
+
+        // Attach comments
+
+        if (extra.comment) {
+            if (stmt.leadingComments) {
+                save = result;
+
+                comment = stmt.leadingComments[0];
+                result = generateComment(comment);
+                if (!endsWithLineTerminator(result)) {
+                    result += '\n';
+                }
+
+                for (i = 1, len = stmt.leadingComments.length; i < len; i += 1) {
+                    comment = stmt.leadingComments[i];
+                    ret = generateComment(comment);
+                    if (!endsWithLineTerminator(ret)) {
+                        ret += '\n';
+                    }
+                    result += addIndent(ret);
+                }
+
+                result += addIndent(save);
+            }
+
+            if (stmt.trailingComments) {
+                for (i = 0, len = stmt.trailingComments.length; i < len; i += 1) {
+                    comment = stmt.trailingComments[i];
+                    if (!endsWithLineTerminator(result)) {
+                        result += '\n';
+                    }
+                    result += addIndent(generateComment(comment));
+                }
+            }
+        }
+
         return result;
     }
 
@@ -845,6 +1176,7 @@
             base = stringRepeat(indent, options.format.indent.base);
             parse = options.parse;
         }
+        extra = options;
 
         switch (node.type) {
         case Syntax.BlockStatement:
@@ -889,7 +1221,11 @@
         case Syntax.ThisExpression:
         case Syntax.UnaryExpression:
         case Syntax.UpdateExpression:
-            return generateExpression(node);
+            return generateExpression(node, {
+                precedence: Precedence.Sequence,
+                allowIn: true,
+                allowCall: true
+            });
 
         default:
             break;
@@ -897,10 +1233,295 @@
         throw new Error('Unknown node type: ' + node.type);
     }
 
+    // simple visitor implementation
+
+    VisitorKeys = {
+        AssignmentExpression: ['left', 'right'],
+        ArrayExpression: ['elements'],
+        BlockStatement: ['body'],
+        BinaryExpression: ['left', 'right'],
+        BreakStatement: ['label'],
+        CallExpression: ['callee', 'arguments'],
+        CatchClause: ['param', 'body'],
+        ConditionalExpression: ['test', 'consequent', 'alternate'],
+        ContinueStatement: ['label'],
+        DoWhileStatement: ['body', 'test'],
+        DebuggerStatement: [],
+        EmptyStatement: [],
+        ExpressionStatement: ['expression'],
+        ForStatement: ['init', 'test', 'update', 'body'],
+        ForInStatement: ['left', 'right', 'body'],
+        FunctionDeclaration: ['id', 'params', 'body'],
+        FunctionExpression: ['id', 'params', 'body'],
+        Identifier: [],
+        IfStatement: ['test', 'consequent', 'alternate'],
+        Literal: [],
+        LabeledStatement: ['label', 'body'],
+        LogicalExpression: ['left', 'right'],
+        MemberExpression: ['object', 'property'],
+        NewExpression: ['callee', 'arguments'],
+        ObjectExpression: ['properties'],
+        Program: ['body'],
+        Property: ['key', 'value'],
+        ReturnStatement: ['argument'],
+        SequenceExpression: ['expressions'],
+        SwitchStatement: ['descriminant', 'cases'],
+        SwitchCase: ['test', 'consequent'],
+        ThisExpression: [],
+        ThrowStatement: ['argument'],
+        TryStatement: ['block', 'handlers', 'finalizer'],
+        UnaryExpression: ['argument'],
+        UpdateExpression: ['argument'],
+        VariableDeclaration: ['declarations'],
+        VariableDeclarator: ['id', 'init'],
+        WhileStatement: ['test', 'body'],
+        WithStatement: ['object', 'body']
+    };
+
+    VisitorOption = {
+        Break: 1,
+        Skip: 2
+    };
+
+    function traverse(top, visitor) {
+        var worklist, leavelist, node, ret, current, current2, candidates, candidate;
+
+        worklist = [ top ];
+        leavelist = [];
+
+        while (worklist.length) {
+            node = worklist.pop();
+
+            if (node) {
+                if (visitor.enter) {
+                    ret = visitor.enter(node);
+                } else {
+                    ret = undefined;
+                }
+
+                if (ret === VisitorOption.Break) {
+                    return;
+                }
+
+                worklist.push(null);
+                leavelist.push(node);
+
+                if (ret !== VisitorOption.Skip) {
+                    candidates = VisitorKeys[node.type];
+                    current = candidates.length;
+                    while ((current -= 1) >= 0) {
+                        candidate = node[candidates[current]];
+                        if (candidate) {
+                            if (isArray(candidate)) {
+                                current2 = candidate.length;
+                                while ((current2 -= 1) >= 0) {
+                                    if (candidate[current2]) {
+                                        worklist.push(candidate[current2]);
+                                    }
+                                }
+                            } else {
+                                worklist.push(candidate);
+                            }
+                        }
+                    }
+                }
+            } else {
+                node = leavelist.pop();
+                if (visitor.leave) {
+                    ret = visitor.leave(node);
+                } else {
+                    ret = undefined;
+                }
+                if (ret === VisitorOption.Break) {
+                    return;
+                }
+            }
+        }
+    }
+
+
+    // 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;
+    }
+
+    function lowerBound(array, func) {
+        var diff, len, i, current;
+
+        len = array.length;
+        i = 0;
+
+        while (len) {
+            diff = len >>> 1;
+            current = i + diff;
+            if (func(array[current])) {
+                i = current + 1;
+                len -= diff + 1;
+            } else {
+                len = diff;
+            }
+        }
+        return i;
+    }
+
+    function extendCommentRange(comment, tokens) {
+        var target, token;
+
+        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) {
+            if (target < tokens.length) {
+                comment.extendedRange[0] = tokens[target].range[1];
+            } else if (token.length) {
+                comment.extendedRange[1] = tokens[tokens.length - 1].range[0];
+            }
+        }
+
+        return comment;
+    }
+
+    function attachComments(tree, providedComments, tokens) {
+        // At first, we should calculate extended comment ranges.
+        var comments = [], len, i;
+
+        if (!tree.range) {
+            throw new Error('attachComments needs range information');
+        }
+
+        for (i = 0, len = providedComments.length; i < len; i += 1) {
+            comments.push(extendCommentRange(deepCopy(providedComments[i]), tokens));
+        }
+
+        //
+        // For example,
+        //
+        //      var i1 = 10,  // test
+        //          i2 = 20;
+        //
+        //  Above comment is probably trailing to i1 = 10.
+        //  So we specialize comma token.
+        //
+        //  And second, comma first style example,
+        //
+        //  var i = [
+        //        10  // testing
+        //      , 20  // testing 2
+        //  ];
+        //
+        //  'testing' comment is trailing to 10 is proper.
+        //
+        //  So we add some specialize path.
+        //
+        //      1. check comment is'nt containing LineTerminator
+        //      2. check LineTerminator is not found between previous token and comment
+        //      3. check LineTerminator is found between comment and next token
+        //
+        //  If above conditions are all true,
+        //  we assume this comment should be attached to previous token as trailing comment.
+        //
+
+        // This traverse attacher is based on John Freeman's implementation.
+        traverse(tree, {
+            cursor: 0,
+            enter: function (node) {
+                var comment;
+
+                while (this.cursor < comments.length) {
+                    comment = comments[this.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(this.cursor, 1);
+                    } else {
+                        this.cursor += 1;
+                    }
+                }
+
+                // already out of owned node
+                if (this.cursor === comments.length) {
+                    return VisitorOption.Break;
+                }
+
+                if (comments[this.cursor].extendedRange[0] > node.range[1]) {
+                    return VisitorOption.Skip;
+                }
+            }
+        });
+
+        traverse(tree, {
+            cursor: 0,
+            leave: function (node) {
+                var comment;
+
+                while (this.cursor < comments.length) {
+                    comment = comments[this.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(this.cursor, 1);
+                    } else {
+                        this.cursor += 1;
+                    }
+                }
+
+                // already out of owned node
+                if (this.cursor === comments.length) {
+                    return VisitorOption.Break;
+                }
+
+                if (comments[this.cursor].extendedRange[0] > node.range[1]) {
+                    return VisitorOption.Skip;
+                }
+            }
+        });
+
+        return tree;
+    }
+
     // Sync with package.json.
-    exports.version = '0.0.4-dev';
+    exports.version = '0.0.4';
 
     exports.generate = generate;
+    exports.traverse = traverse;
+    exports.attachComments = attachComments;
 
 }(typeof exports === 'undefined' ? (escodegen = {}) : exports));
 /* vim: set sw=4 ts=4 et tw=80 : */


[couchdb-escodegen] 09/11: Merge pull request #141 from jiyinyiyong/gh-pages

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch gh-pages
in repository https://gitbox.apache.org/repos/asf/couchdb-escodegen.git

commit 578cfbdf5730fc773a41feddf554c15a427f0a0e
Merge: c6dc33c 8544537
Author: Yusuke Suzuki <ut...@gmail.com>
AuthorDate: Sat Oct 26 23:31:02 2013 -0700

    Merge pull request #141 from jiyinyiyong/gh-pages
    
    www.esprima.org should be esprima.org

 demo/index.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)