Last active
December 28, 2016 19:17
-
-
Save hugs/b0c22d69063949e41be379ba0b51d775 to your computer and use it in GitHub Desktop.
Eval.js Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ | |
// Copyright Joyent, Inc. and other Node contributors. | |
// | |
// Permission is hereby granted, free of charge, to any person obtaining a | |
// copy of this software and associated documentation files (the | |
// "Software"), to deal in the Software without restriction, including | |
// without limitation the rights to use, copy, modify, merge, publish, | |
// distribute, sublicense, and/or sell copies of the Software, and to permit | |
// persons to whom the Software is furnished to do so, subject to the | |
// following conditions: | |
// | |
// The above copyright notice and this permission notice shall be included | |
// in all copies or substantial portions of the Software. | |
// | |
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN | |
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, | |
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | |
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | |
// USE OR OTHER DEALINGS IN THE SOFTWARE. | |
function EventEmitter() { | |
this._events = this._events || {}; | |
this._maxListeners = this._maxListeners || undefined; | |
} | |
module.exports = EventEmitter; | |
// Backwards-compat with node 0.10.x | |
EventEmitter.EventEmitter = EventEmitter; | |
EventEmitter.prototype._events = undefined; | |
EventEmitter.prototype._maxListeners = undefined; | |
// By default EventEmitters will print a warning if more than 10 listeners are | |
// added to it. This is a useful default which helps finding memory leaks. | |
EventEmitter.defaultMaxListeners = 10; | |
// Obviously not all Emitters should be limited to 10. This function allows | |
// that to be increased. Set to zero for unlimited. | |
EventEmitter.prototype.setMaxListeners = function(n) { | |
if (!isNumber(n) || n < 0 || isNaN(n)) | |
throw TypeError('n must be a positive number'); | |
this._maxListeners = n; | |
return this; | |
}; | |
EventEmitter.prototype.emit = function(type) { | |
var er, handler, len, args, i, listeners; | |
if (!this._events) | |
this._events = {}; | |
// If there is no 'error' event listener then throw. | |
if (type === 'error') { | |
if (!this._events.error || | |
(isObject(this._events.error) && !this._events.error.length)) { | |
er = arguments[1]; | |
if (er instanceof Error) { | |
throw er; // Unhandled 'error' event | |
} else { | |
// At least give some kind of context to the user | |
var err = new Error('Uncaught, unspecified "error" event. (' + er + ')'); | |
err.context = er; | |
throw err; | |
} | |
} | |
} | |
handler = this._events[type]; | |
if (isUndefined(handler)) | |
return false; | |
if (isFunction(handler)) { | |
switch (arguments.length) { | |
// fast cases | |
case 1: | |
handler.call(this); | |
break; | |
case 2: | |
handler.call(this, arguments[1]); | |
break; | |
case 3: | |
handler.call(this, arguments[1], arguments[2]); | |
break; | |
// slower | |
default: | |
args = Array.prototype.slice.call(arguments, 1); | |
handler.apply(this, args); | |
} | |
} else if (isObject(handler)) { | |
args = Array.prototype.slice.call(arguments, 1); | |
listeners = handler.slice(); | |
len = listeners.length; | |
for (i = 0; i < len; i++) | |
listeners[i].apply(this, args); | |
} | |
return true; | |
}; | |
EventEmitter.prototype.addListener = function(type, listener) { | |
var m; | |
if (!isFunction(listener)) | |
throw TypeError('listener must be a function'); | |
if (!this._events) | |
this._events = {}; | |
// To avoid recursion in the case that type === "newListener"! Before | |
// adding it to the listeners, first emit "newListener". | |
if (this._events.newListener) | |
this.emit('newListener', type, | |
isFunction(listener.listener) ? | |
listener.listener : listener); | |
if (!this._events[type]) | |
// Optimize the case of one listener. Don't need the extra array object. | |
this._events[type] = listener; | |
else if (isObject(this._events[type])) | |
// If we've already got an array, just append. | |
this._events[type].push(listener); | |
else | |
// Adding the second element, need to change to array. | |
this._events[type] = [this._events[type], listener]; | |
// Check for listener leak | |
if (isObject(this._events[type]) && !this._events[type].warned) { | |
if (!isUndefined(this._maxListeners)) { | |
m = this._maxListeners; | |
} else { | |
m = EventEmitter.defaultMaxListeners; | |
} | |
if (m && m > 0 && this._events[type].length > m) { | |
this._events[type].warned = true; | |
console.error('(node) warning: possible EventEmitter memory ' + | |
'leak detected. %d listeners added. ' + | |
'Use emitter.setMaxListeners() to increase limit.', | |
this._events[type].length); | |
if (typeof console.trace === 'function') { | |
// not supported in IE 10 | |
console.trace(); | |
} | |
} | |
} | |
return this; | |
}; | |
EventEmitter.prototype.on = EventEmitter.prototype.addListener; | |
EventEmitter.prototype.once = function(type, listener) { | |
if (!isFunction(listener)) | |
throw TypeError('listener must be a function'); | |
var fired = false; | |
function g() { | |
this.removeListener(type, g); | |
if (!fired) { | |
fired = true; | |
listener.apply(this, arguments); | |
} | |
} | |
g.listener = listener; | |
this.on(type, g); | |
return this; | |
}; | |
// emits a 'removeListener' event iff the listener was removed | |
EventEmitter.prototype.removeListener = function(type, listener) { | |
var list, position, length, i; | |
if (!isFunction(listener)) | |
throw TypeError('listener must be a function'); | |
if (!this._events || !this._events[type]) | |
return this; | |
list = this._events[type]; | |
length = list.length; | |
position = -1; | |
if (list === listener || | |
(isFunction(list.listener) && list.listener === listener)) { | |
delete this._events[type]; | |
if (this._events.removeListener) | |
this.emit('removeListener', type, listener); | |
} else if (isObject(list)) { | |
for (i = length; i-- > 0;) { | |
if (list[i] === listener || | |
(list[i].listener && list[i].listener === listener)) { | |
position = i; | |
break; | |
} | |
} | |
if (position < 0) | |
return this; | |
if (list.length === 1) { | |
list.length = 0; | |
delete this._events[type]; | |
} else { | |
list.splice(position, 1); | |
} | |
if (this._events.removeListener) | |
this.emit('removeListener', type, listener); | |
} | |
return this; | |
}; | |
EventEmitter.prototype.removeAllListeners = function(type) { | |
var key, listeners; | |
if (!this._events) | |
return this; | |
// not listening for removeListener, no need to emit | |
if (!this._events.removeListener) { | |
if (arguments.length === 0) | |
this._events = {}; | |
else if (this._events[type]) | |
delete this._events[type]; | |
return this; | |
} | |
// emit removeListener for all listeners on all events | |
if (arguments.length === 0) { | |
for (key in this._events) { | |
if (key === 'removeListener') continue; | |
this.removeAllListeners(key); | |
} | |
this.removeAllListeners('removeListener'); | |
this._events = {}; | |
return this; | |
} | |
listeners = this._events[type]; | |
if (isFunction(listeners)) { | |
this.removeListener(type, listeners); | |
} else if (listeners) { | |
// LIFO order | |
while (listeners.length) | |
this.removeListener(type, listeners[listeners.length - 1]); | |
} | |
delete this._events[type]; | |
return this; | |
}; | |
EventEmitter.prototype.listeners = function(type) { | |
var ret; | |
if (!this._events || !this._events[type]) | |
ret = []; | |
else if (isFunction(this._events[type])) | |
ret = [this._events[type]]; | |
else | |
ret = this._events[type].slice(); | |
return ret; | |
}; | |
EventEmitter.prototype.listenerCount = function(type) { | |
if (this._events) { | |
var evlistener = this._events[type]; | |
if (isFunction(evlistener)) | |
return 1; | |
else if (evlistener) | |
return evlistener.length; | |
} | |
return 0; | |
}; | |
EventEmitter.listenerCount = function(emitter, type) { | |
return emitter.listenerCount(type); | |
}; | |
function isFunction(arg) { | |
return typeof arg === 'function'; | |
} | |
function isNumber(arg) { | |
return typeof arg === 'number'; | |
} | |
function isObject(arg) { | |
return typeof arg === 'object' && arg !== null; | |
} | |
function isUndefined(arg) { | |
return arg === void 0; | |
} | |
},{}],2:[function(require,module,exports){ | |
// shim for using process in browser | |
var process = module.exports = {}; | |
// cached from whatever global is present so that test runners that stub it | |
// don't break things. But we need to wrap it in a try catch in case it is | |
// wrapped in strict mode code which doesn't define any globals. It's inside a | |
// function because try/catches deoptimize in certain engines. | |
var cachedSetTimeout; | |
var cachedClearTimeout; | |
function defaultSetTimout() { | |
throw new Error('setTimeout has not been defined'); | |
} | |
function defaultClearTimeout () { | |
throw new Error('clearTimeout has not been defined'); | |
} | |
(function () { | |
try { | |
if (typeof setTimeout === 'function') { | |
cachedSetTimeout = setTimeout; | |
} else { | |
cachedSetTimeout = defaultSetTimout; | |
} | |
} catch (e) { | |
cachedSetTimeout = defaultSetTimout; | |
} | |
try { | |
if (typeof clearTimeout === 'function') { | |
cachedClearTimeout = clearTimeout; | |
} else { | |
cachedClearTimeout = defaultClearTimeout; | |
} | |
} catch (e) { | |
cachedClearTimeout = defaultClearTimeout; | |
} | |
} ()) | |
function runTimeout(fun) { | |
if (cachedSetTimeout === setTimeout) { | |
//normal enviroments in sane situations | |
return setTimeout(fun, 0); | |
} | |
// if setTimeout wasn't available but was latter defined | |
if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { | |
cachedSetTimeout = setTimeout; | |
return setTimeout(fun, 0); | |
} | |
try { | |
// when when somebody has screwed with setTimeout but no I.E. maddness | |
return cachedSetTimeout(fun, 0); | |
} catch(e){ | |
try { | |
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally | |
return cachedSetTimeout.call(null, fun, 0); | |
} catch(e){ | |
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error | |
return cachedSetTimeout.call(this, fun, 0); | |
} | |
} | |
} | |
function runClearTimeout(marker) { | |
if (cachedClearTimeout === clearTimeout) { | |
//normal enviroments in sane situations | |
return clearTimeout(marker); | |
} | |
// if clearTimeout wasn't available but was latter defined | |
if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { | |
cachedClearTimeout = clearTimeout; | |
return clearTimeout(marker); | |
} | |
try { | |
// when when somebody has screwed with setTimeout but no I.E. maddness | |
return cachedClearTimeout(marker); | |
} catch (e){ | |
try { | |
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally | |
return cachedClearTimeout.call(null, marker); | |
} catch (e){ | |
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. | |
// Some versions of I.E. have different rules for clearTimeout vs setTimeout | |
return cachedClearTimeout.call(this, marker); | |
} | |
} | |
} | |
var queue = []; | |
var draining = false; | |
var currentQueue; | |
var queueIndex = -1; | |
function cleanUpNextTick() { | |
if (!draining || !currentQueue) { | |
return; | |
} | |
draining = false; | |
if (currentQueue.length) { | |
queue = currentQueue.concat(queue); | |
} else { | |
queueIndex = -1; | |
} | |
if (queue.length) { | |
drainQueue(); | |
} | |
} | |
function drainQueue() { | |
if (draining) { | |
return; | |
} | |
var timeout = runTimeout(cleanUpNextTick); | |
draining = true; | |
var len = queue.length; | |
while(len) { | |
currentQueue = queue; | |
queue = []; | |
while (++queueIndex < len) { | |
if (currentQueue) { | |
currentQueue[queueIndex].run(); | |
} | |
} | |
queueIndex = -1; | |
len = queue.length; | |
} | |
currentQueue = null; | |
draining = false; | |
runClearTimeout(timeout); | |
} | |
process.nextTick = function (fun) { | |
var args = new Array(arguments.length - 1); | |
if (arguments.length > 1) { | |
for (var i = 1; i < arguments.length; i++) { | |
args[i - 1] = arguments[i]; | |
} | |
} | |
queue.push(new Item(fun, args)); | |
if (queue.length === 1 && !draining) { | |
runTimeout(drainQueue); | |
} | |
}; | |
// v8 likes predictible objects | |
function Item(fun, array) { | |
this.fun = fun; | |
this.array = array; | |
} | |
Item.prototype.run = function () { | |
this.fun.apply(null, this.array); | |
}; | |
process.title = 'browser'; | |
process.browser = true; | |
process.env = {}; | |
process.argv = []; | |
process.version = ''; // empty string to avoid regexp issues | |
process.versions = {}; | |
function noop() {} | |
process.on = noop; | |
process.addListener = noop; | |
process.once = noop; | |
process.off = noop; | |
process.removeListener = noop; | |
process.removeAllListeners = noop; | |
process.emit = noop; | |
process.binding = function (name) { | |
throw new Error('process.binding is not supported'); | |
}; | |
process.cwd = function () { return '/' }; | |
process.chdir = function (dir) { | |
throw new Error('process.chdir is not supported'); | |
}; | |
process.umask = function() { return 0; }; | |
},{}],3:[function(require,module,exports){ | |
if (typeof Object.create === 'function') { | |
// implementation from standard node.js 'util' module | |
module.exports = function inherits(ctor, superCtor) { | |
ctor.super_ = superCtor | |
ctor.prototype = Object.create(superCtor.prototype, { | |
constructor: { | |
value: ctor, | |
enumerable: false, | |
writable: true, | |
configurable: true | |
} | |
}); | |
}; | |
} else { | |
// old school shim for old browsers | |
module.exports = function inherits(ctor, superCtor) { | |
ctor.super_ = superCtor | |
var TempCtor = function () {} | |
TempCtor.prototype = superCtor.prototype | |
ctor.prototype = new TempCtor() | |
ctor.prototype.constructor = ctor | |
} | |
} | |
},{}],4:[function(require,module,exports){ | |
module.exports = function isBuffer(arg) { | |
return arg && typeof arg === 'object' | |
&& typeof arg.copy === 'function' | |
&& typeof arg.fill === 'function' | |
&& typeof arg.readUInt8 === 'function'; | |
} | |
},{}],5:[function(require,module,exports){ | |
(function (process,global){ | |
// Copyright Joyent, Inc. and other Node contributors. | |
// | |
// Permission is hereby granted, free of charge, to any person obtaining a | |
// copy of this software and associated documentation files (the | |
// "Software"), to deal in the Software without restriction, including | |
// without limitation the rights to use, copy, modify, merge, publish, | |
// distribute, sublicense, and/or sell copies of the Software, and to permit | |
// persons to whom the Software is furnished to do so, subject to the | |
// following conditions: | |
// | |
// The above copyright notice and this permission notice shall be included | |
// in all copies or substantial portions of the Software. | |
// | |
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN | |
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, | |
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | |
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | |
// USE OR OTHER DEALINGS IN THE SOFTWARE. | |
var formatRegExp = /%[sdj%]/g; | |
exports.format = function(f) { | |
if (!isString(f)) { | |
var objects = []; | |
for (var i = 0; i < arguments.length; i++) { | |
objects.push(inspect(arguments[i])); | |
} | |
return objects.join(' '); | |
} | |
var i = 1; | |
var args = arguments; | |
var len = args.length; | |
var str = String(f).replace(formatRegExp, function(x) { | |
if (x === '%%') return '%'; | |
if (i >= len) return x; | |
switch (x) { | |
case '%s': return String(args[i++]); | |
case '%d': return Number(args[i++]); | |
case '%j': | |
try { | |
return JSON.stringify(args[i++]); | |
} catch (_) { | |
return '[Circular]'; | |
} | |
default: | |
return x; | |
} | |
}); | |
for (var x = args[i]; i < len; x = args[++i]) { | |
if (isNull(x) || !isObject(x)) { | |
str += ' ' + x; | |
} else { | |
str += ' ' + inspect(x); | |
} | |
} | |
return str; | |
}; | |
// Mark that a method should not be used. | |
// Returns a modified function which warns once by default. | |
// If --no-deprecation is set, then it is a no-op. | |
exports.deprecate = function(fn, msg) { | |
// Allow for deprecating things in the process of starting up. | |
if (isUndefined(global.process)) { | |
return function() { | |
return exports.deprecate(fn, msg).apply(this, arguments); | |
}; | |
} | |
if (process.noDeprecation === true) { | |
return fn; | |
} | |
var warned = false; | |
function deprecated() { | |
if (!warned) { | |
if (process.throwDeprecation) { | |
throw new Error(msg); | |
} else if (process.traceDeprecation) { | |
console.trace(msg); | |
} else { | |
console.error(msg); | |
} | |
warned = true; | |
} | |
return fn.apply(this, arguments); | |
} | |
return deprecated; | |
}; | |
var debugs = {}; | |
var debugEnviron; | |
exports.debuglog = function(set) { | |
if (isUndefined(debugEnviron)) | |
debugEnviron = process.env.NODE_DEBUG || ''; | |
set = set.toUpperCase(); | |
if (!debugs[set]) { | |
if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { | |
var pid = process.pid; | |
debugs[set] = function() { | |
var msg = exports.format.apply(exports, arguments); | |
console.error('%s %d: %s', set, pid, msg); | |
}; | |
} else { | |
debugs[set] = function() {}; | |
} | |
} | |
return debugs[set]; | |
}; | |
/** | |
* Echos the value of a value. Trys to print the value out | |
* in the best way possible given the different types. | |
* | |
* @param {Object} obj The object to print out. | |
* @param {Object} opts Optional options object that alters the output. | |
*/ | |
/* legacy: obj, showHidden, depth, colors*/ | |
function inspect(obj, opts) { | |
// default options | |
var ctx = { | |
seen: [], | |
stylize: stylizeNoColor | |
}; | |
// legacy... | |
if (arguments.length >= 3) ctx.depth = arguments[2]; | |
if (arguments.length >= 4) ctx.colors = arguments[3]; | |
if (isBoolean(opts)) { | |
// legacy... | |
ctx.showHidden = opts; | |
} else if (opts) { | |
// got an "options" object | |
exports._extend(ctx, opts); | |
} | |
// set default options | |
if (isUndefined(ctx.showHidden)) ctx.showHidden = false; | |
if (isUndefined(ctx.depth)) ctx.depth = 2; | |
if (isUndefined(ctx.colors)) ctx.colors = false; | |
if (isUndefined(ctx.customInspect)) ctx.customInspect = true; | |
if (ctx.colors) ctx.stylize = stylizeWithColor; | |
return formatValue(ctx, obj, ctx.depth); | |
} | |
exports.inspect = inspect; | |
// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics | |
inspect.colors = { | |
'bold' : [1, 22], | |
'italic' : [3, 23], | |
'underline' : [4, 24], | |
'inverse' : [7, 27], | |
'white' : [37, 39], | |
'grey' : [90, 39], | |
'black' : [30, 39], | |
'blue' : [34, 39], | |
'cyan' : [36, 39], | |
'green' : [32, 39], | |
'magenta' : [35, 39], | |
'red' : [31, 39], | |
'yellow' : [33, 39] | |
}; | |
// Don't use 'blue' not visible on cmd.exe | |
inspect.styles = { | |
'special': 'cyan', | |
'number': 'yellow', | |
'boolean': 'yellow', | |
'undefined': 'grey', | |
'null': 'bold', | |
'string': 'green', | |
'date': 'magenta', | |
// "name": intentionally not styling | |
'regexp': 'red' | |
}; | |
function stylizeWithColor(str, styleType) { | |
var style = inspect.styles[styleType]; | |
if (style) { | |
return '\u001b[' + inspect.colors[style][0] + 'm' + str + | |
'\u001b[' + inspect.colors[style][1] + 'm'; | |
} else { | |
return str; | |
} | |
} | |
function stylizeNoColor(str, styleType) { | |
return str; | |
} | |
function arrayToHash(array) { | |
var hash = {}; | |
array.forEach(function(val, idx) { | |
hash[val] = true; | |
}); | |
return hash; | |
} | |
function formatValue(ctx, value, recurseTimes) { | |
// Provide a hook for user-specified inspect functions. | |
// Check that value is an object with an inspect function on it | |
if (ctx.customInspect && | |
value && | |
isFunction(value.inspect) && | |
// Filter out the util module, it's inspect function is special | |
value.inspect !== exports.inspect && | |
// Also filter out any prototype objects using the circular check. | |
!(value.constructor && value.constructor.prototype === value)) { | |
var ret = value.inspect(recurseTimes, ctx); | |
if (!isString(ret)) { | |
ret = formatValue(ctx, ret, recurseTimes); | |
} | |
return ret; | |
} | |
// Primitive types cannot have properties | |
var primitive = formatPrimitive(ctx, value); | |
if (primitive) { | |
return primitive; | |
} | |
// Look up the keys of the object. | |
var keys = Object.keys(value); | |
var visibleKeys = arrayToHash(keys); | |
if (ctx.showHidden) { | |
keys = Object.getOwnPropertyNames(value); | |
} | |
// IE doesn't make error fields non-enumerable | |
// http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx | |
if (isError(value) | |
&& (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { | |
return formatError(value); | |
} | |
// Some type of object without properties can be shortcutted. | |
if (keys.length === 0) { | |
if (isFunction(value)) { | |
var name = value.name ? ': ' + value.name : ''; | |
return ctx.stylize('[Function' + name + ']', 'special'); | |
} | |
if (isRegExp(value)) { | |
return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); | |
} | |
if (isDate(value)) { | |
return ctx.stylize(Date.prototype.toString.call(value), 'date'); | |
} | |
if (isError(value)) { | |
return formatError(value); | |
} | |
} | |
var base = '', array = false, braces = ['{', '}']; | |
// Make Array say that they are Array | |
if (isArray(value)) { | |
array = true; | |
braces = ['[', ']']; | |
} | |
// Make functions say that they are functions | |
if (isFunction(value)) { | |
var n = value.name ? ': ' + value.name : ''; | |
base = ' [Function' + n + ']'; | |
} | |
// Make RegExps say that they are RegExps | |
if (isRegExp(value)) { | |
base = ' ' + RegExp.prototype.toString.call(value); | |
} | |
// Make dates with properties first say the date | |
if (isDate(value)) { | |
base = ' ' + Date.prototype.toUTCString.call(value); | |
} | |
// Make error with message first say the error | |
if (isError(value)) { | |
base = ' ' + formatError(value); | |
} | |
if (keys.length === 0 && (!array || value.length == 0)) { | |
return braces[0] + base + braces[1]; | |
} | |
if (recurseTimes < 0) { | |
if (isRegExp(value)) { | |
return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); | |
} else { | |
return ctx.stylize('[Object]', 'special'); | |
} | |
} | |
ctx.seen.push(value); | |
var output; | |
if (array) { | |
output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); | |
} else { | |
output = keys.map(function(key) { | |
return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); | |
}); | |
} | |
ctx.seen.pop(); | |
return reduceToSingleString(output, base, braces); | |
} | |
function formatPrimitive(ctx, value) { | |
if (isUndefined(value)) | |
return ctx.stylize('undefined', 'undefined'); | |
if (isString(value)) { | |
var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') | |
.replace(/'/g, "\\'") | |
.replace(/\\"/g, '"') + '\''; | |
return ctx.stylize(simple, 'string'); | |
} | |
if (isNumber(value)) | |
return ctx.stylize('' + value, 'number'); | |
if (isBoolean(value)) | |
return ctx.stylize('' + value, 'boolean'); | |
// For some reason typeof null is "object", so special case here. | |
if (isNull(value)) | |
return ctx.stylize('null', 'null'); | |
} | |
function formatError(value) { | |
return '[' + Error.prototype.toString.call(value) + ']'; | |
} | |
function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { | |
var output = []; | |
for (var i = 0, l = value.length; i < l; ++i) { | |
if (hasOwnProperty(value, String(i))) { | |
output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, | |
String(i), true)); | |
} else { | |
output.push(''); | |
} | |
} | |
keys.forEach(function(key) { | |
if (!key.match(/^\d+$/)) { | |
output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, | |
key, true)); | |
} | |
}); | |
return output; | |
} | |
function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { | |
var name, str, desc; | |
desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; | |
if (desc.get) { | |
if (desc.set) { | |
str = ctx.stylize('[Getter/Setter]', 'special'); | |
} else { | |
str = ctx.stylize('[Getter]', 'special'); | |
} | |
} else { | |
if (desc.set) { | |
str = ctx.stylize('[Setter]', 'special'); | |
} | |
} | |
if (!hasOwnProperty(visibleKeys, key)) { | |
name = '[' + key + ']'; | |
} | |
if (!str) { | |
if (ctx.seen.indexOf(desc.value) < 0) { | |
if (isNull(recurseTimes)) { | |
str = formatValue(ctx, desc.value, null); | |
} else { | |
str = formatValue(ctx, desc.value, recurseTimes - 1); | |
} | |
if (str.indexOf('\n') > -1) { | |
if (array) { | |
str = str.split('\n').map(function(line) { | |
return ' ' + line; | |
}).join('\n').substr(2); | |
} else { | |
str = '\n' + str.split('\n').map(function(line) { | |
return ' ' + line; | |
}).join('\n'); | |
} | |
} | |
} else { | |
str = ctx.stylize('[Circular]', 'special'); | |
} | |
} | |
if (isUndefined(name)) { | |
if (array && key.match(/^\d+$/)) { | |
return str; | |
} | |
name = JSON.stringify('' + key); | |
if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { | |
name = name.substr(1, name.length - 2); | |
name = ctx.stylize(name, 'name'); | |
} else { | |
name = name.replace(/'/g, "\\'") | |
.replace(/\\"/g, '"') | |
.replace(/(^"|"$)/g, "'"); | |
name = ctx.stylize(name, 'string'); | |
} | |
} | |
return name + ': ' + str; | |
} | |
function reduceToSingleString(output, base, braces) { | |
var numLinesEst = 0; | |
var length = output.reduce(function(prev, cur) { | |
numLinesEst++; | |
if (cur.indexOf('\n') >= 0) numLinesEst++; | |
return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; | |
}, 0); | |
if (length > 60) { | |
return braces[0] + | |
(base === '' ? '' : base + '\n ') + | |
' ' + | |
output.join(',\n ') + | |
' ' + | |
braces[1]; | |
} | |
return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; | |
} | |
// NOTE: These type checking functions intentionally don't use `instanceof` | |
// because it is fragile and can be easily faked with `Object.create()`. | |
function isArray(ar) { | |
return Array.isArray(ar); | |
} | |
exports.isArray = isArray; | |
function isBoolean(arg) { | |
return typeof arg === 'boolean'; | |
} | |
exports.isBoolean = isBoolean; | |
function isNull(arg) { | |
return arg === null; | |
} | |
exports.isNull = isNull; | |
function isNullOrUndefined(arg) { | |
return arg == null; | |
} | |
exports.isNullOrUndefined = isNullOrUndefined; | |
function isNumber(arg) { | |
return typeof arg === 'number'; | |
} | |
exports.isNumber = isNumber; | |
function isString(arg) { | |
return typeof arg === 'string'; | |
} | |
exports.isString = isString; | |
function isSymbol(arg) { | |
return typeof arg === 'symbol'; | |
} | |
exports.isSymbol = isSymbol; | |
function isUndefined(arg) { | |
return arg === void 0; | |
} | |
exports.isUndefined = isUndefined; | |
function isRegExp(re) { | |
return isObject(re) && objectToString(re) === '[object RegExp]'; | |
} | |
exports.isRegExp = isRegExp; | |
function isObject(arg) { | |
return typeof arg === 'object' && arg !== null; | |
} | |
exports.isObject = isObject; | |
function isDate(d) { | |
return isObject(d) && objectToString(d) === '[object Date]'; | |
} | |
exports.isDate = isDate; | |
function isError(e) { | |
return isObject(e) && | |
(objectToString(e) === '[object Error]' || e instanceof Error); | |
} | |
exports.isError = isError; | |
function isFunction(arg) { | |
return typeof arg === 'function'; | |
} | |
exports.isFunction = isFunction; | |
function isPrimitive(arg) { | |
return arg === null || | |
typeof arg === 'boolean' || | |
typeof arg === 'number' || | |
typeof arg === 'string' || | |
typeof arg === 'symbol' || // ES6 symbol | |
typeof arg === 'undefined'; | |
} | |
exports.isPrimitive = isPrimitive; | |
exports.isBuffer = require('./support/isBuffer'); | |
function objectToString(o) { | |
return Object.prototype.toString.call(o); | |
} | |
function pad(n) { | |
return n < 10 ? '0' + n.toString(10) : n.toString(10); | |
} | |
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', | |
'Oct', 'Nov', 'Dec']; | |
// 26 Feb 16:19:34 | |
function timestamp() { | |
var d = new Date(); | |
var time = [pad(d.getHours()), | |
pad(d.getMinutes()), | |
pad(d.getSeconds())].join(':'); | |
return [d.getDate(), months[d.getMonth()], time].join(' '); | |
} | |
// log is just a thin wrapper to console.log that prepends a timestamp | |
exports.log = function() { | |
console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); | |
}; | |
/** | |
* Inherit the prototype methods from one constructor into another. | |
* | |
* The Function.prototype.inherits from lang.js rewritten as a standalone | |
* function (not on Function.prototype). NOTE: If this file is to be loaded | |
* during bootstrapping this function needs to be rewritten using some native | |
* functions as prototype setup using normal JavaScript does not work as | |
* expected during bootstrapping (see mirror.js in r114903). | |
* | |
* @param {function} ctor Constructor function which needs to inherit the | |
* prototype. | |
* @param {function} superCtor Constructor function to inherit prototype from. | |
*/ | |
exports.inherits = require('inherits'); | |
exports._extend = function(origin, add) { | |
// Don't do anything if add isn't an object | |
if (!add || !isObject(add)) return origin; | |
var keys = Object.keys(add); | |
var i = keys.length; | |
while (i--) { | |
origin[keys[i]] = add[keys[i]]; | |
} | |
return origin; | |
}; | |
function hasOwnProperty(obj, prop) { | |
return Object.prototype.hasOwnProperty.call(obj, prop); | |
} | |
}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) | |
},{"./support/isBuffer":4,"_process":2,"inherits":3}],"acorn":[function(require,module,exports){ | |
(function (global, factory) { | |
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : | |
typeof define === 'function' && define.amd ? define(['exports'], factory) : | |
(factory((global.acorn = global.acorn || {}))); | |
}(this, (function (exports) { 'use strict'; | |
// Reserved word lists for various dialects of the language | |
var reservedWords = { | |
3: "abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized throws transient volatile", | |
5: "class enum extends super const export import", | |
6: "enum", | |
strict: "implements interface let package private protected public static yield", | |
strictBind: "eval arguments" | |
} | |
// And the keywords | |
var ecma5AndLessKeywords = "break case catch continue debugger default do else finally for function if return switch throw try var while with null true false instanceof typeof void delete new in this" | |
var keywords = { | |
5: ecma5AndLessKeywords, | |
6: ecma5AndLessKeywords + " const class extends export import super" | |
} | |
// ## Character categories | |
// Big ugly regular expressions that match characters in the | |
// whitespace, identifier, and identifier-start categories. These | |
// are only applied when a character is found to actually have a | |
// code point above 128. | |
// Generated by `bin/generate-identifier-regex.js`. | |
var nonASCIIidentifierStartChars = "\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u037f\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u052f\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-\u0858\u08a0-\u08b4\u08b6-\u08bd\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0af9\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c39\u0c3d\u0c58-\u0c5a\u0c60\u0c61\u0c80\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d54-\u0d56\u0d5f-\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f5\u13f8-\u13fd\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f8\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191e\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1c80-\u1c88\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2118-\u211d\u2124\u2126\u2128\u212a-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309b-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fd5\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua69d\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua7ae\ua7b0-\ua7b7\ua7f7-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua8fd\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\ua9e0-\ua9e4\ua9e6-\ua9ef\ua9fa-\ua9fe\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa7e-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uab30-\uab5a\uab5c-\uab65\uab70-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc" | |
var nonASCIIidentifierChars = "\u200c\u200d\xb7\u0300-\u036f\u0387\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u0669\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7\u06e8\u06ea-\u06ed\u06f0-\u06f9\u0711\u0730-\u074a\u07a6-\u07b0\u07c0-\u07c9\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u08d4-\u08e1\u08e3-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09cb-\u09cd\u09d7\u09e2\u09e3\u09e6-\u09ef\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c00-\u0c03\u0c3e-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0c66-\u0c6f\u0c81-\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0ce6-\u0cef\u0d01-\u0d03\u0d3e-\u0d44\u0d46-\u0d48\u0d4a-\u0d4d\u0d57\u0d62\u0d63\u0d66-\u0d6f\u0d82\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0de6-\u0def\u0df2\u0df3\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0e50-\u0e59\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e\u0f3f\u0f71-\u0f84\u0f86\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u102b-\u103e\u1040-\u1049\u1056-\u1059\u105e-\u1060\u1062-\u1064\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u1369-\u1371\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b4-\u17d3\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u18a9\u1920-\u192b\u1930-\u193b\u1946-\u194f\u19d0-\u19da\u1a17-\u1a1b\u1a55-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1ab0-\u1abd\u1b00-\u1b04\u1b34-\u1b44\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1b82\u1ba1-\u1bad\u1bb0-\u1bb9\u1be6-\u1bf3\u1c24-\u1c37\u1c40-\u1c49\u1c50-\u1c59\u1cd0-\u1cd2\u1cd4-\u1ce8\u1ced\u1cf2-\u1cf4\u1cf8\u1cf9\u1dc0-\u1df5\u1dfb-\u1dff\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2cef-\u2cf1\u2d7f\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua620-\ua629\ua66f\ua674-\ua67d\ua69e\ua69f\ua6f0\ua6f1\ua802\ua806\ua80b\ua823-\ua827\ua880\ua881\ua8b4-\ua8c5\ua8d0-\ua8d9\ua8e0-\ua8f1\ua900-\ua909\ua926-\ua92d\ua947-\ua953\ua980-\ua983\ua9b3-\ua9c0\ua9d0-\ua9d9\ua9e5\ua9f0-\ua9f9\uaa29-\uaa36\uaa43\uaa4c\uaa4d\uaa50-\uaa59\uaa7b-\uaa7d\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uaaeb-\uaaef\uaaf5\uaaf6\uabe3-\uabea\uabec\uabed\uabf0-\uabf9\ufb1e\ufe00-\ufe0f\ufe20-\ufe2f\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f" | |
var nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]") | |
var nonASCIIidentifier = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]") | |
nonASCIIidentifierStartChars = nonASCIIidentifierChars = null | |
// These are a run-length and offset encoded representation of the | |
// >0xffff code points that are a valid part of identifiers. The | |
// offset starts at 0x10000, and each pair of numbers represents an | |
// offset to the next range, and then a size of the range. They were | |
// generated by bin/generate-identifier-regex.js | |
var astralIdentifierStartCodes = [0,11,2,25,2,18,2,1,2,14,3,13,35,122,70,52,268,28,4,48,48,31,17,26,6,37,11,29,3,35,5,7,2,4,43,157,19,35,5,35,5,39,9,51,157,310,10,21,11,7,153,5,3,0,2,43,2,1,4,0,3,22,11,22,10,30,66,18,2,1,11,21,11,25,71,55,7,1,65,0,16,3,2,2,2,26,45,28,4,28,36,7,2,27,28,53,11,21,11,18,14,17,111,72,56,50,14,50,785,52,76,44,33,24,27,35,42,34,4,0,13,47,15,3,22,0,2,0,36,17,2,24,85,6,2,0,2,3,2,14,2,9,8,46,39,7,3,1,3,21,2,6,2,1,2,4,4,0,19,0,13,4,159,52,19,3,54,47,21,1,2,0,185,46,42,3,37,47,21,0,60,42,86,25,391,63,32,0,449,56,264,8,2,36,18,0,50,29,881,921,103,110,18,195,2749,1070,4050,582,8634,568,8,30,114,29,19,47,17,3,32,20,6,18,881,68,12,0,67,12,65,0,32,6124,20,754,9486,1,3071,106,6,12,4,8,8,9,5991,84,2,70,2,1,3,0,3,1,3,3,2,11,2,0,2,6,2,64,2,3,3,7,2,6,2,27,2,3,2,4,2,0,4,6,2,339,3,24,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,7,4149,196,60,67,1213,3,2,26,2,1,2,0,3,0,2,9,2,3,2,0,2,0,7,0,5,0,2,0,2,0,2,2,2,1,2,0,3,0,2,0,2,0,2,0,2,0,2,1,2,0,3,3,2,6,2,3,2,3,2,0,2,9,2,16,6,2,2,4,2,16,4421,42710,42,4148,12,221,3,5761,10591,541] | |
var astralIdentifierCodes = [509,0,227,0,150,4,294,9,1368,2,2,1,6,3,41,2,5,0,166,1,1306,2,54,14,32,9,16,3,46,10,54,9,7,2,37,13,2,9,52,0,13,2,49,13,10,2,4,9,83,11,7,0,161,11,6,9,7,3,57,0,2,6,3,1,3,2,10,0,11,1,3,6,4,4,193,17,10,9,87,19,13,9,214,6,3,8,28,1,83,16,16,9,82,12,9,9,84,14,5,9,423,9,838,7,2,7,17,9,57,21,2,13,19882,9,135,4,60,6,26,9,1016,45,17,3,19723,1,5319,4,4,5,9,7,3,6,31,3,149,2,1418,49,513,54,5,49,9,0,15,0,23,4,2,14,1361,6,2,16,3,6,2,1,2,4,2214,6,110,6,6,9,792487,239] | |
// This has a complexity linear to the value of the code. The | |
// assumption is that looking up astral identifier characters is | |
// rare. | |
function isInAstralSet(code, set) { | |
var pos = 0x10000 | |
for (var i = 0; i < set.length; i += 2) { | |
pos += set[i] | |
if (pos > code) return false | |
pos += set[i + 1] | |
if (pos >= code) return true | |
} | |
} | |
// Test whether a given character code starts an identifier. | |
function isIdentifierStart(code, astral) { | |
if (code < 65) return code === 36 | |
if (code < 91) return true | |
if (code < 97) return code === 95 | |
if (code < 123) return true | |
if (code <= 0xffff) return code >= 0xaa && nonASCIIidentifierStart.test(String.fromCharCode(code)) | |
if (astral === false) return false | |
return isInAstralSet(code, astralIdentifierStartCodes) | |
} | |
// Test whether a given character is part of an identifier. | |
function isIdentifierChar(code, astral) { | |
if (code < 48) return code === 36 | |
if (code < 58) return true | |
if (code < 65) return false | |
if (code < 91) return true | |
if (code < 97) return code === 95 | |
if (code < 123) return true | |
if (code <= 0xffff) return code >= 0xaa && nonASCIIidentifier.test(String.fromCharCode(code)) | |
if (astral === false) return false | |
return isInAstralSet(code, astralIdentifierStartCodes) || isInAstralSet(code, astralIdentifierCodes) | |
} | |
// ## Token types | |
// The assignment of fine-grained, information-carrying type objects | |
// allows the tokenizer to store the information it has about a | |
// token in a way that is very cheap for the parser to look up. | |
// All token type variables start with an underscore, to make them | |
// easy to recognize. | |
// The `beforeExpr` property is used to disambiguate between regular | |
// expressions and divisions. It is set on all token types that can | |
// be followed by an expression (thus, a slash after them would be a | |
// regular expression). | |
// | |
// The `startsExpr` property is used to check if the token ends a | |
// `yield` expression. It is set on all token types that either can | |
// directly start an expression (like a quotation mark) or can | |
// continue an expression (like the body of a string). | |
// | |
// `isLoop` marks a keyword as starting a loop, which is important | |
// to know when parsing a label, in order to allow or disallow | |
// continue jumps to that label. | |
var TokenType = function TokenType(label, conf) { | |
if ( conf === void 0 ) conf = {}; | |
this.label = label | |
this.keyword = conf.keyword | |
this.beforeExpr = !!conf.beforeExpr | |
this.startsExpr = !!conf.startsExpr | |
this.isLoop = !!conf.isLoop | |
this.isAssign = !!conf.isAssign | |
this.prefix = !!conf.prefix | |
this.postfix = !!conf.postfix | |
this.binop = conf.binop || null | |
this.updateContext = null | |
}; | |
function binop(name, prec) { | |
return new TokenType(name, {beforeExpr: true, binop: prec}) | |
} | |
var beforeExpr = {beforeExpr: true}; | |
var startsExpr = {startsExpr: true}; | |
// Map keyword names to token types. | |
var keywordTypes = {} | |
// Succinct definitions of keyword token types | |
function kw(name, options) { | |
if ( options === void 0 ) options = {}; | |
options.keyword = name | |
return keywordTypes[name] = new TokenType(name, options) | |
} | |
var tt = { | |
num: new TokenType("num", startsExpr), | |
regexp: new TokenType("regexp", startsExpr), | |
string: new TokenType("string", startsExpr), | |
name: new TokenType("name", startsExpr), | |
eof: new TokenType("eof"), | |
// Punctuation token types. | |
bracketL: new TokenType("[", {beforeExpr: true, startsExpr: true}), | |
bracketR: new TokenType("]"), | |
braceL: new TokenType("{", {beforeExpr: true, startsExpr: true}), | |
braceR: new TokenType("}"), | |
parenL: new TokenType("(", {beforeExpr: true, startsExpr: true}), | |
parenR: new TokenType(")"), | |
comma: new TokenType(",", beforeExpr), | |
semi: new TokenType(";", beforeExpr), | |
colon: new TokenType(":", beforeExpr), | |
dot: new TokenType("."), | |
question: new TokenType("?", beforeExpr), | |
arrow: new TokenType("=>", beforeExpr), | |
template: new TokenType("template"), | |
ellipsis: new TokenType("...", beforeExpr), | |
backQuote: new TokenType("`", startsExpr), | |
dollarBraceL: new TokenType("${", {beforeExpr: true, startsExpr: true}), | |
// Operators. These carry several kinds of properties to help the | |
// parser use them properly (the presence of these properties is | |
// what categorizes them as operators). | |
// | |
// `binop`, when present, specifies that this operator is a binary | |
// operator, and will refer to its precedence. | |
// | |
// `prefix` and `postfix` mark the operator as a prefix or postfix | |
// unary operator. | |
// | |
// `isAssign` marks all of `=`, `+=`, `-=` etcetera, which act as | |
// binary operators with a very low precedence, that should result | |
// in AssignmentExpression nodes. | |
eq: new TokenType("=", {beforeExpr: true, isAssign: true}), | |
assign: new TokenType("_=", {beforeExpr: true, isAssign: true}), | |
incDec: new TokenType("++/--", {prefix: true, postfix: true, startsExpr: true}), | |
prefix: new TokenType("prefix", {beforeExpr: true, prefix: true, startsExpr: true}), | |
logicalOR: binop("||", 1), | |
logicalAND: binop("&&", 2), | |
bitwiseOR: binop("|", 3), | |
bitwiseXOR: binop("^", 4), | |
bitwiseAND: binop("&", 5), | |
equality: binop("==/!=", 6), | |
relational: binop("</>", 7), | |
bitShift: binop("<</>>", 8), | |
plusMin: new TokenType("+/-", {beforeExpr: true, binop: 9, prefix: true, startsExpr: true}), | |
modulo: binop("%", 10), | |
star: binop("*", 10), | |
slash: binop("/", 10), | |
starstar: new TokenType("**", {beforeExpr: true}), | |
// Keyword token types. | |
_break: kw("break"), | |
_case: kw("case", beforeExpr), | |
_catch: kw("catch"), | |
_continue: kw("continue"), | |
_debugger: kw("debugger"), | |
_default: kw("default", beforeExpr), | |
_do: kw("do", {isLoop: true, beforeExpr: true}), | |
_else: kw("else", beforeExpr), | |
_finally: kw("finally"), | |
_for: kw("for", {isLoop: true}), | |
_function: kw("function", startsExpr), | |
_if: kw("if"), | |
_return: kw("return", beforeExpr), | |
_switch: kw("switch"), | |
_throw: kw("throw", beforeExpr), | |
_try: kw("try"), | |
_var: kw("var"), | |
_const: kw("const"), | |
_while: kw("while", {isLoop: true}), | |
_with: kw("with"), | |
_new: kw("new", {beforeExpr: true, startsExpr: true}), | |
_this: kw("this", startsExpr), | |
_super: kw("super", startsExpr), | |
_class: kw("class"), | |
_extends: kw("extends", beforeExpr), | |
_export: kw("export"), | |
_import: kw("import"), | |
_null: kw("null", startsExpr), | |
_true: kw("true", startsExpr), | |
_false: kw("false", startsExpr), | |
_in: kw("in", {beforeExpr: true, binop: 7}), | |
_instanceof: kw("instanceof", {beforeExpr: true, binop: 7}), | |
_typeof: kw("typeof", {beforeExpr: true, prefix: true, startsExpr: true}), | |
_void: kw("void", {beforeExpr: true, prefix: true, startsExpr: true}), | |
_delete: kw("delete", {beforeExpr: true, prefix: true, startsExpr: true}) | |
} | |
// Matches a whole line break (where CRLF is considered a single | |
// line break). Used to count lines. | |
var lineBreak = /\r\n?|\n|\u2028|\u2029/ | |
var lineBreakG = new RegExp(lineBreak.source, "g") | |
function isNewLine(code) { | |
return code === 10 || code === 13 || code === 0x2028 || code === 0x2029 | |
} | |
var nonASCIIwhitespace = /[\u1680\u180e\u2000-\u200a\u202f\u205f\u3000\ufeff]/ | |
var skipWhiteSpace = /(?:\s|\/\/.*|\/\*[^]*?\*\/)*/g | |
function isArray(obj) { | |
return Object.prototype.toString.call(obj) === "[object Array]" | |
} | |
// Checks if an object has a property. | |
function has(obj, propName) { | |
return Object.prototype.hasOwnProperty.call(obj, propName) | |
} | |
// These are used when `options.locations` is on, for the | |
// `startLoc` and `endLoc` properties. | |
var Position = function Position(line, col) { | |
this.line = line | |
this.column = col | |
}; | |
Position.prototype.offset = function offset (n) { | |
return new Position(this.line, this.column + n) | |
}; | |
var SourceLocation = function SourceLocation(p, start, end) { | |
this.start = start | |
this.end = end | |
if (p.sourceFile !== null) this.source = p.sourceFile | |
}; | |
// The `getLineInfo` function is mostly useful when the | |
// `locations` option is off (for performance reasons) and you | |
// want to find the line/column position for a given character | |
// offset. `input` should be the code string that the offset refers | |
// into. | |
function getLineInfo(input, offset) { | |
for (var line = 1, cur = 0;;) { | |
lineBreakG.lastIndex = cur | |
var match = lineBreakG.exec(input) | |
if (match && match.index < offset) { | |
++line | |
cur = match.index + match[0].length | |
} else { | |
return new Position(line, offset - cur) | |
} | |
} | |
} | |
// A second optional argument can be given to further configure | |
// the parser process. These options are recognized: | |
var defaultOptions = { | |
// `ecmaVersion` indicates the ECMAScript version to parse. Must | |
// be either 3, 5, 6 (2015), 7 (2016), or 8 (2017). This influences support | |
// for strict mode, the set of reserved words, and support for | |
// new syntax features. The default is 7. | |
ecmaVersion: 7, | |
// `sourceType` indicates the mode the code should be parsed in. | |
// Can be either `"script"` or `"module"`. This influences global | |
// strict mode and parsing of `import` and `export` declarations. | |
sourceType: "script", | |
// `onInsertedSemicolon` can be a callback that will be called | |
// when a semicolon is automatically inserted. It will be passed | |
// th position of the comma as an offset, and if `locations` is | |
// enabled, it is given the location as a `{line, column}` object | |
// as second argument. | |
onInsertedSemicolon: null, | |
// `onTrailingComma` is similar to `onInsertedSemicolon`, but for | |
// trailing commas. | |
onTrailingComma: null, | |
// By default, reserved words are only enforced if ecmaVersion >= 5. | |
// Set `allowReserved` to a boolean value to explicitly turn this on | |
// an off. When this option has the value "never", reserved words | |
// and keywords can also not be used as property names. | |
allowReserved: null, | |
// When enabled, a return at the top level is not considered an | |
// error. | |
allowReturnOutsideFunction: false, | |
// When enabled, import/export statements are not constrained to | |
// appearing at the top of the program. | |
allowImportExportEverywhere: false, | |
// When enabled, hashbang directive in the beginning of file | |
// is allowed and treated as a line comment. | |
allowHashBang: false, | |
// When `locations` is on, `loc` properties holding objects with | |
// `start` and `end` properties in `{line, column}` form (with | |
// line being 1-based and column 0-based) will be attached to the | |
// nodes. | |
locations: false, | |
// A function can be passed as `onToken` option, which will | |
// cause Acorn to call that function with object in the same | |
// format as tokens returned from `tokenizer().getToken()`. Note | |
// that you are not allowed to call the parser from the | |
// callback—that will corrupt its internal state. | |
onToken: null, | |
// A function can be passed as `onComment` option, which will | |
// cause Acorn to call that function with `(block, text, start, | |
// end)` parameters whenever a comment is skipped. `block` is a | |
// boolean indicating whether this is a block (`/* */`) comment, | |
// `text` is the content of the comment, and `start` and `end` are | |
// character offsets that denote the start and end of the comment. | |
// When the `locations` option is on, two more parameters are | |
// passed, the full `{line, column}` locations of the start and | |
// end of the comments. Note that you are not allowed to call the | |
// parser from the callback—that will corrupt its internal state. | |
onComment: null, | |
// Nodes have their start and end characters offsets recorded in | |
// `start` and `end` properties (directly on the node, rather than | |
// the `loc` object, which holds line/column data. To also add a | |
// [semi-standardized][range] `range` property holding a `[start, | |
// end]` array with the same numbers, set the `ranges` option to | |
// `true`. | |
// | |
// [range]: https://bugzilla.mozilla.org/show_bug.cgi?id=745678 | |
ranges: false, | |
// It is possible to parse multiple files into a single AST by | |
// passing the tree produced by parsing the first file as | |
// `program` option in subsequent parses. This will add the | |
// toplevel forms of the parsed file to the `Program` (top) node | |
// of an existing parse tree. | |
program: null, | |
// When `locations` is on, you can pass this to record the source | |
// file in every node's `loc` object. | |
sourceFile: null, | |
// This value, if given, is stored in every node, whether | |
// `locations` is on or off. | |
directSourceFile: null, | |
// When enabled, parenthesized expressions are represented by | |
// (non-standard) ParenthesizedExpression nodes | |
preserveParens: false, | |
plugins: {} | |
} | |
// Interpret and default an options object | |
function getOptions(opts) { | |
var options = {} | |
for (var opt in defaultOptions) | |
options[opt] = opts && has(opts, opt) ? opts[opt] : defaultOptions[opt] | |
if (options.ecmaVersion >= 2015) | |
options.ecmaVersion -= 2009 | |
if (options.allowReserved == null) | |
options.allowReserved = options.ecmaVersion < 5 | |
if (isArray(options.onToken)) { | |
var tokens = options.onToken | |
options.onToken = function (token) { return tokens.push(token); } | |
} | |
if (isArray(options.onComment)) | |
options.onComment = pushComment(options, options.onComment) | |
return options | |
} | |
function pushComment(options, array) { | |
return function (block, text, start, end, startLoc, endLoc) { | |
var comment = { | |
type: block ? 'Block' : 'Line', | |
value: text, | |
start: start, | |
end: end | |
} | |
if (options.locations) | |
comment.loc = new SourceLocation(this, startLoc, endLoc) | |
if (options.ranges) | |
comment.range = [start, end] | |
array.push(comment) | |
} | |
} | |
// Registered plugins | |
var plugins = {} | |
function keywordRegexp(words) { | |
return new RegExp("^(" + words.replace(/ /g, "|") + ")$") | |
} | |
var Parser = function Parser(options, input, startPos) { | |
this.options = options = getOptions(options) | |
this.sourceFile = options.sourceFile | |
this.keywords = keywordRegexp(keywords[options.ecmaVersion >= 6 ? 6 : 5]) | |
var reserved = "" | |
if (!options.allowReserved) { | |
for (var v = options.ecmaVersion;; v--) | |
if (reserved = reservedWords[v]) break | |
if (options.sourceType == "module") reserved += " await" | |
} | |
this.reservedWords = keywordRegexp(reserved) | |
var reservedStrict = (reserved ? reserved + " " : "") + reservedWords.strict | |
this.reservedWordsStrict = keywordRegexp(reservedStrict) | |
this.reservedWordsStrictBind = keywordRegexp(reservedStrict + " " + reservedWords.strictBind) | |
this.input = String(input) | |
// Used to signal to callers of `readWord1` whether the word | |
// contained any escape sequences. This is needed because words with | |
// escape sequences must not be interpreted as keywords. | |
this.containsEsc = false | |
// Load plugins | |
this.loadPlugins(options.plugins) | |
// Set up token state | |
// The current position of the tokenizer in the input. | |
if (startPos) { | |
this.pos = startPos | |
this.lineStart = this.input.lastIndexOf("\n", startPos - 1) + 1 | |
this.curLine = this.input.slice(0, this.lineStart).split(lineBreak).length | |
} else { | |
this.pos = this.lineStart = 0 | |
this.curLine = 1 | |
} | |
// Properties of the current token: | |
// Its type | |
this.type = tt.eof | |
// For tokens that include more information than their type, the value | |
this.value = null | |
// Its start and end offset | |
this.start = this.end = this.pos | |
// And, if locations are used, the {line, column} object | |
// corresponding to those offsets | |
this.startLoc = this.endLoc = this.curPosition() | |
// Position information for the previous token | |
this.lastTokEndLoc = this.lastTokStartLoc = null | |
this.lastTokStart = this.lastTokEnd = this.pos | |
// The context stack is used to superficially track syntactic | |
// context to predict whether a regular expression is allowed in a | |
// given position. | |
this.context = this.initialContext() | |
this.exprAllowed = true | |
// Figure out if it's a module code. | |
this.strict = this.inModule = options.sourceType === "module" | |
// Used to signify the start of a potential arrow function | |
this.potentialArrowAt = -1 | |
// Flags to track whether we are in a function, a generator, an async function. | |
this.inFunction = this.inGenerator = this.inAsync = false | |
// Positions to delayed-check that yield/await does not exist in default parameters. | |
this.yieldPos = this.awaitPos = 0 | |
// Labels in scope. | |
this.labels = [] | |
// If enabled, skip leading hashbang line. | |
if (this.pos === 0 && options.allowHashBang && this.input.slice(0, 2) === '#!') | |
this.skipLineComment(2) | |
}; | |
// DEPRECATED Kept for backwards compatibility until 3.0 in case a plugin uses them | |
Parser.prototype.isKeyword = function isKeyword (word) { return this.keywords.test(word) }; | |
Parser.prototype.isReservedWord = function isReservedWord (word) { return this.reservedWords.test(word) }; | |
Parser.prototype.extend = function extend (name, f) { | |
this[name] = f(this[name]) | |
}; | |
Parser.prototype.loadPlugins = function loadPlugins (pluginConfigs) { | |
var this$1 = this; | |
for (var name in pluginConfigs) { | |
var plugin = plugins[name] | |
if (!plugin) throw new Error("Plugin '" + name + "' not found") | |
plugin(this$1, pluginConfigs[name]) | |
} | |
}; | |
Parser.prototype.parse = function parse () { | |
var node = this.options.program || this.startNode() | |
this.nextToken() | |
return this.parseTopLevel(node) | |
}; | |
var pp = Parser.prototype | |
// ## Parser utilities | |
// Test whether a statement node is the string literal `"use strict"`. | |
pp.isUseStrict = function(stmt) { | |
return this.options.ecmaVersion >= 5 && stmt.type === "ExpressionStatement" && | |
stmt.expression.type === "Literal" && | |
stmt.expression.raw.slice(1, -1) === "use strict" | |
} | |
// Predicate that tests whether the next token is of the given | |
// type, and if yes, consumes it as a side effect. | |
pp.eat = function(type) { | |
if (this.type === type) { | |
this.next() | |
return true | |
} else { | |
return false | |
} | |
} | |
// Tests whether parsed token is a contextual keyword. | |
pp.isContextual = function(name) { | |
return this.type === tt.name && this.value === name | |
} | |
// Consumes contextual keyword if possible. | |
pp.eatContextual = function(name) { | |
return this.value === name && this.eat(tt.name) | |
} | |
// Asserts that following token is given contextual keyword. | |
pp.expectContextual = function(name) { | |
if (!this.eatContextual(name)) this.unexpected() | |
} | |
// Test whether a semicolon can be inserted at the current position. | |
pp.canInsertSemicolon = function() { | |
return this.type === tt.eof || | |
this.type === tt.braceR || | |
lineBreak.test(this.input.slice(this.lastTokEnd, this.start)) | |
} | |
pp.insertSemicolon = function() { | |
if (this.canInsertSemicolon()) { | |
if (this.options.onInsertedSemicolon) | |
this.options.onInsertedSemicolon(this.lastTokEnd, this.lastTokEndLoc) | |
return true | |
} | |
} | |
// Consume a semicolon, or, failing that, see if we are allowed to | |
// pretend that there is a semicolon at this position. | |
pp.semicolon = function() { | |
if (!this.eat(tt.semi) && !this.insertSemicolon()) this.unexpected() | |
} | |
pp.afterTrailingComma = function(tokType, notNext) { | |
if (this.type == tokType) { | |
if (this.options.onTrailingComma) | |
this.options.onTrailingComma(this.lastTokStart, this.lastTokStartLoc) | |
if (!notNext) | |
this.next() | |
return true | |
} | |
} | |
// Expect a token of a given type. If found, consume it, otherwise, | |
// raise an unexpected token error. | |
pp.expect = function(type) { | |
this.eat(type) || this.unexpected() | |
} | |
// Raise an unexpected token error. | |
pp.unexpected = function(pos) { | |
this.raise(pos != null ? pos : this.start, "Unexpected token") | |
} | |
var DestructuringErrors = function DestructuringErrors() { | |
this.shorthandAssign = 0 | |
this.trailingComma = 0 | |
}; | |
pp.checkPatternErrors = function(refDestructuringErrors, andThrow) { | |
var trailing = refDestructuringErrors && refDestructuringErrors.trailingComma | |
if (!andThrow) return !!trailing | |
if (trailing) this.raise(trailing, "Comma is not permitted after the rest element") | |
} | |
pp.checkExpressionErrors = function(refDestructuringErrors, andThrow) { | |
var pos = refDestructuringErrors && refDestructuringErrors.shorthandAssign | |
if (!andThrow) return !!pos | |
if (pos) this.raise(pos, "Shorthand property assignments are valid only in destructuring patterns") | |
} | |
pp.checkYieldAwaitInDefaultParams = function() { | |
if (this.yieldPos && (!this.awaitPos || this.yieldPos < this.awaitPos)) | |
this.raise(this.yieldPos, "Yield expression cannot be a default value") | |
if (this.awaitPos) | |
this.raise(this.awaitPos, "Await expression cannot be a default value") | |
} | |
var pp$1 = Parser.prototype | |
// ### Statement parsing | |
// Parse a program. Initializes the parser, reads any number of | |
// statements, and wraps them in a Program node. Optionally takes a | |
// `program` argument. If present, the statements will be appended | |
// to its body instead of creating a new node. | |
pp$1.parseTopLevel = function(node) { | |
var this$1 = this; | |
var first = true, exports = {} | |
if (!node.body) node.body = [] | |
while (this.type !== tt.eof) { | |
var stmt = this$1.parseStatement(true, true, exports) | |
node.body.push(stmt) | |
if (first) { | |
if (this$1.isUseStrict(stmt)) this$1.setStrict(true) | |
first = false | |
} | |
} | |
this.next() | |
if (this.options.ecmaVersion >= 6) { | |
node.sourceType = this.options.sourceType | |
} | |
return this.finishNode(node, "Program") | |
} | |
var loopLabel = {kind: "loop"}; | |
var switchLabel = {kind: "switch"}; | |
pp$1.isLet = function() { | |
if (this.type !== tt.name || this.options.ecmaVersion < 6 || this.value != "let") return false | |
skipWhiteSpace.lastIndex = this.pos | |
var skip = skipWhiteSpace.exec(this.input) | |
var next = this.pos + skip[0].length, nextCh = this.input.charCodeAt(next) | |
if (nextCh === 91 || nextCh == 123) return true // '{' and '[' | |
if (isIdentifierStart(nextCh, true)) { | |
for (var pos = next + 1; isIdentifierChar(this.input.charCodeAt(pos), true); ++pos) {} | |
var ident = this.input.slice(next, pos) | |
if (!this.isKeyword(ident)) return true | |
} | |
return false | |
} | |
// check 'async [no LineTerminator here] function' | |
// - 'async /*foo*/ function' is OK. | |
// - 'async /*\n*/ function' is invalid. | |
pp$1.isAsyncFunction = function() { | |
if (this.type !== tt.name || this.options.ecmaVersion < 8 || this.value != "async") | |
return false | |
skipWhiteSpace.lastIndex = this.pos | |
var skip = skipWhiteSpace.exec(this.input) | |
var next = this.pos + skip[0].length | |
return !lineBreak.test(this.input.slice(this.pos, next)) && | |
this.input.slice(next, next + 8) === "function" && | |
(next + 8 == this.input.length || !isIdentifierChar(this.input.charAt(next + 8))) | |
} | |
// Parse a single statement. | |
// | |
// If expecting a statement and finding a slash operator, parse a | |
// regular expression literal. This is to handle cases like | |
// `if (foo) /blah/.exec(foo)`, where looking at the previous token | |
// does not help. | |
pp$1.parseStatement = function(declaration, topLevel, exports) { | |
var starttype = this.type, node = this.startNode(), kind | |
if (this.isLet()) { | |
starttype = tt._var | |
kind = "let" | |
} | |
// Most types of statements are recognized by the keyword they | |
// start with. Many are trivial to parse, some require a bit of | |
// complexity. | |
switch (starttype) { | |
case tt._break: case tt._continue: return this.parseBreakContinueStatement(node, starttype.keyword) | |
case tt._debugger: return this.parseDebuggerStatement(node) | |
case tt._do: return this.parseDoStatement(node) | |
case tt._for: return this.parseForStatement(node) | |
case tt._function: | |
if (!declaration && this.options.ecmaVersion >= 6) this.unexpected() | |
return this.parseFunctionStatement(node, false) | |
case tt._class: | |
if (!declaration) this.unexpected() | |
return this.parseClass(node, true) | |
case tt._if: return this.parseIfStatement(node) | |
case tt._return: return this.parseReturnStatement(node) | |
case tt._switch: return this.parseSwitchStatement(node) | |
case tt._throw: return this.parseThrowStatement(node) | |
case tt._try: return this.parseTryStatement(node) | |
case tt._const: case tt._var: | |
kind = kind || this.value | |
if (!declaration && kind != "var") this.unexpected() | |
return this.parseVarStatement(node, kind) | |
case tt._while: return this.parseWhileStatement(node) | |
case tt._with: return this.parseWithStatement(node) | |
case tt.braceL: return this.parseBlock() | |
case tt.semi: return this.parseEmptyStatement(node) | |
case tt._export: | |
case tt._import: | |
if (!this.options.allowImportExportEverywhere) { | |
if (!topLevel) | |
this.raise(this.start, "'import' and 'export' may only appear at the top level") | |
if (!this.inModule) | |
this.raise(this.start, "'import' and 'export' may appear only with 'sourceType: module'") | |
} | |
return starttype === tt._import ? this.parseImport(node) : this.parseExport(node, exports) | |
// If the statement does not start with a statement keyword or a | |
// brace, it's an ExpressionStatement or LabeledStatement. We | |
// simply start parsing an expression, and afterwards, if the | |
// next token is a colon and the expression was a simple | |
// Identifier node, we switch to interpreting it as a label. | |
default: | |
if (this.isAsyncFunction() && declaration) { | |
this.next() | |
return this.parseFunctionStatement(node, true) | |
} | |
var maybeName = this.value, expr = this.parseExpression() | |
if (starttype === tt.name && expr.type === "Identifier" && this.eat(tt.colon)) | |
return this.parseLabeledStatement(node, maybeName, expr) | |
else return this.parseExpressionStatement(node, expr) | |
} | |
} | |
pp$1.parseBreakContinueStatement = function(node, keyword) { | |
var this$1 = this; | |
var isBreak = keyword == "break" | |
this.next() | |
if (this.eat(tt.semi) || this.insertSemicolon()) node.label = null | |
else if (this.type !== tt.name) this.unexpected() | |
else { | |
node.label = this.parseIdent() | |
this.semicolon() | |
} | |
// Verify that there is an actual destination to break or | |
// continue to. | |
for (var i = 0; i < this.labels.length; ++i) { | |
var lab = this$1.labels[i] | |
if (node.label == null || lab.name === node.label.name) { | |
if (lab.kind != null && (isBreak || lab.kind === "loop")) break | |
if (node.label && isBreak) break | |
} | |
} | |
if (i === this.labels.length) this.raise(node.start, "Unsyntactic " + keyword) | |
return this.finishNode(node, isBreak ? "BreakStatement" : "ContinueStatement") | |
} | |
pp$1.parseDebuggerStatement = function(node) { | |
this.next() | |
this.semicolon() | |
return this.finishNode(node, "DebuggerStatement") | |
} | |
pp$1.parseDoStatement = function(node) { | |
this.next() | |
this.labels.push(loopLabel) | |
node.body = this.parseStatement(false) | |
this.labels.pop() | |
this.expect(tt._while) | |
node.test = this.parseParenExpression() | |
if (this.options.ecmaVersion >= 6) | |
this.eat(tt.semi) | |
else | |
this.semicolon() | |
return this.finishNode(node, "DoWhileStatement") | |
} | |
// Disambiguating between a `for` and a `for`/`in` or `for`/`of` | |
// loop is non-trivial. Basically, we have to parse the init `var` | |
// statement or expression, disallowing the `in` operator (see | |
// the second parameter to `parseExpression`), and then check | |
// whether the next token is `in` or `of`. When there is no init | |
// part (semicolon immediately after the opening parenthesis), it | |
// is a regular `for` loop. | |
pp$1.parseForStatement = function(node) { | |
this.next() | |
this.labels.push(loopLabel) | |
this.expect(tt.parenL) | |
if (this.type === tt.semi) return this.parseFor(node, null) | |
var isLet = this.isLet() | |
if (this.type === tt._var || this.type === tt._const || isLet) { | |
var init$1 = this.startNode(), kind = isLet ? "let" : this.value | |
this.next() | |
this.parseVar(init$1, true, kind) | |
this.finishNode(init$1, "VariableDeclaration") | |
if ((this.type === tt._in || (this.options.ecmaVersion >= 6 && this.isContextual("of"))) && init$1.declarations.length === 1 && | |
!(kind !== "var" && init$1.declarations[0].init)) | |
return this.parseForIn(node, init$1) | |
return this.parseFor(node, init$1) | |
} | |
var refDestructuringErrors = new DestructuringErrors | |
var init = this.parseExpression(true, refDestructuringErrors) | |
if (this.type === tt._in || (this.options.ecmaVersion >= 6 && this.isContextual("of"))) { | |
this.checkPatternErrors(refDestructuringErrors, true) | |
this.toAssignable(init) | |
this.checkLVal(init) | |
return this.parseForIn(node, init) | |
} else { | |
this.checkExpressionErrors(refDestructuringErrors, true) | |
} | |
return this.parseFor(node, init) | |
} | |
pp$1.parseFunctionStatement = function(node, isAsync) { | |
this.next() | |
return this.parseFunction(node, true, false, isAsync) | |
} | |
pp$1.isFunction = function() { | |
return this.type === tt._function || this.isAsyncFunction() | |
} | |
pp$1.parseIfStatement = function(node) { | |
this.next() | |
node.test = this.parseParenExpression() | |
// allow function declarations in branches, but only in non-strict mode | |
node.consequent = this.parseStatement(!this.strict && this.isFunction()) | |
node.alternate = this.eat(tt._else) ? this.parseStatement(!this.strict && this.isFunction()) : null | |
return this.finishNode(node, "IfStatement") | |
} | |
pp$1.parseReturnStatement = function(node) { | |
if (!this.inFunction && !this.options.allowReturnOutsideFunction) | |
this.raise(this.start, "'return' outside of function") | |
this.next() | |
// In `return` (and `break`/`continue`), the keywords with | |
// optional arguments, we eagerly look for a semicolon or the | |
// possibility to insert one. | |
if (this.eat(tt.semi) || this.insertSemicolon()) node.argument = null | |
else { node.argument = this.parseExpression(); this.semicolon() } | |
return this.finishNode(node, "ReturnStatement") | |
} | |
pp$1.parseSwitchStatement = function(node) { | |
var this$1 = this; | |
this.next() | |
node.discriminant = this.parseParenExpression() | |
node.cases = [] | |
this.expect(tt.braceL) | |
this.labels.push(switchLabel) | |
// Statements under must be grouped (by label) in SwitchCase | |
// nodes. `cur` is used to keep the node that we are currently | |
// adding statements to. | |
for (var cur, sawDefault = false; this.type != tt.braceR;) { | |
if (this$1.type === tt._case || this$1.type === tt._default) { | |
var isCase = this$1.type === tt._case | |
if (cur) this$1.finishNode(cur, "SwitchCase") | |
node.cases.push(cur = this$1.startNode()) | |
cur.consequent = [] | |
this$1.next() | |
if (isCase) { | |
cur.test = this$1.parseExpression() | |
} else { | |
if (sawDefault) this$1.raiseRecoverable(this$1.lastTokStart, "Multiple default clauses") | |
sawDefault = true | |
cur.test = null | |
} | |
this$1.expect(tt.colon) | |
} else { | |
if (!cur) this$1.unexpected() | |
cur.consequent.push(this$1.parseStatement(true)) | |
} | |
} | |
if (cur) this.finishNode(cur, "SwitchCase") | |
this.next() // Closing brace | |
this.labels.pop() | |
return this.finishNode(node, "SwitchStatement") | |
} | |
pp$1.parseThrowStatement = function(node) { | |
this.next() | |
if (lineBreak.test(this.input.slice(this.lastTokEnd, this.start))) | |
this.raise(this.lastTokEnd, "Illegal newline after throw") | |
node.argument = this.parseExpression() | |
this.semicolon() | |
return this.finishNode(node, "ThrowStatement") | |
} | |
// Reused empty array added for node fields that are always empty. | |
var empty = [] | |
pp$1.parseTryStatement = function(node) { | |
this.next() | |
node.block = this.parseBlock() | |
node.handler = null | |
if (this.type === tt._catch) { | |
var clause = this.startNode() | |
this.next() | |
this.expect(tt.parenL) | |
clause.param = this.parseBindingAtom() | |
this.checkLVal(clause.param, true) | |
this.expect(tt.parenR) | |
clause.body = this.parseBlock() | |
node.handler = this.finishNode(clause, "CatchClause") | |
} | |
node.finalizer = this.eat(tt._finally) ? this.parseBlock() : null | |
if (!node.handler && !node.finalizer) | |
this.raise(node.start, "Missing catch or finally clause") | |
return this.finishNode(node, "TryStatement") | |
} | |
pp$1.parseVarStatement = function(node, kind) { | |
this.next() | |
this.parseVar(node, false, kind) | |
this.semicolon() | |
return this.finishNode(node, "VariableDeclaration") | |
} | |
pp$1.parseWhileStatement = function(node) { | |
this.next() | |
node.test = this.parseParenExpression() | |
this.labels.push(loopLabel) | |
node.body = this.parseStatement(false) | |
this.labels.pop() | |
return this.finishNode(node, "WhileStatement") | |
} | |
pp$1.parseWithStatement = function(node) { | |
if (this.strict) this.raise(this.start, "'with' in strict mode") | |
this.next() | |
node.object = this.parseParenExpression() | |
node.body = this.parseStatement(false) | |
return this.finishNode(node, "WithStatement") | |
} | |
pp$1.parseEmptyStatement = function(node) { | |
this.next() | |
return this.finishNode(node, "EmptyStatement") | |
} | |
pp$1.parseLabeledStatement = function(node, maybeName, expr) { | |
var this$1 = this; | |
for (var i = 0; i < this.labels.length; ++i) | |
if (this$1.labels[i].name === maybeName) this$1.raise(expr.start, "Label '" + maybeName + "' is already declared") | |
var kind = this.type.isLoop ? "loop" : this.type === tt._switch ? "switch" : null | |
for (var i$1 = this.labels.length - 1; i$1 >= 0; i$1--) { | |
var label = this$1.labels[i$1] | |
if (label.statementStart == node.start) { | |
label.statementStart = this$1.start | |
label.kind = kind | |
} else break | |
} | |
this.labels.push({name: maybeName, kind: kind, statementStart: this.start}) | |
node.body = this.parseStatement(true) | |
this.labels.pop() | |
node.label = expr | |
return this.finishNode(node, "LabeledStatement") | |
} | |
pp$1.parseExpressionStatement = function(node, expr) { | |
node.expression = expr | |
this.semicolon() | |
return this.finishNode(node, "ExpressionStatement") | |
} | |
// Parse a semicolon-enclosed block of statements, handling `"use | |
// strict"` declarations when `allowStrict` is true (used for | |
// function bodies). | |
pp$1.parseBlock = function(allowStrict) { | |
var this$1 = this; | |
var node = this.startNode(), first = true, oldStrict | |
node.body = [] | |
this.expect(tt.braceL) | |
while (!this.eat(tt.braceR)) { | |
var stmt = this$1.parseStatement(true) | |
node.body.push(stmt) | |
if (first && allowStrict && this$1.isUseStrict(stmt)) { | |
oldStrict = this$1.strict | |
this$1.setStrict(this$1.strict = true) | |
} | |
first = false | |
} | |
if (oldStrict === false) this.setStrict(false) | |
return this.finishNode(node, "BlockStatement") | |
} | |
// Parse a regular `for` loop. The disambiguation code in | |
// `parseStatement` will already have parsed the init statement or | |
// expression. | |
pp$1.parseFor = function(node, init) { | |
node.init = init | |
this.expect(tt.semi) | |
node.test = this.type === tt.semi ? null : this.parseExpression() | |
this.expect(tt.semi) | |
node.update = this.type === tt.parenR ? null : this.parseExpression() | |
this.expect(tt.parenR) | |
node.body = this.parseStatement(false) | |
this.labels.pop() | |
return this.finishNode(node, "ForStatement") | |
} | |
// Parse a `for`/`in` and `for`/`of` loop, which are almost | |
// same from parser's perspective. | |
pp$1.parseForIn = function(node, init) { | |
var type = this.type === tt._in ? "ForInStatement" : "ForOfStatement" | |
this.next() | |
node.left = init | |
node.right = this.parseExpression() | |
this.expect(tt.parenR) | |
node.body = this.parseStatement(false) | |
this.labels.pop() | |
return this.finishNode(node, type) | |
} | |
// Parse a list of variable declarations. | |
pp$1.parseVar = function(node, isFor, kind) { | |
var this$1 = this; | |
node.declarations = [] | |
node.kind = kind | |
for (;;) { | |
var decl = this$1.startNode() | |
this$1.parseVarId(decl) | |
if (this$1.eat(tt.eq)) { | |
decl.init = this$1.parseMaybeAssign(isFor) | |
} else if (kind === "const" && !(this$1.type === tt._in || (this$1.options.ecmaVersion >= 6 && this$1.isContextual("of")))) { | |
this$1.unexpected() | |
} else if (decl.id.type != "Identifier" && !(isFor && (this$1.type === tt._in || this$1.isContextual("of")))) { | |
this$1.raise(this$1.lastTokEnd, "Complex binding patterns require an initialization value") | |
} else { | |
decl.init = null | |
} | |
node.declarations.push(this$1.finishNode(decl, "VariableDeclarator")) | |
if (!this$1.eat(tt.comma)) break | |
} | |
return node | |
} | |
pp$1.parseVarId = function(decl) { | |
decl.id = this.parseBindingAtom() | |
this.checkLVal(decl.id, true) | |
} | |
// Parse a function declaration or literal (depending on the | |
// `isStatement` parameter). | |
pp$1.parseFunction = function(node, isStatement, allowExpressionBody, isAsync) { | |
this.initFunction(node) | |
if (this.options.ecmaVersion >= 6 && !isAsync) | |
node.generator = this.eat(tt.star) | |
if (this.options.ecmaVersion >= 8) | |
node.async = !!isAsync | |
if (isStatement) | |
node.id = this.parseIdent() | |
var oldInGen = this.inGenerator, oldInAsync = this.inAsync, oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos | |
this.inGenerator = node.generator | |
this.inAsync = node.async | |
this.yieldPos = 0 | |
this.awaitPos = 0 | |
if (!isStatement && this.type === tt.name) | |
node.id = this.parseIdent() | |
this.parseFunctionParams(node) | |
this.parseFunctionBody(node, allowExpressionBody) | |
this.inGenerator = oldInGen | |
this.inAsync = oldInAsync | |
this.yieldPos = oldYieldPos | |
this.awaitPos = oldAwaitPos | |
return this.finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression") | |
} | |
pp$1.parseFunctionParams = function(node) { | |
this.expect(tt.parenL) | |
node.params = this.parseBindingList(tt.parenR, false, this.options.ecmaVersion >= 8, true) | |
this.checkYieldAwaitInDefaultParams() | |
} | |
// Parse a class declaration or literal (depending on the | |
// `isStatement` parameter). | |
pp$1.parseClass = function(node, isStatement) { | |
var this$1 = this; | |
this.next() | |
this.parseClassId(node, isStatement) | |
this.parseClassSuper(node) | |
var classBody = this.startNode() | |
var hadConstructor = false | |
classBody.body = [] | |
this.expect(tt.braceL) | |
while (!this.eat(tt.braceR)) { | |
if (this$1.eat(tt.semi)) continue | |
var method = this$1.startNode() | |
var isGenerator = this$1.eat(tt.star) | |
var isAsync = false | |
var isMaybeStatic = this$1.type === tt.name && this$1.value === "static" | |
this$1.parsePropertyName(method) | |
method.static = isMaybeStatic && this$1.type !== tt.parenL | |
if (method.static) { | |
if (isGenerator) this$1.unexpected() | |
isGenerator = this$1.eat(tt.star) | |
this$1.parsePropertyName(method) | |
} | |
if (this$1.options.ecmaVersion >= 8 && !isGenerator && !method.computed && | |
method.key.type === "Identifier" && method.key.name === "async" && this$1.type !== tt.parenL && | |
!this$1.canInsertSemicolon()) { | |
isAsync = true | |
this$1.parsePropertyName(method) | |
} | |
method.kind = "method" | |
var isGetSet = false | |
if (!method.computed) { | |
var key = method.key; | |
if (!isGenerator && !isAsync && key.type === "Identifier" && this$1.type !== tt.parenL && (key.name === "get" || key.name === "set")) { | |
isGetSet = true | |
method.kind = key.name | |
key = this$1.parsePropertyName(method) | |
} | |
if (!method.static && (key.type === "Identifier" && key.name === "constructor" || | |
key.type === "Literal" && key.value === "constructor")) { | |
if (hadConstructor) this$1.raise(key.start, "Duplicate constructor in the same class") | |
if (isGetSet) this$1.raise(key.start, "Constructor can't have get/set modifier") | |
if (isGenerator) this$1.raise(key.start, "Constructor can't be a generator") | |
if (isAsync) this$1.raise(key.start, "Constructor can't be an async method") | |
method.kind = "constructor" | |
hadConstructor = true | |
} | |
} | |
this$1.parseClassMethod(classBody, method, isGenerator, isAsync) | |
if (isGetSet) { | |
var paramCount = method.kind === "get" ? 0 : 1 | |
if (method.value.params.length !== paramCount) { | |
var start = method.value.start | |
if (method.kind === "get") | |
this$1.raiseRecoverable(start, "getter should have no params") | |
else | |
this$1.raiseRecoverable(start, "setter should have exactly one param") | |
} else { | |
if (method.kind === "set" && method.value.params[0].type === "RestElement") | |
this$1.raiseRecoverable(method.value.params[0].start, "Setter cannot use rest params") | |
} | |
} | |
} | |
node.body = this.finishNode(classBody, "ClassBody") | |
return this.finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression") | |
} | |
pp$1.parseClassMethod = function(classBody, method, isGenerator, isAsync) { | |
method.value = this.parseMethod(isGenerator, isAsync) | |
classBody.body.push(this.finishNode(method, "MethodDefinition")) | |
} | |
pp$1.parseClassId = function(node, isStatement) { | |
node.id = this.type === tt.name ? this.parseIdent() : isStatement ? this.unexpected() : null | |
} | |
pp$1.parseClassSuper = function(node) { | |
node.superClass = this.eat(tt._extends) ? this.parseExprSubscripts() : null | |
} | |
// Parses module export declaration. | |
pp$1.parseExport = function(node, exports) { | |
var this$1 = this; | |
this.next() | |
// export * from '...' | |
if (this.eat(tt.star)) { | |
this.expectContextual("from") | |
node.source = this.type === tt.string ? this.parseExprAtom() : this.unexpected() | |
this.semicolon() | |
return this.finishNode(node, "ExportAllDeclaration") | |
} | |
if (this.eat(tt._default)) { // export default ... | |
this.checkExport(exports, "default", this.lastTokStart) | |
var parens = this.type == tt.parenL | |
var expr = this.parseMaybeAssign() | |
var needsSemi = true | |
if (!parens && (expr.type == "FunctionExpression" || | |
expr.type == "ClassExpression")) { | |
needsSemi = false | |
if (expr.id) { | |
expr.type = expr.type == "FunctionExpression" | |
? "FunctionDeclaration" | |
: "ClassDeclaration" | |
} | |
} | |
node.declaration = expr | |
if (needsSemi) this.semicolon() | |
return this.finishNode(node, "ExportDefaultDeclaration") | |
} | |
// export var|const|let|function|class ... | |
if (this.shouldParseExportStatement()) { | |
node.declaration = this.parseStatement(true) | |
if (node.declaration.type === "VariableDeclaration") | |
this.checkVariableExport(exports, node.declaration.declarations) | |
else | |
this.checkExport(exports, node.declaration.id.name, node.declaration.id.start) | |
node.specifiers = [] | |
node.source = null | |
} else { // export { x, y as z } [from '...'] | |
node.declaration = null | |
node.specifiers = this.parseExportSpecifiers(exports) | |
if (this.eatContextual("from")) { | |
node.source = this.type === tt.string ? this.parseExprAtom() : this.unexpected() | |
} else { | |
// check for keywords used as local names | |
for (var i = 0; i < node.specifiers.length; i++) { | |
if (this$1.keywords.test(node.specifiers[i].local.name) || this$1.reservedWords.test(node.specifiers[i].local.name)) { | |
this$1.unexpected(node.specifiers[i].local.start) | |
} | |
} | |
node.source = null | |
} | |
this.semicolon() | |
} | |
return this.finishNode(node, "ExportNamedDeclaration") | |
} | |
pp$1.checkExport = function(exports, name, pos) { | |
if (!exports) return | |
if (Object.prototype.hasOwnProperty.call(exports, name)) | |
this.raiseRecoverable(pos, "Duplicate export '" + name + "'") | |
exports[name] = true | |
} | |
pp$1.checkPatternExport = function(exports, pat) { | |
var this$1 = this; | |
var type = pat.type | |
if (type == "Identifier") | |
this.checkExport(exports, pat.name, pat.start) | |
else if (type == "ObjectPattern") | |
for (var i = 0; i < pat.properties.length; ++i) | |
this$1.checkPatternExport(exports, pat.properties[i].value) | |
else if (type == "ArrayPattern") | |
for (var i$1 = 0; i$1 < pat.elements.length; ++i$1) { | |
var elt = pat.elements[i$1] | |
if (elt) this$1.checkPatternExport(exports, elt) | |
} | |
else if (type == "AssignmentPattern") | |
this.checkPatternExport(exports, pat.left) | |
else if (type == "ParenthesizedExpression") | |
this.checkPatternExport(exports, pat.expression) | |
} | |
pp$1.checkVariableExport = function(exports, decls) { | |
var this$1 = this; | |
if (!exports) return | |
for (var i = 0; i < decls.length; i++) | |
this$1.checkPatternExport(exports, decls[i].id) | |
} | |
pp$1.shouldParseExportStatement = function() { | |
return this.type.keyword === "var" | |
|| this.type.keyword === "const" | |
|| this.type.keyword === "class" | |
|| this.type.keyword === "function" | |
|| this.isLet() | |
|| this.isAsyncFunction() | |
} | |
// Parses a comma-separated list of module exports. | |
pp$1.parseExportSpecifiers = function(exports) { | |
var this$1 = this; | |
var nodes = [], first = true | |
// export { x, y as z } [from '...'] | |
this.expect(tt.braceL) | |
while (!this.eat(tt.braceR)) { | |
if (!first) { | |
this$1.expect(tt.comma) | |
if (this$1.afterTrailingComma(tt.braceR)) break | |
} else first = false | |
var node = this$1.startNode() | |
node.local = this$1.parseIdent(this$1.type === tt._default) | |
node.exported = this$1.eatContextual("as") ? this$1.parseIdent(true) : node.local | |
this$1.checkExport(exports, node.exported.name, node.exported.start) | |
nodes.push(this$1.finishNode(node, "ExportSpecifier")) | |
} | |
return nodes | |
} | |
// Parses import declaration. | |
pp$1.parseImport = function(node) { | |
this.next() | |
// import '...' | |
if (this.type === tt.string) { | |
node.specifiers = empty | |
node.source = this.parseExprAtom() | |
} else { | |
node.specifiers = this.parseImportSpecifiers() | |
this.expectContextual("from") | |
node.source = this.type === tt.string ? this.parseExprAtom() : this.unexpected() | |
} | |
this.semicolon() | |
return this.finishNode(node, "ImportDeclaration") | |
} | |
// Parses a comma-separated list of module imports. | |
pp$1.parseImportSpecifiers = function() { | |
var this$1 = this; | |
var nodes = [], first = true | |
if (this.type === tt.name) { | |
// import defaultObj, { x, y as z } from '...' | |
var node = this.startNode() | |
node.local = this.parseIdent() | |
this.checkLVal(node.local, true) | |
nodes.push(this.finishNode(node, "ImportDefaultSpecifier")) | |
if (!this.eat(tt.comma)) return nodes | |
} | |
if (this.type === tt.star) { | |
var node$1 = this.startNode() | |
this.next() | |
this.expectContextual("as") | |
node$1.local = this.parseIdent() | |
this.checkLVal(node$1.local, true) | |
nodes.push(this.finishNode(node$1, "ImportNamespaceSpecifier")) | |
return nodes | |
} | |
this.expect(tt.braceL) | |
while (!this.eat(tt.braceR)) { | |
if (!first) { | |
this$1.expect(tt.comma) | |
if (this$1.afterTrailingComma(tt.braceR)) break | |
} else first = false | |
var node$2 = this$1.startNode() | |
node$2.imported = this$1.parseIdent(true) | |
if (this$1.eatContextual("as")) { | |
node$2.local = this$1.parseIdent() | |
} else { | |
node$2.local = node$2.imported | |
if (this$1.isKeyword(node$2.local.name)) this$1.unexpected(node$2.local.start) | |
if (this$1.reservedWordsStrict.test(node$2.local.name)) this$1.raiseRecoverable(node$2.local.start, "The keyword '" + node$2.local.name + "' is reserved") | |
} | |
this$1.checkLVal(node$2.local, true) | |
nodes.push(this$1.finishNode(node$2, "ImportSpecifier")) | |
} | |
return nodes | |
} | |
var pp$2 = Parser.prototype | |
// Convert existing expression atom to assignable pattern | |
// if possible. | |
pp$2.toAssignable = function(node, isBinding) { | |
var this$1 = this; | |
if (this.options.ecmaVersion >= 6 && node) { | |
switch (node.type) { | |
case "Identifier": | |
if (this.inAsync && node.name === "await") | |
this.raise(node.start, "Can not use 'await' as identifier inside an async function") | |
break | |
case "ObjectPattern": | |
case "ArrayPattern": | |
break | |
case "ObjectExpression": | |
node.type = "ObjectPattern" | |
for (var i = 0; i < node.properties.length; i++) { | |
var prop = node.properties[i] | |
if (prop.kind !== "init") this$1.raise(prop.key.start, "Object pattern can't contain getter or setter") | |
this$1.toAssignable(prop.value, isBinding) | |
} | |
break | |
case "ArrayExpression": | |
node.type = "ArrayPattern" | |
this.toAssignableList(node.elements, isBinding) | |
break | |
case "AssignmentExpression": | |
if (node.operator === "=") { | |
node.type = "AssignmentPattern" | |
delete node.operator | |
this.toAssignable(node.left, isBinding) | |
// falls through to AssignmentPattern | |
} else { | |
this.raise(node.left.end, "Only '=' operator can be used for specifying default value.") | |
break | |
} | |
case "AssignmentPattern": | |
break | |
case "ParenthesizedExpression": | |
node.expression = this.toAssignable(node.expression, isBinding) | |
break | |
case "MemberExpression": | |
if (!isBinding) break | |
default: | |
this.raise(node.start, "Assigning to rvalue") | |
} | |
} | |
return node | |
} | |
// Convert list of expression atoms to binding list. | |
pp$2.toAssignableList = function(exprList, isBinding) { | |
var this$1 = this; | |
var end = exprList.length | |
if (end) { | |
var last = exprList[end - 1] | |
if (last && last.type == "RestElement") { | |
--end | |
} else if (last && last.type == "SpreadElement") { | |
last.type = "RestElement" | |
var arg = last.argument | |
this.toAssignable(arg, isBinding) | |
if (arg.type !== "Identifier" && arg.type !== "MemberExpression" && arg.type !== "ArrayPattern") | |
this.unexpected(arg.start) | |
--end | |
} | |
if (isBinding && last && last.type === "RestElement" && last.argument.type !== "Identifier") | |
this.unexpected(last.argument.start) | |
} | |
for (var i = 0; i < end; i++) { | |
var elt = exprList[i] | |
if (elt) this$1.toAssignable(elt, isBinding) | |
} | |
return exprList | |
} | |
// Parses spread element. | |
pp$2.parseSpread = function(refDestructuringErrors) { | |
var node = this.startNode() | |
this.next() | |
node.argument = this.parseMaybeAssign(false, refDestructuringErrors) | |
return this.finishNode(node, "SpreadElement") | |
} | |
pp$2.parseRest = function(allowNonIdent) { | |
var node = this.startNode() | |
this.next() | |
// RestElement inside of a function parameter must be an identifier | |
if (allowNonIdent) node.argument = this.type === tt.name ? this.parseIdent() : this.unexpected() | |
else node.argument = this.type === tt.name || this.type === tt.bracketL ? this.parseBindingAtom() : this.unexpected() | |
return this.finishNode(node, "RestElement") | |
} | |
// Parses lvalue (assignable) atom. | |
pp$2.parseBindingAtom = function() { | |
if (this.options.ecmaVersion < 6) return this.parseIdent() | |
switch (this.type) { | |
case tt.name: | |
return this.parseIdent() | |
case tt.bracketL: | |
var node = this.startNode() | |
this.next() | |
node.elements = this.parseBindingList(tt.bracketR, true, true) | |
return this.finishNode(node, "ArrayPattern") | |
case tt.braceL: | |
return this.parseObj(true) | |
default: | |
this.unexpected() | |
} | |
} | |
pp$2.parseBindingList = function(close, allowEmpty, allowTrailingComma, allowNonIdent) { | |
var this$1 = this; | |
var elts = [], first = true | |
while (!this.eat(close)) { | |
if (first) first = false | |
else this$1.expect(tt.comma) | |
if (allowEmpty && this$1.type === tt.comma) { | |
elts.push(null) | |
} else if (allowTrailingComma && this$1.afterTrailingComma(close)) { | |
break | |
} else if (this$1.type === tt.ellipsis) { | |
var rest = this$1.parseRest(allowNonIdent) | |
this$1.parseBindingListItem(rest) | |
elts.push(rest) | |
if (this$1.type === tt.comma) this$1.raise(this$1.start, "Comma is not permitted after the rest element") | |
this$1.expect(close) | |
break | |
} else { | |
var elem = this$1.parseMaybeDefault(this$1.start, this$1.startLoc) | |
this$1.parseBindingListItem(elem) | |
elts.push(elem) | |
} | |
} | |
return elts | |
} | |
pp$2.parseBindingListItem = function(param) { | |
return param | |
} | |
// Parses assignment pattern around given atom if possible. | |
pp$2.parseMaybeDefault = function(startPos, startLoc, left) { | |
left = left || this.parseBindingAtom() | |
if (this.options.ecmaVersion < 6 || !this.eat(tt.eq)) return left | |
var node = this.startNodeAt(startPos, startLoc) | |
node.left = left | |
node.right = this.parseMaybeAssign() | |
return this.finishNode(node, "AssignmentPattern") | |
} | |
// Verify that a node is an lval — something that can be assigned | |
// to. | |
pp$2.checkLVal = function(expr, isBinding, checkClashes) { | |
var this$1 = this; | |
switch (expr.type) { | |
case "Identifier": | |
if (this.strict && this.reservedWordsStrictBind.test(expr.name)) | |
this.raiseRecoverable(expr.start, (isBinding ? "Binding " : "Assigning to ") + expr.name + " in strict mode") | |
if (checkClashes) { | |
if (has(checkClashes, expr.name)) | |
this.raiseRecoverable(expr.start, "Argument name clash") | |
checkClashes[expr.name] = true | |
} | |
break | |
case "MemberExpression": | |
if (isBinding) this.raiseRecoverable(expr.start, (isBinding ? "Binding" : "Assigning to") + " member expression") | |
break | |
case "ObjectPattern": | |
for (var i = 0; i < expr.properties.length; i++) | |
this$1.checkLVal(expr.properties[i].value, isBinding, checkClashes) | |
break | |
case "ArrayPattern": | |
for (var i$1 = 0; i$1 < expr.elements.length; i$1++) { | |
var elem = expr.elements[i$1] | |
if (elem) this$1.checkLVal(elem, isBinding, checkClashes) | |
} | |
break | |
case "AssignmentPattern": | |
this.checkLVal(expr.left, isBinding, checkClashes) | |
break | |
case "RestElement": | |
this.checkLVal(expr.argument, isBinding, checkClashes) | |
break | |
case "ParenthesizedExpression": | |
this.checkLVal(expr.expression, isBinding, checkClashes) | |
break | |
default: | |
this.raise(expr.start, (isBinding ? "Binding" : "Assigning to") + " rvalue") | |
} | |
} | |
// A recursive descent parser operates by defining functions for all | |
// syntactic elements, and recursively calling those, each function | |
// advancing the input stream and returning an AST node. Precedence | |
// of constructs (for example, the fact that `!x[1]` means `!(x[1])` | |
// instead of `(!x)[1]` is handled by the fact that the parser | |
// function that parses unary prefix operators is called first, and | |
// in turn calls the function that parses `[]` subscripts — that | |
// way, it'll receive the node for `x[1]` already parsed, and wraps | |
// *that* in the unary operator node. | |
// | |
// Acorn uses an [operator precedence parser][opp] to handle binary | |
// operator precedence, because it is much more compact than using | |
// the technique outlined above, which uses different, nesting | |
// functions to specify precedence, for all of the ten binary | |
// precedence levels that JavaScript defines. | |
// | |
// [opp]: http://en.wikipedia.org/wiki/Operator-precedence_parser | |
var pp$3 = Parser.prototype | |
// Check if property name clashes with already added. | |
// Object/class getters and setters are not allowed to clash — | |
// either with each other or with an init property — and in | |
// strict mode, init properties are also not allowed to be repeated. | |
pp$3.checkPropClash = function(prop, propHash) { | |
if (this.options.ecmaVersion >= 6 && (prop.computed || prop.method || prop.shorthand)) | |
return | |
var key = prop.key; | |
var name | |
switch (key.type) { | |
case "Identifier": name = key.name; break | |
case "Literal": name = String(key.value); break | |
default: return | |
} | |
var kind = prop.kind; | |
if (this.options.ecmaVersion >= 6) { | |
if (name === "__proto__" && kind === "init") { | |
if (propHash.proto) this.raiseRecoverable(key.start, "Redefinition of __proto__ property") | |
propHash.proto = true | |
} | |
return | |
} | |
name = "$" + name | |
var other = propHash[name] | |
if (other) { | |
var isGetSet = kind !== "init" | |
if ((this.strict || isGetSet) && other[kind] || !(isGetSet ^ other.init)) | |
this.raiseRecoverable(key.start, "Redefinition of property") | |
} else { | |
other = propHash[name] = { | |
init: false, | |
get: false, | |
set: false | |
} | |
} | |
other[kind] = true | |
} | |
// ### Expression parsing | |
// These nest, from the most general expression type at the top to | |
// 'atomic', nondivisible expression types at the bottom. Most of | |
// the functions will simply let the function(s) below them parse, | |
// and, *if* the syntactic construct they handle is present, wrap | |
// the AST node that the inner parser gave them in another node. | |
// Parse a full expression. The optional arguments are used to | |
// forbid the `in` operator (in for loops initalization expressions) | |
// and provide reference for storing '=' operator inside shorthand | |
// property assignment in contexts where both object expression | |
// and object pattern might appear (so it's possible to raise | |
// delayed syntax error at correct position). | |
pp$3.parseExpression = function(noIn, refDestructuringErrors) { | |
var this$1 = this; | |
var startPos = this.start, startLoc = this.startLoc | |
var expr = this.parseMaybeAssign(noIn, refDestructuringErrors) | |
if (this.type === tt.comma) { | |
var node = this.startNodeAt(startPos, startLoc) | |
node.expressions = [expr] | |
while (this.eat(tt.comma)) node.expressions.push(this$1.parseMaybeAssign(noIn, refDestructuringErrors)) | |
return this.finishNode(node, "SequenceExpression") | |
} | |
return expr | |
} | |
// Parse an assignment expression. This includes applications of | |
// operators like `+=`. | |
pp$3.parseMaybeAssign = function(noIn, refDestructuringErrors, afterLeftParse) { | |
if (this.inGenerator && this.isContextual("yield")) return this.parseYield() | |
var ownDestructuringErrors = false | |
if (!refDestructuringErrors) { | |
refDestructuringErrors = new DestructuringErrors | |
ownDestructuringErrors = true | |
} | |
var startPos = this.start, startLoc = this.startLoc | |
if (this.type == tt.parenL || this.type == tt.name) | |
this.potentialArrowAt = this.start | |
var left = this.parseMaybeConditional(noIn, refDestructuringErrors) | |
if (afterLeftParse) left = afterLeftParse.call(this, left, startPos, startLoc) | |
if (this.type.isAssign) { | |
this.checkPatternErrors(refDestructuringErrors, true) | |
if (!ownDestructuringErrors) DestructuringErrors.call(refDestructuringErrors) | |
var node = this.startNodeAt(startPos, startLoc) | |
node.operator = this.value | |
node.left = this.type === tt.eq ? this.toAssignable(left) : left | |
refDestructuringErrors.shorthandAssign = 0 // reset because shorthand default was used correctly | |
this.checkLVal(left) | |
this.next() | |
node.right = this.parseMaybeAssign(noIn) | |
return this.finishNode(node, "AssignmentExpression") | |
} else { | |
if (ownDestructuringErrors) this.checkExpressionErrors(refDestructuringErrors, true) | |
} | |
return left | |
} | |
// Parse a ternary conditional (`?:`) operator. | |
pp$3.parseMaybeConditional = function(noIn, refDestructuringErrors) { | |
var startPos = this.start, startLoc = this.startLoc | |
var expr = this.parseExprOps(noIn, refDestructuringErrors) | |
if (this.checkExpressionErrors(refDestructuringErrors)) return expr | |
if (this.eat(tt.question)) { | |
var node = this.startNodeAt(startPos, startLoc) | |
node.test = expr | |
node.consequent = this.parseMaybeAssign() | |
this.expect(tt.colon) | |
node.alternate = this.parseMaybeAssign(noIn) | |
return this.finishNode(node, "ConditionalExpression") | |
} | |
return expr | |
} | |
// Start the precedence parser. | |
pp$3.parseExprOps = function(noIn, refDestructuringErrors) { | |
var startPos = this.start, startLoc = this.startLoc | |
var expr = this.parseMaybeUnary(refDestructuringErrors, false) | |
if (this.checkExpressionErrors(refDestructuringErrors)) return expr | |
return this.parseExprOp(expr, startPos, startLoc, -1, noIn) | |
} | |
// Parse binary operators with the operator precedence parsing | |
// algorithm. `left` is the left-hand side of the operator. | |
// `minPrec` provides context that allows the function to stop and | |
// defer further parser to one of its callers when it encounters an | |
// operator that has a lower precedence than the set it is parsing. | |
pp$3.parseExprOp = function(left, leftStartPos, leftStartLoc, minPrec, noIn) { | |
var prec = this.type.binop | |
if (prec != null && (!noIn || this.type !== tt._in)) { | |
if (prec > minPrec) { | |
var logical = this.type === tt.logicalOR || this.type === tt.logicalAND | |
var op = this.value | |
this.next() | |
var startPos = this.start, startLoc = this.startLoc | |
var right = this.parseExprOp(this.parseMaybeUnary(null, false), startPos, startLoc, prec, noIn) | |
var node = this.buildBinary(leftStartPos, leftStartLoc, left, right, op, logical) | |
return this.parseExprOp(node, leftStartPos, leftStartLoc, minPrec, noIn) | |
} | |
} | |
return left | |
} | |
pp$3.buildBinary = function(startPos, startLoc, left, right, op, logical) { | |
var node = this.startNodeAt(startPos, startLoc) | |
node.left = left | |
node.operator = op | |
node.right = right | |
return this.finishNode(node, logical ? "LogicalExpression" : "BinaryExpression") | |
} | |
// Parse unary operators, both prefix and postfix. | |
pp$3.parseMaybeUnary = function(refDestructuringErrors, sawUnary) { | |
var this$1 = this; | |
var startPos = this.start, startLoc = this.startLoc, expr | |
if (this.inAsync && this.isContextual("await")) { | |
expr = this.parseAwait(refDestructuringErrors) | |
sawUnary = true | |
} else if (this.type.prefix) { | |
var node = this.startNode(), update = this.type === tt.incDec | |
node.operator = this.value | |
node.prefix = true | |
this.next() | |
node.argument = this.parseMaybeUnary(null, true) | |
this.checkExpressionErrors(refDestructuringErrors, true) | |
if (update) this.checkLVal(node.argument) | |
else if (this.strict && node.operator === "delete" && | |
node.argument.type === "Identifier") | |
this.raiseRecoverable(node.start, "Deleting local variable in strict mode") | |
else sawUnary = true | |
expr = this.finishNode(node, update ? "UpdateExpression" : "UnaryExpression") | |
} else { | |
expr = this.parseExprSubscripts(refDestructuringErrors) | |
if (this.checkExpressionErrors(refDestructuringErrors)) return expr | |
while (this.type.postfix && !this.canInsertSemicolon()) { | |
var node$1 = this$1.startNodeAt(startPos, startLoc) | |
node$1.operator = this$1.value | |
node$1.prefix = false | |
node$1.argument = expr | |
this$1.checkLVal(expr) | |
this$1.next() | |
expr = this$1.finishNode(node$1, "UpdateExpression") | |
} | |
} | |
if (!sawUnary && this.eat(tt.starstar)) | |
return this.buildBinary(startPos, startLoc, expr, this.parseMaybeUnary(null, false), "**", false) | |
else | |
return expr | |
} | |
// Parse call, dot, and `[]`-subscript expressions. | |
pp$3.parseExprSubscripts = function(refDestructuringErrors) { | |
var startPos = this.start, startLoc = this.startLoc | |
var expr = this.parseExprAtom(refDestructuringErrors) | |
var skipArrowSubscripts = expr.type === "ArrowFunctionExpression" && this.input.slice(this.lastTokStart, this.lastTokEnd) !== ")" | |
if (this.checkExpressionErrors(refDestructuringErrors) || skipArrowSubscripts) return expr | |
return this.parseSubscripts(expr, startPos, startLoc) | |
} | |
pp$3.parseSubscripts = function(base, startPos, startLoc, noCalls) { | |
var this$1 = this; | |
for (;;) { | |
var maybeAsyncArrow = this$1.options.ecmaVersion >= 8 && base.type === "Identifier" && base.name === "async" && !this$1.canInsertSemicolon() | |
if (this$1.eat(tt.dot)) { | |
var node = this$1.startNodeAt(startPos, startLoc) | |
node.object = base | |
node.property = this$1.parseIdent(true) | |
node.computed = false | |
base = this$1.finishNode(node, "MemberExpression") | |
} else if (this$1.eat(tt.bracketL)) { | |
var node$1 = this$1.startNodeAt(startPos, startLoc) | |
node$1.object = base | |
node$1.property = this$1.parseExpression() | |
node$1.computed = true | |
this$1.expect(tt.bracketR) | |
base = this$1.finishNode(node$1, "MemberExpression") | |
} else if (!noCalls && this$1.eat(tt.parenL)) { | |
var refDestructuringErrors = new DestructuringErrors, oldYieldPos = this$1.yieldPos, oldAwaitPos = this$1.awaitPos | |
this$1.yieldPos = 0 | |
this$1.awaitPos = 0 | |
var exprList = this$1.parseExprList(tt.parenR, this$1.options.ecmaVersion >= 8, false, refDestructuringErrors) | |
if (maybeAsyncArrow && !this$1.canInsertSemicolon() && this$1.eat(tt.arrow)) { | |
this$1.checkPatternErrors(refDestructuringErrors, true) | |
this$1.checkYieldAwaitInDefaultParams() | |
this$1.yieldPos = oldYieldPos | |
this$1.awaitPos = oldAwaitPos | |
return this$1.parseArrowExpression(this$1.startNodeAt(startPos, startLoc), exprList, true) | |
} | |
this$1.checkExpressionErrors(refDestructuringErrors, true) | |
this$1.yieldPos = oldYieldPos || this$1.yieldPos | |
this$1.awaitPos = oldAwaitPos || this$1.awaitPos | |
var node$2 = this$1.startNodeAt(startPos, startLoc) | |
node$2.callee = base | |
node$2.arguments = exprList | |
base = this$1.finishNode(node$2, "CallExpression") | |
} else if (this$1.type === tt.backQuote) { | |
var node$3 = this$1.startNodeAt(startPos, startLoc) | |
node$3.tag = base | |
node$3.quasi = this$1.parseTemplate() | |
base = this$1.finishNode(node$3, "TaggedTemplateExpression") | |
} else { | |
return base | |
} | |
} | |
} | |
// Parse an atomic expression — either a single token that is an | |
// expression, an expression started by a keyword like `function` or | |
// `new`, or an expression wrapped in punctuation like `()`, `[]`, | |
// or `{}`. | |
pp$3.parseExprAtom = function(refDestructuringErrors) { | |
var node, canBeArrow = this.potentialArrowAt == this.start | |
switch (this.type) { | |
case tt._super: | |
if (!this.inFunction) | |
this.raise(this.start, "'super' outside of function or class") | |
case tt._this: | |
var type = this.type === tt._this ? "ThisExpression" : "Super" | |
node = this.startNode() | |
this.next() | |
return this.finishNode(node, type) | |
case tt.name: | |
var startPos = this.start, startLoc = this.startLoc | |
var id = this.parseIdent(this.type !== tt.name) | |
if (this.options.ecmaVersion >= 8 && id.name === "async" && !this.canInsertSemicolon() && this.eat(tt._function)) | |
return this.parseFunction(this.startNodeAt(startPos, startLoc), false, false, true) | |
if (canBeArrow && !this.canInsertSemicolon()) { | |
if (this.eat(tt.arrow)) | |
return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), [id], false) | |
if (this.options.ecmaVersion >= 8 && id.name === "async" && this.type === tt.name) { | |
id = this.parseIdent() | |
if (this.canInsertSemicolon() || !this.eat(tt.arrow)) | |
this.unexpected() | |
return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), [id], true) | |
} | |
} | |
return id | |
case tt.regexp: | |
var value = this.value | |
node = this.parseLiteral(value.value) | |
node.regex = {pattern: value.pattern, flags: value.flags} | |
return node | |
case tt.num: case tt.string: | |
return this.parseLiteral(this.value) | |
case tt._null: case tt._true: case tt._false: | |
node = this.startNode() | |
node.value = this.type === tt._null ? null : this.type === tt._true | |
node.raw = this.type.keyword | |
this.next() | |
return this.finishNode(node, "Literal") | |
case tt.parenL: | |
return this.parseParenAndDistinguishExpression(canBeArrow) | |
case tt.bracketL: | |
node = this.startNode() | |
this.next() | |
node.elements = this.parseExprList(tt.bracketR, true, true, refDestructuringErrors) | |
return this.finishNode(node, "ArrayExpression") | |
case tt.braceL: | |
return this.parseObj(false, refDestructuringErrors) | |
case tt._function: | |
node = this.startNode() | |
this.next() | |
return this.parseFunction(node, false) | |
case tt._class: | |
return this.parseClass(this.startNode(), false) | |
case tt._new: | |
return this.parseNew() | |
case tt.backQuote: | |
return this.parseTemplate() | |
default: | |
this.unexpected() | |
} | |
} | |
pp$3.parseLiteral = function(value) { | |
var node = this.startNode() | |
node.value = value | |
node.raw = this.input.slice(this.start, this.end) | |
this.next() | |
return this.finishNode(node, "Literal") | |
} | |
pp$3.parseParenExpression = function() { | |
this.expect(tt.parenL) | |
var val = this.parseExpression() | |
this.expect(tt.parenR) | |
return val | |
} | |
pp$3.parseParenAndDistinguishExpression = function(canBeArrow) { | |
var this$1 = this; | |
var startPos = this.start, startLoc = this.startLoc, val, allowTrailingComma = this.options.ecmaVersion >= 8 | |
if (this.options.ecmaVersion >= 6) { | |
this.next() | |
var innerStartPos = this.start, innerStartLoc = this.startLoc | |
var exprList = [], first = true, lastIsComma = false | |
var refDestructuringErrors = new DestructuringErrors, oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos, spreadStart, innerParenStart | |
this.yieldPos = 0 | |
this.awaitPos = 0 | |
while (this.type !== tt.parenR) { | |
first ? first = false : this$1.expect(tt.comma) | |
if (allowTrailingComma && this$1.afterTrailingComma(tt.parenR, true)) { | |
lastIsComma = true | |
break | |
} else if (this$1.type === tt.ellipsis) { | |
spreadStart = this$1.start | |
exprList.push(this$1.parseParenItem(this$1.parseRest())) | |
if (this$1.type === tt.comma) this$1.raise(this$1.start, "Comma is not permitted after the rest element") | |
break | |
} else { | |
if (this$1.type === tt.parenL && !innerParenStart) { | |
innerParenStart = this$1.start | |
} | |
exprList.push(this$1.parseMaybeAssign(false, refDestructuringErrors, this$1.parseParenItem)) | |
} | |
} | |
var innerEndPos = this.start, innerEndLoc = this.startLoc | |
this.expect(tt.parenR) | |
if (canBeArrow && !this.canInsertSemicolon() && this.eat(tt.arrow)) { | |
this.checkPatternErrors(refDestructuringErrors, true) | |
this.checkYieldAwaitInDefaultParams() | |
if (innerParenStart) this.unexpected(innerParenStart) | |
this.yieldPos = oldYieldPos | |
this.awaitPos = oldAwaitPos | |
return this.parseParenArrowList(startPos, startLoc, exprList) | |
} | |
if (!exprList.length || lastIsComma) this.unexpected(this.lastTokStart) | |
if (spreadStart) this.unexpected(spreadStart) | |
this.checkExpressionErrors(refDestructuringErrors, true) | |
this.yieldPos = oldYieldPos || this.yieldPos | |
this.awaitPos = oldAwaitPos || this.awaitPos | |
if (exprList.length > 1) { | |
val = this.startNodeAt(innerStartPos, innerStartLoc) | |
val.expressions = exprList | |
this.finishNodeAt(val, "SequenceExpression", innerEndPos, innerEndLoc) | |
} else { | |
val = exprList[0] | |
} | |
} else { | |
val = this.parseParenExpression() | |
} | |
if (this.options.preserveParens) { | |
var par = this.startNodeAt(startPos, startLoc) | |
par.expression = val | |
return this.finishNode(par, "ParenthesizedExpression") | |
} else { | |
return val | |
} | |
} | |
pp$3.parseParenItem = function(item) { | |
return item | |
} | |
pp$3.parseParenArrowList = function(startPos, startLoc, exprList) { | |
return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), exprList) | |
} | |
// New's precedence is slightly tricky. It must allow its argument to | |
// be a `[]` or dot subscript expression, but not a call — at least, | |
// not without wrapping it in parentheses. Thus, it uses the noCalls | |
// argument to parseSubscripts to prevent it from consuming the | |
// argument list. | |
var empty$1 = [] | |
pp$3.parseNew = function() { | |
var node = this.startNode() | |
var meta = this.parseIdent(true) | |
if (this.options.ecmaVersion >= 6 && this.eat(tt.dot)) { | |
node.meta = meta | |
node.property = this.parseIdent(true) | |
if (node.property.name !== "target") | |
this.raiseRecoverable(node.property.start, "The only valid meta property for new is new.target") | |
if (!this.inFunction) | |
this.raiseRecoverable(node.start, "new.target can only be used in functions") | |
return this.finishNode(node, "MetaProperty") | |
} | |
var startPos = this.start, startLoc = this.startLoc | |
node.callee = this.parseSubscripts(this.parseExprAtom(), startPos, startLoc, true) | |
if (this.eat(tt.parenL)) node.arguments = this.parseExprList(tt.parenR, this.options.ecmaVersion >= 8, false) | |
else node.arguments = empty$1 | |
return this.finishNode(node, "NewExpression") | |
} | |
// Parse template expression. | |
pp$3.parseTemplateElement = function() { | |
var elem = this.startNode() | |
elem.value = { | |
raw: this.input.slice(this.start, this.end).replace(/\r\n?/g, '\n'), | |
cooked: this.value | |
} | |
this.next() | |
elem.tail = this.type === tt.backQuote | |
return this.finishNode(elem, "TemplateElement") | |
} | |
pp$3.parseTemplate = function() { | |
var this$1 = this; | |
var node = this.startNode() | |
this.next() | |
node.expressions = [] | |
var curElt = this.parseTemplateElement() | |
node.quasis = [curElt] | |
while (!curElt.tail) { | |
this$1.expect(tt.dollarBraceL) | |
node.expressions.push(this$1.parseExpression()) | |
this$1.expect(tt.braceR) | |
node.quasis.push(curElt = this$1.parseTemplateElement()) | |
} | |
this.next() | |
return this.finishNode(node, "TemplateLiteral") | |
} | |
// Parse an object literal or binding pattern. | |
pp$3.parseObj = function(isPattern, refDestructuringErrors) { | |
var this$1 = this; | |
var node = this.startNode(), first = true, propHash = {} | |
node.properties = [] | |
this.next() | |
while (!this.eat(tt.braceR)) { | |
if (!first) { | |
this$1.expect(tt.comma) | |
if (this$1.afterTrailingComma(tt.braceR)) break | |
} else first = false | |
var prop = this$1.startNode(), isGenerator, isAsync, startPos, startLoc | |
if (this$1.options.ecmaVersion >= 6) { | |
prop.method = false | |
prop.shorthand = false | |
if (isPattern || refDestructuringErrors) { | |
startPos = this$1.start | |
startLoc = this$1.startLoc | |
} | |
if (!isPattern) | |
isGenerator = this$1.eat(tt.star) | |
} | |
this$1.parsePropertyName(prop) | |
if (!isPattern && this$1.options.ecmaVersion >= 8 && !isGenerator && !prop.computed && | |
prop.key.type === "Identifier" && prop.key.name === "async" && this$1.type !== tt.parenL && | |
this$1.type !== tt.colon && !this$1.canInsertSemicolon()) { | |
isAsync = true | |
this$1.parsePropertyName(prop, refDestructuringErrors) | |
} else { | |
isAsync = false | |
} | |
this$1.parsePropertyValue(prop, isPattern, isGenerator, isAsync, startPos, startLoc, refDestructuringErrors) | |
this$1.checkPropClash(prop, propHash) | |
node.properties.push(this$1.finishNode(prop, "Property")) | |
} | |
return this.finishNode(node, isPattern ? "ObjectPattern" : "ObjectExpression") | |
} | |
pp$3.parsePropertyValue = function(prop, isPattern, isGenerator, isAsync, startPos, startLoc, refDestructuringErrors) { | |
if ((isGenerator || isAsync) && this.type === tt.colon) | |
this.unexpected() | |
if (this.eat(tt.colon)) { | |
prop.value = isPattern ? this.parseMaybeDefault(this.start, this.startLoc) : this.parseMaybeAssign(false, refDestructuringErrors) | |
prop.kind = "init" | |
} else if (this.options.ecmaVersion >= 6 && this.type === tt.parenL) { | |
if (isPattern) this.unexpected() | |
prop.kind = "init" | |
prop.method = true | |
prop.value = this.parseMethod(isGenerator, isAsync) | |
} else if (this.options.ecmaVersion >= 5 && !prop.computed && prop.key.type === "Identifier" && | |
(prop.key.name === "get" || prop.key.name === "set") && | |
(this.type != tt.comma && this.type != tt.braceR)) { | |
if (isGenerator || isAsync || isPattern) this.unexpected() | |
prop.kind = prop.key.name | |
this.parsePropertyName(prop) | |
prop.value = this.parseMethod(false) | |
var paramCount = prop.kind === "get" ? 0 : 1 | |
if (prop.value.params.length !== paramCount) { | |
var start = prop.value.start | |
if (prop.kind === "get") | |
this.raiseRecoverable(start, "getter should have no params") | |
else | |
this.raiseRecoverable(start, "setter should have exactly one param") | |
} else { | |
if (prop.kind === "set" && prop.value.params[0].type === "RestElement") | |
this.raiseRecoverable(prop.value.params[0].start, "Setter cannot use rest params") | |
} | |
} else if (this.options.ecmaVersion >= 6 && !prop.computed && prop.key.type === "Identifier") { | |
if (this.keywords.test(prop.key.name) || | |
(this.strict ? this.reservedWordsStrict : this.reservedWords).test(prop.key.name) || | |
(this.inGenerator && prop.key.name == "yield") || | |
(this.inAsync && prop.key.name == "await")) | |
this.raiseRecoverable(prop.key.start, "'" + prop.key.name + "' can not be used as shorthand property") | |
prop.kind = "init" | |
if (isPattern) { | |
prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key) | |
} else if (this.type === tt.eq && refDestructuringErrors) { | |
if (!refDestructuringErrors.shorthandAssign) | |
refDestructuringErrors.shorthandAssign = this.start | |
prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key) | |
} else { | |
prop.value = prop.key | |
} | |
prop.shorthand = true | |
} else this.unexpected() | |
} | |
pp$3.parsePropertyName = function(prop) { | |
if (this.options.ecmaVersion >= 6) { | |
if (this.eat(tt.bracketL)) { | |
prop.computed = true | |
prop.key = this.parseMaybeAssign() | |
this.expect(tt.bracketR) | |
return prop.key | |
} else { | |
prop.computed = false | |
} | |
} | |
return prop.key = this.type === tt.num || this.type === tt.string ? this.parseExprAtom() : this.parseIdent(true) | |
} | |
// Initialize empty function node. | |
pp$3.initFunction = function(node) { | |
node.id = null | |
if (this.options.ecmaVersion >= 6) { | |
node.generator = false | |
node.expression = false | |
} | |
if (this.options.ecmaVersion >= 8) | |
node.async = false | |
} | |
// Parse object or class method. | |
pp$3.parseMethod = function(isGenerator, isAsync) { | |
var node = this.startNode(), oldInGen = this.inGenerator, oldInAsync = this.inAsync, oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos | |
this.initFunction(node) | |
if (this.options.ecmaVersion >= 6) | |
node.generator = isGenerator | |
if (this.options.ecmaVersion >= 8) | |
node.async = !!isAsync | |
this.inGenerator = node.generator | |
this.inAsync = node.async | |
this.yieldPos = 0 | |
this.awaitPos = 0 | |
this.expect(tt.parenL) | |
node.params = this.parseBindingList(tt.parenR, false, this.options.ecmaVersion >= 8) | |
this.checkYieldAwaitInDefaultParams() | |
this.parseFunctionBody(node, false) | |
this.inGenerator = oldInGen | |
this.inAsync = oldInAsync | |
this.yieldPos = oldYieldPos | |
this.awaitPos = oldAwaitPos | |
return this.finishNode(node, "FunctionExpression") | |
} | |
// Parse arrow function expression with given parameters. | |
pp$3.parseArrowExpression = function(node, params, isAsync) { | |
var oldInGen = this.inGenerator, oldInAsync = this.inAsync, oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos | |
this.initFunction(node) | |
if (this.options.ecmaVersion >= 8) | |
node.async = !!isAsync | |
this.inGenerator = false | |
this.inAsync = node.async | |
this.yieldPos = 0 | |
this.awaitPos = 0 | |
node.params = this.toAssignableList(params, true) | |
this.parseFunctionBody(node, true) | |
this.inGenerator = oldInGen | |
this.inAsync = oldInAsync | |
this.yieldPos = oldYieldPos | |
this.awaitPos = oldAwaitPos | |
return this.finishNode(node, "ArrowFunctionExpression") | |
} | |
// Parse function body and check parameters. | |
pp$3.parseFunctionBody = function(node, isArrowFunction) { | |
var isExpression = isArrowFunction && this.type !== tt.braceL | |
if (isExpression) { | |
node.body = this.parseMaybeAssign() | |
node.expression = true | |
} else { | |
// Start a new scope with regard to labels and the `inFunction` | |
// flag (restore them to their old value afterwards). | |
var oldInFunc = this.inFunction, oldLabels = this.labels | |
this.inFunction = true; this.labels = [] | |
node.body = this.parseBlock(true) | |
node.expression = false | |
this.inFunction = oldInFunc; this.labels = oldLabels | |
} | |
// If this is a strict mode function, verify that argument names | |
// are not repeated, and it does not try to bind the words `eval` | |
// or `arguments`. | |
var useStrict = (!isExpression && node.body.body.length && this.isUseStrict(node.body.body[0])) ? node.body.body[0] : null | |
if (useStrict && this.options.ecmaVersion >= 7 && !this.isSimpleParamList(node.params)) | |
this.raiseRecoverable(useStrict.start, "Illegal 'use strict' directive in function with non-simple parameter list") | |
if (this.strict || useStrict) { | |
var oldStrict = this.strict | |
this.strict = true | |
if (node.id) | |
this.checkLVal(node.id, true) | |
this.checkParams(node) | |
this.strict = oldStrict | |
} else if (isArrowFunction || !this.isSimpleParamList(node.params)) { | |
this.checkParams(node) | |
} | |
} | |
pp$3.isSimpleParamList = function(params) { | |
for (var i = 0; i < params.length; i++) | |
if (params[i].type !== "Identifier") return false | |
return true | |
} | |
// Checks function params for various disallowed patterns such as using "eval" | |
// or "arguments" and duplicate parameters. | |
pp$3.checkParams = function(node) { | |
var this$1 = this; | |
var nameHash = {} | |
for (var i = 0; i < node.params.length; i++) this$1.checkLVal(node.params[i], true, nameHash) | |
} | |
// Parses a comma-separated list of expressions, and returns them as | |
// an array. `close` is the token type that ends the list, and | |
// `allowEmpty` can be turned on to allow subsequent commas with | |
// nothing in between them to be parsed as `null` (which is needed | |
// for array literals). | |
pp$3.parseExprList = function(close, allowTrailingComma, allowEmpty, refDestructuringErrors) { | |
var this$1 = this; | |
var elts = [], first = true | |
while (!this.eat(close)) { | |
if (!first) { | |
this$1.expect(tt.comma) | |
if (allowTrailingComma && this$1.afterTrailingComma(close)) break | |
} else first = false | |
var elt | |
if (allowEmpty && this$1.type === tt.comma) | |
elt = null | |
else if (this$1.type === tt.ellipsis) { | |
elt = this$1.parseSpread(refDestructuringErrors) | |
if (this$1.type === tt.comma && refDestructuringErrors && !refDestructuringErrors.trailingComma) { | |
refDestructuringErrors.trailingComma = this$1.start | |
} | |
} else | |
elt = this$1.parseMaybeAssign(false, refDestructuringErrors) | |
elts.push(elt) | |
} | |
return elts | |
} | |
// Parse the next token as an identifier. If `liberal` is true (used | |
// when parsing properties), it will also convert keywords into | |
// identifiers. | |
pp$3.parseIdent = function(liberal) { | |
var node = this.startNode() | |
if (liberal && this.options.allowReserved == "never") liberal = false | |
if (this.type === tt.name) { | |
if (!liberal && (this.strict ? this.reservedWordsStrict : this.reservedWords).test(this.value) && | |
(this.options.ecmaVersion >= 6 || | |
this.input.slice(this.start, this.end).indexOf("\\") == -1)) | |
this.raiseRecoverable(this.start, "The keyword '" + this.value + "' is reserved") | |
if (this.inGenerator && this.value === "yield") | |
this.raiseRecoverable(this.start, "Can not use 'yield' as identifier inside a generator") | |
if (this.inAsync && this.value === "await") | |
this.raiseRecoverable(this.start, "Can not use 'await' as identifier inside an async function") | |
node.name = this.value | |
} else if (liberal && this.type.keyword) { | |
node.name = this.type.keyword | |
} else { | |
this.unexpected() | |
} | |
this.next() | |
return this.finishNode(node, "Identifier") | |
} | |
// Parses yield expression inside generator. | |
pp$3.parseYield = function() { | |
if (!this.yieldPos) this.yieldPos = this.start | |
var node = this.startNode() | |
this.next() | |
if (this.type == tt.semi || this.canInsertSemicolon() || (this.type != tt.star && !this.type.startsExpr)) { | |
node.delegate = false | |
node.argument = null | |
} else { | |
node.delegate = this.eat(tt.star) | |
node.argument = this.parseMaybeAssign() | |
} | |
return this.finishNode(node, "YieldExpression") | |
} | |
pp$3.parseAwait = function() { | |
if (!this.awaitPos) this.awaitPos = this.start | |
var node = this.startNode() | |
this.next() | |
node.argument = this.parseMaybeUnary(null, true) | |
return this.finishNode(node, "AwaitExpression") | |
} | |
var pp$4 = Parser.prototype | |
// This function is used to raise exceptions on parse errors. It | |
// takes an offset integer (into the current `input`) to indicate | |
// the location of the error, attaches the position to the end | |
// of the error message, and then raises a `SyntaxError` with that | |
// message. | |
pp$4.raise = function(pos, message) { | |
var loc = getLineInfo(this.input, pos) | |
message += " (" + loc.line + ":" + loc.column + ")" | |
var err = new SyntaxError(message) | |
err.pos = pos; err.loc = loc; err.raisedAt = this.pos | |
throw err | |
} | |
pp$4.raiseRecoverable = pp$4.raise | |
pp$4.curPosition = function() { | |
if (this.options.locations) { | |
return new Position(this.curLine, this.pos - this.lineStart) | |
} | |
} | |
var Node = function Node(parser, pos, loc) { | |
this.type = "" | |
this.start = pos | |
this.end = 0 | |
if (parser.options.locations) | |
this.loc = new SourceLocation(parser, loc) | |
if (parser.options.directSourceFile) | |
this.sourceFile = parser.options.directSourceFile | |
if (parser.options.ranges) | |
this.range = [pos, 0] | |
}; | |
// Start an AST node, attaching a start offset. | |
var pp$5 = Parser.prototype | |
pp$5.startNode = function() { | |
return new Node(this, this.start, this.startLoc) | |
} | |
pp$5.startNodeAt = function(pos, loc) { | |
return new Node(this, pos, loc) | |
} | |
// Finish an AST node, adding `type` and `end` properties. | |
function finishNodeAt(node, type, pos, loc) { | |
node.type = type | |
node.end = pos | |
if (this.options.locations) | |
node.loc.end = loc | |
if (this.options.ranges) | |
node.range[1] = pos | |
return node | |
} | |
pp$5.finishNode = function(node, type) { | |
return finishNodeAt.call(this, node, type, this.lastTokEnd, this.lastTokEndLoc) | |
} | |
// Finish node at given position | |
pp$5.finishNodeAt = function(node, type, pos, loc) { | |
return finishNodeAt.call(this, node, type, pos, loc) | |
} | |
// The algorithm used to determine whether a regexp can appear at a | |
// given point in the program is loosely based on sweet.js' approach. | |
// See https://github.com/mozilla/sweet.js/wiki/design | |
var TokContext = function TokContext(token, isExpr, preserveSpace, override) { | |
this.token = token | |
this.isExpr = !!isExpr | |
this.preserveSpace = !!preserveSpace | |
this.override = override | |
}; | |
var types = { | |
b_stat: new TokContext("{", false), | |
b_expr: new TokContext("{", true), | |
b_tmpl: new TokContext("${", true), | |
p_stat: new TokContext("(", false), | |
p_expr: new TokContext("(", true), | |
q_tmpl: new TokContext("`", true, true, function (p) { return p.readTmplToken(); }), | |
f_expr: new TokContext("function", true) | |
} | |
var pp$6 = Parser.prototype | |
pp$6.initialContext = function() { | |
return [types.b_stat] | |
} | |
pp$6.braceIsBlock = function(prevType) { | |
if (prevType === tt.colon) { | |
var parent = this.curContext() | |
if (parent === types.b_stat || parent === types.b_expr) | |
return !parent.isExpr | |
} | |
if (prevType === tt._return) | |
return lineBreak.test(this.input.slice(this.lastTokEnd, this.start)) | |
if (prevType === tt._else || prevType === tt.semi || prevType === tt.eof || prevType === tt.parenR) | |
return true | |
if (prevType == tt.braceL) | |
return this.curContext() === types.b_stat | |
return !this.exprAllowed | |
} | |
pp$6.updateContext = function(prevType) { | |
var update, type = this.type | |
if (type.keyword && prevType == tt.dot) | |
this.exprAllowed = false | |
else if (update = type.updateContext) | |
update.call(this, prevType) | |
else | |
this.exprAllowed = type.beforeExpr | |
} | |
// Token-specific context update code | |
tt.parenR.updateContext = tt.braceR.updateContext = function() { | |
if (this.context.length == 1) { | |
this.exprAllowed = true | |
return | |
} | |
var out = this.context.pop() | |
if (out === types.b_stat && this.curContext() === types.f_expr) { | |
this.context.pop() | |
this.exprAllowed = false | |
} else if (out === types.b_tmpl) { | |
this.exprAllowed = true | |
} else { | |
this.exprAllowed = !out.isExpr | |
} | |
} | |
tt.braceL.updateContext = function(prevType) { | |
this.context.push(this.braceIsBlock(prevType) ? types.b_stat : types.b_expr) | |
this.exprAllowed = true | |
} | |
tt.dollarBraceL.updateContext = function() { | |
this.context.push(types.b_tmpl) | |
this.exprAllowed = true | |
} | |
tt.parenL.updateContext = function(prevType) { | |
var statementParens = prevType === tt._if || prevType === tt._for || prevType === tt._with || prevType === tt._while | |
this.context.push(statementParens ? types.p_stat : types.p_expr) | |
this.exprAllowed = true | |
} | |
tt.incDec.updateContext = function() { | |
// tokExprAllowed stays unchanged | |
} | |
tt._function.updateContext = function(prevType) { | |
if (prevType.beforeExpr && prevType !== tt.semi && prevType !== tt._else && | |
!((prevType === tt.colon || prevType === tt.braceL) && this.curContext() === types.b_stat)) | |
this.context.push(types.f_expr) | |
this.exprAllowed = false | |
} | |
tt.backQuote.updateContext = function() { | |
if (this.curContext() === types.q_tmpl) | |
this.context.pop() | |
else | |
this.context.push(types.q_tmpl) | |
this.exprAllowed = false | |
} | |
// Object type used to represent tokens. Note that normally, tokens | |
// simply exist as properties on the parser object. This is only | |
// used for the onToken callback and the external tokenizer. | |
var Token = function Token(p) { | |
this.type = p.type | |
this.value = p.value | |
this.start = p.start | |
this.end = p.end | |
if (p.options.locations) | |
this.loc = new SourceLocation(p, p.startLoc, p.endLoc) | |
if (p.options.ranges) | |
this.range = [p.start, p.end] | |
}; | |
// ## Tokenizer | |
var pp$7 = Parser.prototype | |
// Are we running under Rhino? | |
var isRhino = typeof Packages == "object" && Object.prototype.toString.call(Packages) == "[object JavaPackage]" | |
// Move to the next token | |
pp$7.next = function() { | |
if (this.options.onToken) | |
this.options.onToken(new Token(this)) | |
this.lastTokEnd = this.end | |
this.lastTokStart = this.start | |
this.lastTokEndLoc = this.endLoc | |
this.lastTokStartLoc = this.startLoc | |
this.nextToken() | |
} | |
pp$7.getToken = function() { | |
this.next() | |
return new Token(this) | |
} | |
// If we're in an ES6 environment, make parsers iterable | |
if (typeof Symbol !== "undefined") | |
pp$7[Symbol.iterator] = function () { | |
var self = this | |
return {next: function () { | |
var token = self.getToken() | |
return { | |
done: token.type === tt.eof, | |
value: token | |
} | |
}} | |
} | |
// Toggle strict mode. Re-reads the next number or string to please | |
// pedantic tests (`"use strict"; 010;` should fail). | |
pp$7.setStrict = function(strict) { | |
var this$1 = this; | |
this.strict = strict | |
if (this.type !== tt.num && this.type !== tt.string) return | |
this.pos = this.start | |
if (this.options.locations) { | |
while (this.pos < this.lineStart) { | |
this$1.lineStart = this$1.input.lastIndexOf("\n", this$1.lineStart - 2) + 1 | |
--this$1.curLine | |
} | |
} | |
this.nextToken() | |
} | |
pp$7.curContext = function() { | |
return this.context[this.context.length - 1] | |
} | |
// Read a single token, updating the parser object's token-related | |
// properties. | |
pp$7.nextToken = function() { | |
var curContext = this.curContext() | |
if (!curContext || !curContext.preserveSpace) this.skipSpace() | |
this.start = this.pos | |
if (this.options.locations) this.startLoc = this.curPosition() | |
if (this.pos >= this.input.length) return this.finishToken(tt.eof) | |
if (curContext.override) return curContext.override(this) | |
else this.readToken(this.fullCharCodeAtPos()) | |
} | |
pp$7.readToken = function(code) { | |
// Identifier or keyword. '\uXXXX' sequences are allowed in | |
// identifiers, so '\' also dispatches to that. | |
if (isIdentifierStart(code, this.options.ecmaVersion >= 6) || code === 92 /* '\' */) | |
return this.readWord() | |
return this.getTokenFromCode(code) | |
} | |
pp$7.fullCharCodeAtPos = function() { | |
var code = this.input.charCodeAt(this.pos) | |
if (code <= 0xd7ff || code >= 0xe000) return code | |
var next = this.input.charCodeAt(this.pos + 1) | |
return (code << 10) + next - 0x35fdc00 | |
} | |
pp$7.skipBlockComment = function() { | |
var this$1 = this; | |
var startLoc = this.options.onComment && this.curPosition() | |
var start = this.pos, end = this.input.indexOf("*/", this.pos += 2) | |
if (end === -1) this.raise(this.pos - 2, "Unterminated comment") | |
this.pos = end + 2 | |
if (this.options.locations) { | |
lineBreakG.lastIndex = start | |
var match | |
while ((match = lineBreakG.exec(this.input)) && match.index < this.pos) { | |
++this$1.curLine | |
this$1.lineStart = match.index + match[0].length | |
} | |
} | |
if (this.options.onComment) | |
this.options.onComment(true, this.input.slice(start + 2, end), start, this.pos, | |
startLoc, this.curPosition()) | |
} | |
pp$7.skipLineComment = function(startSkip) { | |
var this$1 = this; | |
var start = this.pos | |
var startLoc = this.options.onComment && this.curPosition() | |
var ch = this.input.charCodeAt(this.pos+=startSkip) | |
while (this.pos < this.input.length && ch !== 10 && ch !== 13 && ch !== 8232 && ch !== 8233) { | |
++this$1.pos | |
ch = this$1.input.charCodeAt(this$1.pos) | |
} | |
if (this.options.onComment) | |
this.options.onComment(false, this.input.slice(start + startSkip, this.pos), start, this.pos, | |
startLoc, this.curPosition()) | |
} | |
// Called at the start of the parse and after every token. Skips | |
// whitespace and comments, and. | |
pp$7.skipSpace = function() { | |
var this$1 = this; | |
loop: while (this.pos < this.input.length) { | |
var ch = this$1.input.charCodeAt(this$1.pos) | |
switch (ch) { | |
case 32: case 160: // ' ' | |
++this$1.pos | |
break | |
case 13: | |
if (this$1.input.charCodeAt(this$1.pos + 1) === 10) { | |
++this$1.pos | |
} | |
case 10: case 8232: case 8233: | |
++this$1.pos | |
if (this$1.options.locations) { | |
++this$1.curLine | |
this$1.lineStart = this$1.pos | |
} | |
break | |
case 47: // '/' | |
switch (this$1.input.charCodeAt(this$1.pos + 1)) { | |
case 42: // '*' | |
this$1.skipBlockComment() | |
break | |
case 47: | |
this$1.skipLineComment(2) | |
break | |
default: | |
break loop | |
} | |
break | |
default: | |
if (ch > 8 && ch < 14 || ch >= 5760 && nonASCIIwhitespace.test(String.fromCharCode(ch))) { | |
++this$1.pos | |
} else { | |
break loop | |
} | |
} | |
} | |
} | |
// Called at the end of every token. Sets `end`, `val`, and | |
// maintains `context` and `exprAllowed`, and skips the space after | |
// the token, so that the next one's `start` will point at the | |
// right position. | |
pp$7.finishToken = function(type, val) { | |
this.end = this.pos | |
if (this.options.locations) this.endLoc = this.curPosition() | |
var prevType = this.type | |
this.type = type | |
this.value = val | |
this.updateContext(prevType) | |
} | |
// ### Token reading | |
// This is the function that is called to fetch the next token. It | |
// is somewhat obscure, because it works in character codes rather | |
// than characters, and because operator parsing has been inlined | |
// into it. | |
// | |
// All in the name of speed. | |
// | |
pp$7.readToken_dot = function() { | |
var next = this.input.charCodeAt(this.pos + 1) | |
if (next >= 48 && next <= 57) return this.readNumber(true) | |
var next2 = this.input.charCodeAt(this.pos + 2) | |
if (this.options.ecmaVersion >= 6 && next === 46 && next2 === 46) { // 46 = dot '.' | |
this.pos += 3 | |
return this.finishToken(tt.ellipsis) | |
} else { | |
++this.pos | |
return this.finishToken(tt.dot) | |
} | |
} | |
pp$7.readToken_slash = function() { // '/' | |
var next = this.input.charCodeAt(this.pos + 1) | |
if (this.exprAllowed) {++this.pos; return this.readRegexp()} | |
if (next === 61) return this.finishOp(tt.assign, 2) | |
return this.finishOp(tt.slash, 1) | |
} | |
pp$7.readToken_mult_modulo_exp = function(code) { // '%*' | |
var next = this.input.charCodeAt(this.pos + 1) | |
var size = 1 | |
var tokentype = code === 42 ? tt.star : tt.modulo | |
// exponentiation operator ** and **= | |
if (this.options.ecmaVersion >= 7 && next === 42) { | |
++size | |
tokentype = tt.starstar | |
next = this.input.charCodeAt(this.pos + 2) | |
} | |
if (next === 61) return this.finishOp(tt.assign, size + 1) | |
return this.finishOp(tokentype, size) | |
} | |
pp$7.readToken_pipe_amp = function(code) { // '|&' | |
var next = this.input.charCodeAt(this.pos + 1) | |
if (next === code) return this.finishOp(code === 124 ? tt.logicalOR : tt.logicalAND, 2) | |
if (next === 61) return this.finishOp(tt.assign, 2) | |
return this.finishOp(code === 124 ? tt.bitwiseOR : tt.bitwiseAND, 1) | |
} | |
pp$7.readToken_caret = function() { // '^' | |
var next = this.input.charCodeAt(this.pos + 1) | |
if (next === 61) return this.finishOp(tt.assign, 2) | |
return this.finishOp(tt.bitwiseXOR, 1) | |
} | |
pp$7.readToken_plus_min = function(code) { // '+-' | |
var next = this.input.charCodeAt(this.pos + 1) | |
if (next === code) { | |
if (next == 45 && this.input.charCodeAt(this.pos + 2) == 62 && | |
lineBreak.test(this.input.slice(this.lastTokEnd, this.pos))) { | |
// A `-->` line comment | |
this.skipLineComment(3) | |
this.skipSpace() | |
return this.nextToken() | |
} | |
return this.finishOp(tt.incDec, 2) | |
} | |
if (next === 61) return this.finishOp(tt.assign, 2) | |
return this.finishOp(tt.plusMin, 1) | |
} | |
pp$7.readToken_lt_gt = function(code) { // '<>' | |
var next = this.input.charCodeAt(this.pos + 1) | |
var size = 1 | |
if (next === code) { | |
size = code === 62 && this.input.charCodeAt(this.pos + 2) === 62 ? 3 : 2 | |
if (this.input.charCodeAt(this.pos + size) === 61) return this.finishOp(tt.assign, size + 1) | |
return this.finishOp(tt.bitShift, size) | |
} | |
if (next == 33 && code == 60 && this.input.charCodeAt(this.pos + 2) == 45 && | |
this.input.charCodeAt(this.pos + 3) == 45) { | |
if (this.inModule) this.unexpected() | |
// `<!--`, an XML-style comment that should be interpreted as a line comment | |
this.skipLineComment(4) | |
this.skipSpace() | |
return this.nextToken() | |
} | |
if (next === 61) size = 2 | |
return this.finishOp(tt.relational, size) | |
} | |
pp$7.readToken_eq_excl = function(code) { // '=!' | |
var next = this.input.charCodeAt(this.pos + 1) | |
if (next === 61) return this.finishOp(tt.equality, this.input.charCodeAt(this.pos + 2) === 61 ? 3 : 2) | |
if (code === 61 && next === 62 && this.options.ecmaVersion >= 6) { // '=>' | |
this.pos += 2 | |
return this.finishToken(tt.arrow) | |
} | |
return this.finishOp(code === 61 ? tt.eq : tt.prefix, 1) | |
} | |
pp$7.getTokenFromCode = function(code) { | |
switch (code) { | |
// The interpretation of a dot depends on whether it is followed | |
// by a digit or another two dots. | |
case 46: // '.' | |
return this.readToken_dot() | |
// Punctuation tokens. | |
case 40: ++this.pos; return this.finishToken(tt.parenL) | |
case 41: ++this.pos; return this.finishToken(tt.parenR) | |
case 59: ++this.pos; return this.finishToken(tt.semi) | |
case 44: ++this.pos; return this.finishToken(tt.comma) | |
case 91: ++this.pos; return this.finishToken(tt.bracketL) | |
case 93: ++this.pos; return this.finishToken(tt.bracketR) | |
case 123: ++this.pos; return this.finishToken(tt.braceL) | |
case 125: ++this.pos; return this.finishToken(tt.braceR) | |
case 58: ++this.pos; return this.finishToken(tt.colon) | |
case 63: ++this.pos; return this.finishToken(tt.question) | |
case 96: // '`' | |
if (this.options.ecmaVersion < 6) break | |
++this.pos | |
return this.finishToken(tt.backQuote) | |
case 48: // '0' | |
var next = this.input.charCodeAt(this.pos + 1) | |
if (next === 120 || next === 88) return this.readRadixNumber(16) // '0x', '0X' - hex number | |
if (this.options.ecmaVersion >= 6) { | |
if (next === 111 || next === 79) return this.readRadixNumber(8) // '0o', '0O' - octal number | |
if (next === 98 || next === 66) return this.readRadixNumber(2) // '0b', '0B' - binary number | |
} | |
// Anything else beginning with a digit is an integer, octal | |
// number, or float. | |
case 49: case 50: case 51: case 52: case 53: case 54: case 55: case 56: case 57: // 1-9 | |
return this.readNumber(false) | |
// Quotes produce strings. | |
case 34: case 39: // '"', "'" | |
return this.readString(code) | |
// Operators are parsed inline in tiny state machines. '=' (61) is | |
// often referred to. `finishOp` simply skips the amount of | |
// characters it is given as second argument, and returns a token | |
// of the type given by its first argument. | |
case 47: // '/' | |
return this.readToken_slash() | |
case 37: case 42: // '%*' | |
return this.readToken_mult_modulo_exp(code) | |
case 124: case 38: // '|&' | |
return this.readToken_pipe_amp(code) | |
case 94: // '^' | |
return this.readToken_caret() | |
case 43: case 45: // '+-' | |
return this.readToken_plus_min(code) | |
case 60: case 62: // '<>' | |
return this.readToken_lt_gt(code) | |
case 61: case 33: // '=!' | |
return this.readToken_eq_excl(code) | |
case 126: // '~' | |
return this.finishOp(tt.prefix, 1) | |
} | |
this.raise(this.pos, "Unexpected character '" + codePointToString(code) + "'") | |
} | |
pp$7.finishOp = function(type, size) { | |
var str = this.input.slice(this.pos, this.pos + size) | |
this.pos += size | |
return this.finishToken(type, str) | |
} | |
// Parse a regular expression. Some context-awareness is necessary, | |
// since a '/' inside a '[]' set does not end the expression. | |
function tryCreateRegexp(src, flags, throwErrorAt, parser) { | |
try { | |
return new RegExp(src, flags) | |
} catch (e) { | |
if (throwErrorAt !== undefined) { | |
if (e instanceof SyntaxError) parser.raise(throwErrorAt, "Error parsing regular expression: " + e.message) | |
throw e | |
} | |
} | |
} | |
var regexpUnicodeSupport = !!tryCreateRegexp("\uffff", "u") | |
pp$7.readRegexp = function() { | |
var this$1 = this; | |
var escaped, inClass, start = this.pos | |
for (;;) { | |
if (this$1.pos >= this$1.input.length) this$1.raise(start, "Unterminated regular expression") | |
var ch = this$1.input.charAt(this$1.pos) | |
if (lineBreak.test(ch)) this$1.raise(start, "Unterminated regular expression") | |
if (!escaped) { | |
if (ch === "[") inClass = true | |
else if (ch === "]" && inClass) inClass = false | |
else if (ch === "/" && !inClass) break | |
escaped = ch === "\\" | |
} else escaped = false | |
++this$1.pos | |
} | |
var content = this.input.slice(start, this.pos) | |
++this.pos | |
// Need to use `readWord1` because '\uXXXX' sequences are allowed | |
// here (don't ask). | |
var mods = this.readWord1() | |
var tmp = content, tmpFlags = "" | |
if (mods) { | |
var validFlags = /^[gim]*$/ | |
if (this.options.ecmaVersion >= 6) validFlags = /^[gimuy]*$/ | |
if (!validFlags.test(mods)) this.raise(start, "Invalid regular expression flag") | |
if (mods.indexOf("u") >= 0) { | |
if (regexpUnicodeSupport) { | |
tmpFlags = "u" | |
} else { | |
// Replace each astral symbol and every Unicode escape sequence that | |
// possibly represents an astral symbol or a paired surrogate with a | |
// single ASCII symbol to avoid throwing on regular expressions that | |
// are only valid in combination with the `/u` flag. | |
// Note: replacing with the ASCII symbol `x` might cause false | |
// negatives in unlikely scenarios. For example, `[\u{61}-b]` is a | |
// perfectly valid pattern that is equivalent to `[a-b]`, but it would | |
// be replaced by `[x-b]` which throws an error. | |
tmp = tmp.replace(/\\u\{([0-9a-fA-F]+)\}/g, function (_match, code, offset) { | |
code = Number("0x" + code) | |
if (code > 0x10FFFF) this$1.raise(start + offset + 3, "Code point out of bounds") | |
return "x" | |
}) | |
tmp = tmp.replace(/\\u([a-fA-F0-9]{4})|[\uD800-\uDBFF][\uDC00-\uDFFF]/g, "x") | |
tmpFlags = tmpFlags.replace("u", "") | |
} | |
} | |
} | |
// Detect invalid regular expressions. | |
var value = null | |
// Rhino's regular expression parser is flaky and throws uncatchable exceptions, | |
// so don't do detection if we are running under Rhino | |
if (!isRhino) { | |
tryCreateRegexp(tmp, tmpFlags, start, this) | |
// Get a regular expression object for this pattern-flag pair, or `null` in | |
// case the current environment doesn't support the flags it uses. | |
value = tryCreateRegexp(content, mods) | |
} | |
return this.finishToken(tt.regexp, {pattern: content, flags: mods, value: value}) | |
} | |
// Read an integer in the given radix. Return null if zero digits | |
// were read, the integer value otherwise. When `len` is given, this | |
// will return `null` unless the integer has exactly `len` digits. | |
pp$7.readInt = function(radix, len) { | |
var this$1 = this; | |
var start = this.pos, total = 0 | |
for (var i = 0, e = len == null ? Infinity : len; i < e; ++i) { | |
var code = this$1.input.charCodeAt(this$1.pos), val | |
if (code >= 97) val = code - 97 + 10 // a | |
else if (code >= 65) val = code - 65 + 10 // A | |
else if (code >= 48 && code <= 57) val = code - 48 // 0-9 | |
else val = Infinity | |
if (val >= radix) break | |
++this$1.pos | |
total = total * radix + val | |
} | |
if (this.pos === start || len != null && this.pos - start !== len) return null | |
return total | |
} | |
pp$7.readRadixNumber = function(radix) { | |
this.pos += 2 // 0x | |
var val = this.readInt(radix) | |
if (val == null) this.raise(this.start + 2, "Expected number in radix " + radix) | |
if (isIdentifierStart(this.fullCharCodeAtPos())) this.raise(this.pos, "Identifier directly after number") | |
return this.finishToken(tt.num, val) | |
} | |
// Read an integer, octal integer, or floating-point number. | |
pp$7.readNumber = function(startsWithDot) { | |
var start = this.pos, isFloat = false, octal = this.input.charCodeAt(this.pos) === 48 | |
if (!startsWithDot && this.readInt(10) === null) this.raise(start, "Invalid number") | |
if (octal && this.pos == start + 1) octal = false | |
var next = this.input.charCodeAt(this.pos) | |
if (next === 46 && !octal) { // '.' | |
++this.pos | |
this.readInt(10) | |
isFloat = true | |
next = this.input.charCodeAt(this.pos) | |
} | |
if ((next === 69 || next === 101) && !octal) { // 'eE' | |
next = this.input.charCodeAt(++this.pos) | |
if (next === 43 || next === 45) ++this.pos // '+-' | |
if (this.readInt(10) === null) this.raise(start, "Invalid number") | |
isFloat = true | |
} | |
if (isIdentifierStart(this.fullCharCodeAtPos())) this.raise(this.pos, "Identifier directly after number") | |
var str = this.input.slice(start, this.pos), val | |
if (isFloat) val = parseFloat(str) | |
else if (!octal || str.length === 1) val = parseInt(str, 10) | |
else if (/[89]/.test(str) || this.strict) this.raise(start, "Invalid number") | |
else val = parseInt(str, 8) | |
return this.finishToken(tt.num, val) | |
} | |
// Read a string value, interpreting backslash-escapes. | |
pp$7.readCodePoint = function() { | |
var ch = this.input.charCodeAt(this.pos), code | |
if (ch === 123) { | |
if (this.options.ecmaVersion < 6) this.unexpected() | |
var codePos = ++this.pos | |
code = this.readHexChar(this.input.indexOf('}', this.pos) - this.pos) | |
++this.pos | |
if (code > 0x10FFFF) this.raise(codePos, "Code point out of bounds") | |
} else { | |
code = this.readHexChar(4) | |
} | |
return code | |
} | |
function codePointToString(code) { | |
// UTF-16 Decoding | |
if (code <= 0xFFFF) return String.fromCharCode(code) | |
code -= 0x10000 | |
return String.fromCharCode((code >> 10) + 0xD800, (code & 1023) + 0xDC00) | |
} | |
pp$7.readString = function(quote) { | |
var this$1 = this; | |
var out = "", chunkStart = ++this.pos | |
for (;;) { | |
if (this$1.pos >= this$1.input.length) this$1.raise(this$1.start, "Unterminated string constant") | |
var ch = this$1.input.charCodeAt(this$1.pos) | |
if (ch === quote) break | |
if (ch === 92) { // '\' | |
out += this$1.input.slice(chunkStart, this$1.pos) | |
out += this$1.readEscapedChar(false) | |
chunkStart = this$1.pos | |
} else { | |
if (isNewLine(ch)) this$1.raise(this$1.start, "Unterminated string constant") | |
++this$1.pos | |
} | |
} | |
out += this.input.slice(chunkStart, this.pos++) | |
return this.finishToken(tt.string, out) | |
} | |
// Reads template string tokens. | |
pp$7.readTmplToken = function() { | |
var this$1 = this; | |
var out = "", chunkStart = this.pos | |
for (;;) { | |
if (this$1.pos >= this$1.input.length) this$1.raise(this$1.start, "Unterminated template") | |
var ch = this$1.input.charCodeAt(this$1.pos) | |
if (ch === 96 || ch === 36 && this$1.input.charCodeAt(this$1.pos + 1) === 123) { // '`', '${' | |
if (this$1.pos === this$1.start && this$1.type === tt.template) { | |
if (ch === 36) { | |
this$1.pos += 2 | |
return this$1.finishToken(tt.dollarBraceL) | |
} else { | |
++this$1.pos | |
return this$1.finishToken(tt.backQuote) | |
} | |
} | |
out += this$1.input.slice(chunkStart, this$1.pos) | |
return this$1.finishToken(tt.template, out) | |
} | |
if (ch === 92) { // '\' | |
out += this$1.input.slice(chunkStart, this$1.pos) | |
out += this$1.readEscapedChar(true) | |
chunkStart = this$1.pos | |
} else if (isNewLine(ch)) { | |
out += this$1.input.slice(chunkStart, this$1.pos) | |
++this$1.pos | |
switch (ch) { | |
case 13: | |
if (this$1.input.charCodeAt(this$1.pos) === 10) ++this$1.pos | |
case 10: | |
out += "\n" | |
break | |
default: | |
out += String.fromCharCode(ch) | |
break | |
} | |
if (this$1.options.locations) { | |
++this$1.curLine | |
this$1.lineStart = this$1.pos | |
} | |
chunkStart = this$1.pos | |
} else { | |
++this$1.pos | |
} | |
} | |
} | |
// Used to read escaped characters | |
pp$7.readEscapedChar = function(inTemplate) { | |
var ch = this.input.charCodeAt(++this.pos) | |
++this.pos | |
switch (ch) { | |
case 110: return "\n" // 'n' -> '\n' | |
case 114: return "\r" // 'r' -> '\r' | |
case 120: return String.fromCharCode(this.readHexChar(2)) // 'x' | |
case 117: return codePointToString(this.readCodePoint()) // 'u' | |
case 116: return "\t" // 't' -> '\t' | |
case 98: return "\b" // 'b' -> '\b' | |
case 118: return "\u000b" // 'v' -> '\u000b' | |
case 102: return "\f" // 'f' -> '\f' | |
case 13: if (this.input.charCodeAt(this.pos) === 10) ++this.pos // '\r\n' | |
case 10: // ' \n' | |
if (this.options.locations) { this.lineStart = this.pos; ++this.curLine } | |
return "" | |
default: | |
if (ch >= 48 && ch <= 55) { | |
var octalStr = this.input.substr(this.pos - 1, 3).match(/^[0-7]+/)[0] | |
var octal = parseInt(octalStr, 8) | |
if (octal > 255) { | |
octalStr = octalStr.slice(0, -1) | |
octal = parseInt(octalStr, 8) | |
} | |
if (octalStr !== "0" && (this.strict || inTemplate)) { | |
this.raise(this.pos - 2, "Octal literal in strict mode") | |
} | |
this.pos += octalStr.length - 1 | |
return String.fromCharCode(octal) | |
} | |
return String.fromCharCode(ch) | |
} | |
} | |
// Used to read character escape sequences ('\x', '\u', '\U'). | |
pp$7.readHexChar = function(len) { | |
var codePos = this.pos | |
var n = this.readInt(16, len) | |
if (n === null) this.raise(codePos, "Bad character escape sequence") | |
return n | |
} | |
// Read an identifier, and return it as a string. Sets `this.containsEsc` | |
// to whether the word contained a '\u' escape. | |
// | |
// Incrementally adds only escaped chars, adding other chunks as-is | |
// as a micro-optimization. | |
pp$7.readWord1 = function() { | |
var this$1 = this; | |
this.containsEsc = false | |
var word = "", first = true, chunkStart = this.pos | |
var astral = this.options.ecmaVersion >= 6 | |
while (this.pos < this.input.length) { | |
var ch = this$1.fullCharCodeAtPos() | |
if (isIdentifierChar(ch, astral)) { | |
this$1.pos += ch <= 0xffff ? 1 : 2 | |
} else if (ch === 92) { // "\" | |
this$1.containsEsc = true | |
word += this$1.input.slice(chunkStart, this$1.pos) | |
var escStart = this$1.pos | |
if (this$1.input.charCodeAt(++this$1.pos) != 117) // "u" | |
this$1.raise(this$1.pos, "Expecting Unicode escape sequence \\uXXXX") | |
++this$1.pos | |
var esc = this$1.readCodePoint() | |
if (!(first ? isIdentifierStart : isIdentifierChar)(esc, astral)) | |
this$1.raise(escStart, "Invalid Unicode escape") | |
word += codePointToString(esc) | |
chunkStart = this$1.pos | |
} else { | |
break | |
} | |
first = false | |
} | |
return word + this.input.slice(chunkStart, this.pos) | |
} | |
// Read an identifier or keyword token. Will check for reserved | |
// words when necessary. | |
pp$7.readWord = function() { | |
var word = this.readWord1() | |
var type = tt.name | |
if ((this.options.ecmaVersion >= 6 || !this.containsEsc) && this.keywords.test(word)) | |
type = keywordTypes[word] | |
return this.finishToken(type, word) | |
} | |
// Acorn is a tiny, fast JavaScript parser written in JavaScript. | |
// | |
// Acorn was written by Marijn Haverbeke, Ingvar Stepanyan, and | |
// various contributors and released under an MIT license. | |
// | |
// Git repositories for Acorn are available at | |
// | |
// http://marijnhaverbeke.nl/git/acorn | |
// https://github.com/ternjs/acorn.git | |
// | |
// Please use the [github bug tracker][ghbt] to report issues. | |
// | |
// [ghbt]: https://github.com/ternjs/acorn/issues | |
// | |
// This file defines the main parser interface. The library also comes | |
// with a [error-tolerant parser][dammit] and an | |
// [abstract syntax tree walker][walk], defined in other files. | |
// | |
// [dammit]: acorn_loose.js | |
// [walk]: util/walk.js | |
var version = "4.0.4" | |
// The main exported interface (under `self.acorn` when in the | |
// browser) is a `parse` function that takes a code string and | |
// returns an abstract syntax tree as specified by [Mozilla parser | |
// API][api]. | |
// | |
// [api]: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API | |
function parse(input, options) { | |
return new Parser(options, input).parse() | |
} | |
// This function tries to parse a single expression at a given | |
// offset in a string. Useful for parsing mixed-language formats | |
// that embed JavaScript expressions. | |
function parseExpressionAt(input, pos, options) { | |
var p = new Parser(options, input, pos) | |
p.nextToken() | |
return p.parseExpression() | |
} | |
// Acorn is organized as a tokenizer and a recursive-descent parser. | |
// The `tokenizer` export provides an interface to the tokenizer. | |
function tokenizer(input, options) { | |
return new Parser(options, input) | |
} | |
// This is a terrible kludge to support the existing, pre-ES6 | |
// interface where the loose parser module retroactively adds exports | |
// to this module. | |
function addLooseExports(parse, Parser, plugins) { | |
exports.parse_dammit = parse | |
exports.LooseParser = Parser | |
exports.pluginsLoose = plugins | |
} | |
exports.version = version; | |
exports.parse = parse; | |
exports.parseExpressionAt = parseExpressionAt; | |
exports.tokenizer = tokenizer; | |
exports.addLooseExports = addLooseExports; | |
exports.Parser = Parser; | |
exports.plugins = plugins; | |
exports.defaultOptions = defaultOptions; | |
exports.Position = Position; | |
exports.SourceLocation = SourceLocation; | |
exports.getLineInfo = getLineInfo; | |
exports.Node = Node; | |
exports.TokenType = TokenType; | |
exports.tokTypes = tt; | |
exports.TokContext = TokContext; | |
exports.tokContexts = types; | |
exports.isIdentifierChar = isIdentifierChar; | |
exports.isIdentifierStart = isIdentifierStart; | |
exports.Token = Token; | |
exports.isNewLine = isNewLine; | |
exports.lineBreak = lineBreak; | |
exports.lineBreakG = lineBreakG; | |
Object.defineProperty(exports, '__esModule', { value: true }); | |
}))); | |
},{}],"evaljs":[function(require,module,exports){ | |
(function (process,global){ | |
/** | |
* Copyright (c) 2014, Facebook, Inc. | |
* All rights reserved. | |
* | |
* This source code is licensed under the BSD-style license found in the | |
* https://raw.github.com/facebook/regenerator/master/LICENSE file. An | |
* additional grant of patent rights can be found in the PATENTS file in | |
* the same directory. | |
*/ | |
!(function(global) { | |
"use strict"; | |
var Op = Object.prototype; | |
var hasOwn = Op.hasOwnProperty; | |
var undefined; // More compressible than void 0. | |
var $Symbol = typeof Symbol === "function" ? Symbol : {}; | |
var iteratorSymbol = $Symbol.iterator || "@@iterator"; | |
var toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag"; | |
var inModule = typeof module === "object"; | |
var runtime = global.regeneratorRuntime; | |
if (runtime) { | |
if (inModule) { | |
// If regeneratorRuntime is defined globally and we're in a module, | |
// make the exports object identical to regeneratorRuntime. | |
module.exports = runtime; | |
} | |
// Don't bother evaluating the rest of this file if the runtime was | |
// already defined globally. | |
return; | |
} | |
// Define the runtime globally (as expected by generated code) as either | |
// module.exports (if we're in a module) or a new, empty object. | |
runtime = global.regeneratorRuntime = inModule ? module.exports : {}; | |
function wrap(innerFn, outerFn, self, tryLocsList) { | |
// If outerFn provided and outerFn.prototype is a Generator, then outerFn.prototype instanceof Generator. | |
var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator; | |
var generator = Object.create(protoGenerator.prototype); | |
var context = new Context(tryLocsList || []); | |
// The ._invoke method unifies the implementations of the .next, | |
// .throw, and .return methods. | |
generator._invoke = makeInvokeMethod(innerFn, self, context); | |
return generator; | |
} | |
runtime.wrap = wrap; | |
// Try/catch helper to minimize deoptimizations. Returns a completion | |
// record like context.tryEntries[i].completion. This interface could | |
// have been (and was previously) designed to take a closure to be | |
// invoked without arguments, but in all the cases we care about we | |
// already have an existing method we want to call, so there's no need | |
// to create a new function object. We can even get away with assuming | |
// the method takes exactly one argument, since that happens to be true | |
// in every case, so we don't have to touch the arguments object. The | |
// only additional allocation required is the completion record, which | |
// has a stable shape and so hopefully should be cheap to allocate. | |
function tryCatch(fn, obj, arg) { | |
try { | |
return { type: "normal", arg: fn.call(obj, arg) }; | |
} catch (err) { | |
return { type: "throw", arg: err }; | |
} | |
} | |
var GenStateSuspendedStart = "suspendedStart"; | |
var GenStateSuspendedYield = "suspendedYield"; | |
var GenStateExecuting = "executing"; | |
var GenStateCompleted = "completed"; | |
// Returning this object from the innerFn has the same effect as | |
// breaking out of the dispatch switch statement. | |
var ContinueSentinel = {}; | |
// Dummy constructor functions that we use as the .constructor and | |
// .constructor.prototype properties for functions that return Generator | |
// objects. For full spec compliance, you may wish to configure your | |
// minifier not to mangle the names of these two functions. | |
function Generator() {} | |
function GeneratorFunction() {} | |
function GeneratorFunctionPrototype() {} | |
// This is a polyfill for %IteratorPrototype% for environments that | |
// don't natively support it. | |
var IteratorPrototype = {}; | |
IteratorPrototype[iteratorSymbol] = function () { | |
return this; | |
}; | |
var getProto = Object.getPrototypeOf; | |
var NativeIteratorPrototype = getProto && getProto(getProto(values([]))); | |
if (NativeIteratorPrototype && | |
NativeIteratorPrototype !== Op && | |
hasOwn.call(NativeIteratorPrototype, iteratorSymbol)) { | |
// This environment has a native %IteratorPrototype%; use it instead | |
// of the polyfill. | |
IteratorPrototype = NativeIteratorPrototype; | |
} | |
var Gp = GeneratorFunctionPrototype.prototype = | |
Generator.prototype = Object.create(IteratorPrototype); | |
GeneratorFunction.prototype = Gp.constructor = GeneratorFunctionPrototype; | |
GeneratorFunctionPrototype.constructor = GeneratorFunction; | |
GeneratorFunctionPrototype[toStringTagSymbol] = | |
GeneratorFunction.displayName = "GeneratorFunction"; | |
// Helper for defining the .next, .throw, and .return methods of the | |
// Iterator interface in terms of a single ._invoke method. | |
function defineIteratorMethods(prototype) { | |
["next", "throw", "return"].forEach(function(method) { | |
prototype[method] = function(arg) { | |
return this._invoke(method, arg); | |
}; | |
}); | |
} | |
runtime.isGeneratorFunction = function(genFun) { | |
var ctor = typeof genFun === "function" && genFun.constructor; | |
return ctor | |
? ctor === GeneratorFunction || | |
// For the native GeneratorFunction constructor, the best we can | |
// do is to check its .name property. | |
(ctor.displayName || ctor.name) === "GeneratorFunction" | |
: false; | |
}; | |
runtime.mark = function(genFun) { | |
if (Object.setPrototypeOf) { | |
Object.setPrototypeOf(genFun, GeneratorFunctionPrototype); | |
} else { | |
genFun.__proto__ = GeneratorFunctionPrototype; | |
if (!(toStringTagSymbol in genFun)) { | |
genFun[toStringTagSymbol] = "GeneratorFunction"; | |
} | |
} | |
genFun.prototype = Object.create(Gp); | |
return genFun; | |
}; | |
// Within the body of any async function, `await x` is transformed to | |
// `yield regeneratorRuntime.awrap(x)`, so that the runtime can test | |
// `hasOwn.call(value, "__await")` to determine if the yielded value is | |
// meant to be awaited. | |
runtime.awrap = function(arg) { | |
return { __await: arg }; | |
}; | |
function AsyncIterator(generator) { | |
function invoke(method, arg, resolve, reject) { | |
var record = tryCatch(generator[method], generator, arg); | |
if (record.type === "throw") { | |
reject(record.arg); | |
} else { | |
var result = record.arg; | |
var value = result.value; | |
if (value && | |
typeof value === "object" && | |
hasOwn.call(value, "__await")) { | |
return Promise.resolve(value.__await).then(function(value) { | |
invoke("next", value, resolve, reject); | |
}, function(err) { | |
invoke("throw", err, resolve, reject); | |
}); | |
} | |
return Promise.resolve(value).then(function(unwrapped) { | |
// When a yielded Promise is resolved, its final value becomes | |
// the .value of the Promise<{value,done}> result for the | |
// current iteration. If the Promise is rejected, however, the | |
// result for this iteration will be rejected with the same | |
// reason. Note that rejections of yielded Promises are not | |
// thrown back into the generator function, as is the case | |
// when an awaited Promise is rejected. This difference in | |
// behavior between yield and await is important, because it | |
// allows the consumer to decide what to do with the yielded | |
// rejection (swallow it and continue, manually .throw it back | |
// into the generator, abandon iteration, whatever). With | |
// await, by contrast, there is no opportunity to examine the | |
// rejection reason outside the generator function, so the | |
// only option is to throw it from the await expression, and | |
// let the generator function handle the exception. | |
result.value = unwrapped; | |
resolve(result); | |
}, reject); | |
} | |
} | |
if (typeof process === "object" && process.domain) { | |
invoke = process.domain.bind(invoke); | |
} | |
var previousPromise; | |
function enqueue(method, arg) { | |
function callInvokeWithMethodAndArg() { | |
return new Promise(function(resolve, reject) { | |
invoke(method, arg, resolve, reject); | |
}); | |
} | |
return previousPromise = | |
// If enqueue has been called before, then we want to wait until | |
// all previous Promises have been resolved before calling invoke, | |
// so that results are always delivered in the correct order. If | |
// enqueue has not been called before, then it is important to | |
// call invoke immediately, without waiting on a callback to fire, | |
// so that the async generator function has the opportunity to do | |
// any necessary setup in a predictable way. This predictability | |
// is why the Promise constructor synchronously invokes its | |
// executor callback, and why async functions synchronously | |
// execute code before the first await. Since we implement simple | |
// async functions in terms of async generators, it is especially | |
// important to get this right, even though it requires care. | |
previousPromise ? previousPromise.then( | |
callInvokeWithMethodAndArg, | |
// Avoid propagating failures to Promises returned by later | |
// invocations of the iterator. | |
callInvokeWithMethodAndArg | |
) : callInvokeWithMethodAndArg(); | |
} | |
// Define the unified helper method that is used to implement .next, | |
// .throw, and .return (see defineIteratorMethods). | |
this._invoke = enqueue; | |
} | |
defineIteratorMethods(AsyncIterator.prototype); | |
runtime.AsyncIterator = AsyncIterator; | |
// Note that simple async functions are implemented on top of | |
// AsyncIterator objects; they just return a Promise for the value of | |
// the final result produced by the iterator. | |
runtime.async = function(innerFn, outerFn, self, tryLocsList) { | |
var iter = new AsyncIterator( | |
wrap(innerFn, outerFn, self, tryLocsList) | |
); | |
return runtime.isGeneratorFunction(outerFn) | |
? iter // If outerFn is a generator, return the full iterator. | |
: iter.next().then(function(result) { | |
return result.done ? result.value : iter.next(); | |
}); | |
}; | |
function makeInvokeMethod(innerFn, self, context) { | |
var state = GenStateSuspendedStart; | |
return function invoke(method, arg) { | |
if (state === GenStateExecuting) { | |
throw new Error("Generator is already running"); | |
} | |
if (state === GenStateCompleted) { | |
if (method === "throw") { | |
throw arg; | |
} | |
// Be forgiving, per 25.3.3.3.3 of the spec: | |
// https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generatorresume | |
return doneResult(); | |
} | |
while (true) { | |
var delegate = context.delegate; | |
if (delegate) { | |
if (method === "return" || | |
(method === "throw" && delegate.iterator[method] === undefined)) { | |
// A return or throw (when the delegate iterator has no throw | |
// method) always terminates the yield* loop. | |
context.delegate = null; | |
// If the delegate iterator has a return method, give it a | |
// chance to clean up. | |
var returnMethod = delegate.iterator["return"]; | |
if (returnMethod) { | |
var record = tryCatch(returnMethod, delegate.iterator, arg); | |
if (record.type === "throw") { | |
// If the return method threw an exception, let that | |
// exception prevail over the original return or throw. | |
method = "throw"; | |
arg = record.arg; | |
continue; | |
} | |
} | |
if (method === "return") { | |
// Continue with the outer return, now that the delegate | |
// iterator has been terminated. | |
continue; | |
} | |
} | |
var record = tryCatch( | |
delegate.iterator[method], | |
delegate.iterator, | |
arg | |
); | |
if (record.type === "throw") { | |
context.delegate = null; | |
// Like returning generator.throw(uncaught), but without the | |
// overhead of an extra function call. | |
method = "throw"; | |
arg = record.arg; | |
continue; | |
} | |
// Delegate generator ran and handled its own exceptions so | |
// regardless of what the method was, we continue as if it is | |
// "next" with an undefined arg. | |
method = "next"; | |
arg = undefined; | |
var info = record.arg; | |
if (info.done) { | |
context[delegate.resultName] = info.value; | |
context.next = delegate.nextLoc; | |
} else { | |
state = GenStateSuspendedYield; | |
return info; | |
} | |
context.delegate = null; | |
} | |
if (method === "next") { | |
// Setting context._sent for legacy support of Babel's | |
// function.sent implementation. | |
context.sent = context._sent = arg; | |
} else if (method === "throw") { | |
if (state === GenStateSuspendedStart) { | |
state = GenStateCompleted; | |
throw arg; | |
} | |
if (context.dispatchException(arg)) { | |
// If the dispatched exception was caught by a catch block, | |
// then let that catch block handle the exception normally. | |
method = "next"; | |
arg = undefined; | |
} | |
} else if (method === "return") { | |
context.abrupt("return", arg); | |
} | |
state = GenStateExecuting; | |
var record = tryCatch(innerFn, self, context); | |
if (record.type === "normal") { | |
// If an exception is thrown from innerFn, we leave state === | |
// GenStateExecuting and loop back for another invocation. | |
state = context.done | |
? GenStateCompleted | |
: GenStateSuspendedYield; | |
var info = { | |
value: record.arg, | |
done: context.done | |
}; | |
if (record.arg === ContinueSentinel) { | |
if (context.delegate && method === "next") { | |
// Deliberately forget the last sent value so that we don't | |
// accidentally pass it on to the delegate. | |
arg = undefined; | |
} | |
} else { | |
return info; | |
} | |
} else if (record.type === "throw") { | |
state = GenStateCompleted; | |
// Dispatch the exception by looping back around to the | |
// context.dispatchException(arg) call above. | |
method = "throw"; | |
arg = record.arg; | |
} | |
} | |
}; | |
} | |
// Define Generator.prototype.{next,throw,return} in terms of the | |
// unified ._invoke helper method. | |
defineIteratorMethods(Gp); | |
Gp[toStringTagSymbol] = "Generator"; | |
Gp.toString = function() { | |
return "[object Generator]"; | |
}; | |
function pushTryEntry(locs) { | |
var entry = { tryLoc: locs[0] }; | |
if (1 in locs) { | |
entry.catchLoc = locs[1]; | |
} | |
if (2 in locs) { | |
entry.finallyLoc = locs[2]; | |
entry.afterLoc = locs[3]; | |
} | |
this.tryEntries.push(entry); | |
} | |
function resetTryEntry(entry) { | |
var record = entry.completion || {}; | |
record.type = "normal"; | |
delete record.arg; | |
entry.completion = record; | |
} | |
function Context(tryLocsList) { | |
// The root entry object (effectively a try statement without a catch | |
// or a finally block) gives us a place to store values thrown from | |
// locations where there is no enclosing try statement. | |
this.tryEntries = [{ tryLoc: "root" }]; | |
tryLocsList.forEach(pushTryEntry, this); | |
this.reset(true); | |
} | |
runtime.keys = function(object) { | |
var keys = []; | |
for (var key in object) { | |
keys.push(key); | |
} | |
keys.reverse(); | |
// Rather than returning an object with a next method, we keep | |
// things simple and return the next function itself. | |
return function next() { | |
while (keys.length) { | |
var key = keys.pop(); | |
if (key in object) { | |
next.value = key; | |
next.done = false; | |
return next; | |
} | |
} | |
// To avoid creating an additional object, we just hang the .value | |
// and .done properties off the next function object itself. This | |
// also ensures that the minifier will not anonymize the function. | |
next.done = true; | |
return next; | |
}; | |
}; | |
function values(iterable) { | |
if (iterable) { | |
var iteratorMethod = iterable[iteratorSymbol]; | |
if (iteratorMethod) { | |
return iteratorMethod.call(iterable); | |
} | |
if (typeof iterable.next === "function") { | |
return iterable; | |
} | |
if (!isNaN(iterable.length)) { | |
var i = -1, next = function next() { | |
while (++i < iterable.length) { | |
if (hasOwn.call(iterable, i)) { | |
next.value = iterable[i]; | |
next.done = false; | |
return next; | |
} | |
} | |
next.value = undefined; | |
next.done = true; | |
return next; | |
}; | |
return next.next = next; | |
} | |
} | |
// Return an iterator with no values. | |
return { next: doneResult }; | |
} | |
runtime.values = values; | |
function doneResult() { | |
return { value: undefined, done: true }; | |
} | |
Context.prototype = { | |
constructor: Context, | |
reset: function(skipTempReset) { | |
this.prev = 0; | |
this.next = 0; | |
// Resetting context._sent for legacy support of Babel's | |
// function.sent implementation. | |
this.sent = this._sent = undefined; | |
this.done = false; | |
this.delegate = null; | |
this.tryEntries.forEach(resetTryEntry); | |
if (!skipTempReset) { | |
for (var name in this) { | |
// Not sure about the optimal order of these conditions: | |
if (name.charAt(0) === "t" && | |
hasOwn.call(this, name) && | |
!isNaN(+name.slice(1))) { | |
this[name] = undefined; | |
} | |
} | |
} | |
}, | |
stop: function() { | |
this.done = true; | |
var rootEntry = this.tryEntries[0]; | |
var rootRecord = rootEntry.completion; | |
if (rootRecord.type === "throw") { | |
throw rootRecord.arg; | |
} | |
return this.rval; | |
}, | |
dispatchException: function(exception) { | |
if (this.done) { | |
throw exception; | |
} | |
var context = this; | |
function handle(loc, caught) { | |
record.type = "throw"; | |
record.arg = exception; | |
context.next = loc; | |
return !!caught; | |
} | |
for (var i = this.tryEntries.length - 1; i >= 0; --i) { | |
var entry = this.tryEntries[i]; | |
var record = entry.completion; | |
if (entry.tryLoc === "root") { | |
// Exception thrown outside of any try block that could handle | |
// it, so set the completion value of the entire function to | |
// throw the exception. | |
return handle("end"); | |
} | |
if (entry.tryLoc <= this.prev) { | |
var hasCatch = hasOwn.call(entry, "catchLoc"); | |
var hasFinally = hasOwn.call(entry, "finallyLoc"); | |
if (hasCatch && hasFinally) { | |
if (this.prev < entry.catchLoc) { | |
return handle(entry.catchLoc, true); | |
} else if (this.prev < entry.finallyLoc) { | |
return handle(entry.finallyLoc); | |
} | |
} else if (hasCatch) { | |
if (this.prev < entry.catchLoc) { | |
return handle(entry.catchLoc, true); | |
} | |
} else if (hasFinally) { | |
if (this.prev < entry.finallyLoc) { | |
return handle(entry.finallyLoc); | |
} | |
} else { | |
throw new Error("try statement without catch or finally"); | |
} | |
} | |
} | |
}, | |
abrupt: function(type, arg) { | |
for (var i = this.tryEntries.length - 1; i >= 0; --i) { | |
var entry = this.tryEntries[i]; | |
if (entry.tryLoc <= this.prev && | |
hasOwn.call(entry, "finallyLoc") && | |
this.prev < entry.finallyLoc) { | |
var finallyEntry = entry; | |
break; | |
} | |
} | |
if (finallyEntry && | |
(type === "break" || | |
type === "continue") && | |
finallyEntry.tryLoc <= arg && | |
arg <= finallyEntry.finallyLoc) { | |
// Ignore the finally entry if control is not jumping to a | |
// location outside the try/catch block. | |
finallyEntry = null; | |
} | |
var record = finallyEntry ? finallyEntry.completion : {}; | |
record.type = type; | |
record.arg = arg; | |
if (finallyEntry) { | |
this.next = finallyEntry.finallyLoc; | |
} else { | |
this.complete(record); | |
} | |
return ContinueSentinel; | |
}, | |
complete: function(record, afterLoc) { | |
if (record.type === "throw") { | |
throw record.arg; | |
} | |
if (record.type === "break" || | |
record.type === "continue") { | |
this.next = record.arg; | |
} else if (record.type === "return") { | |
this.rval = record.arg; | |
this.next = "end"; | |
} else if (record.type === "normal" && afterLoc) { | |
this.next = afterLoc; | |
} | |
}, | |
finish: function(finallyLoc) { | |
for (var i = this.tryEntries.length - 1; i >= 0; --i) { | |
var entry = this.tryEntries[i]; | |
if (entry.finallyLoc === finallyLoc) { | |
this.complete(entry.completion, entry.afterLoc); | |
resetTryEntry(entry); | |
return ContinueSentinel; | |
} | |
} | |
}, | |
"catch": function(tryLoc) { | |
for (var i = this.tryEntries.length - 1; i >= 0; --i) { | |
var entry = this.tryEntries[i]; | |
if (entry.tryLoc === tryLoc) { | |
var record = entry.completion; | |
if (record.type === "throw") { | |
var thrown = record.arg; | |
resetTryEntry(entry); | |
} | |
return thrown; | |
} | |
} | |
// The context.catch method must only be called with a location | |
// argument that corresponds to a known catch block. | |
throw new Error("illegal catch attempt"); | |
}, | |
delegateYield: function(iterable, resultName, nextLoc) { | |
this.delegate = { | |
iterator: values(iterable), | |
resultName: resultName, | |
nextLoc: nextLoc | |
}; | |
return ContinueSentinel; | |
} | |
}; | |
})( | |
// Among the various tricks for obtaining a reference to the global | |
// object, this seems to be the most reliable technique that does not | |
// use indirect eval (which violates Content Security Policy). | |
typeof global === "object" ? global : | |
typeof window === "object" ? window : | |
typeof self === "object" ? self : this | |
); | |
/* jshint esversion: 6 */ | |
/* jshint noyield: true */ | |
"use strict"; | |
//TODO: | |
//- LabeledStatement -> including use in break/continue | |
//- nicer error handling? | |
//-> TESTS | |
//-> BENCHMARKS | |
var parse = require('acorn').parse; | |
var util = require("util"); | |
var EventEmitter = require("events").EventEmitter; | |
function noop() {} | |
function execute(func) { | |
var result = func(); | |
if ('' + result === 'null') { | |
return result; | |
} | |
// FIXME: Convert to yield* | |
if (result !== undefined) { | |
if (result.next) { | |
var iter = result; | |
var res = iter.next(); | |
while (!res.done) { | |
res = iter.next(); | |
} | |
if ('' + res.value === 'null') { | |
return res.value; | |
} | |
if ('' + res.value === 'undefined') { | |
return res.value; | |
} | |
return res.value; | |
} | |
} | |
return result; | |
} | |
function Arguments() { | |
//TODO: add es3 'arguments.callee'? | |
} | |
Arguments.prototype.toString = function () { | |
return '[object Arguments]'; | |
}; | |
function Return(val) { | |
this.value = val; | |
} | |
// need something unique to compare a against. | |
var Break = {}; | |
var Continue = {}; | |
function Environment(globalObjects) { | |
EventEmitter.call(this); | |
if (!Array.isArray(globalObjects)) { | |
globalObjects = [globalObjects]; | |
} | |
var parent; | |
globalObjects.forEach(function (vars) { | |
parent = createVarStore(parent, vars); | |
}); | |
// the topmost store is our current store | |
this._curVarStore = parent; | |
this._curDeclarations = {}; | |
this._globalObj = globalObjects[0]; | |
this._curThis = this._globalObj; | |
this._boundGen = this._gen.bind(this); | |
this.DEBUG = false; | |
this.DELAY = 0; | |
this.STATE = 'running'; | |
} | |
util.inherits(Environment, EventEmitter); | |
function createVarStore(parent, vars) { | |
vars = vars || {}; | |
return { | |
parent: parent, | |
vars: vars | |
}; | |
} | |
Environment.prototype.gen = function (node) { | |
var opts = { | |
'locations': true | |
}; | |
if (typeof node === 'string') { | |
node = parse(node, opts); | |
} | |
var resp = this._gen(node); | |
addDeclarationsToStore(this._curDeclarations, this._curVarStore); | |
this._curDeclarations = {}; | |
return resp; | |
}; | |
Environment.prototype._gen = function (node) { | |
var closure = ({ | |
BinaryExpression: this._genBinExpr, | |
LogicalExpression: this._genBinExpr, | |
UnaryExpression: this._genUnaryExpr, | |
UpdateExpression: this._genUpdExpr, | |
ObjectExpression: this._genObjExpr, | |
ArrayExpression: this._genArrExpr, | |
CallExpression: this._genCallExpr, | |
NewExpression: this._genNewExpr, | |
MemberExpression: this._genMemExpr, | |
ThisExpression: this._genThisExpr, | |
SequenceExpression: this._genSeqExpr, | |
Literal: this._genLit, | |
Identifier: this._genIdent, | |
AssignmentExpression: this._genAssignExpr, | |
FunctionDeclaration: this._genFuncDecl, | |
VariableDeclaration: this._genVarDecl, | |
BlockStatement: this._genProgram, | |
Program: this._genProgram, | |
ExpressionStatement: this._genExprStmt, | |
EmptyStatement: this._genEmptyStmt, | |
ReturnStatement: this._genRetStmt, | |
FunctionExpression: this._genFuncExpr, | |
IfStatement: this._genIfStmt, | |
ConditionalExpression: this._genCondStmt, | |
ForStatement: this._genLoopStmt, | |
WhileStatement: this._genLoopStmt, | |
DoWhileStatement: this._genDoWhileStmt, | |
ForInStatement: this._genForInStmt, | |
WithStatement: this._genWithStmt, | |
ThrowStatement: this._genThrowStmt, | |
TryStatement: this._genTryStmt, | |
ContinueStatement: this._genContStmt, | |
BreakStatement: this._genBreakStmt, | |
SwitchStatement: this._genSwitchStmt | |
}[node.type] || function () { | |
console.warn("Not implemented yet: " + node.type); | |
return noop; | |
}).call(this, node); | |
if (this.DEBUG) { | |
return function () { | |
var info = 'closure for ' + node.type + ' called'; | |
var line = ((node.loc || {}).start || {}).line; | |
if (line) { | |
info += ' while processing line ' + line; | |
} | |
var resp = closure(); | |
info += '. Result:'; | |
console.log(info, resp); | |
return resp; | |
}; | |
} | |
return closure; | |
}; | |
Environment.prototype._genBinExpr = function (node) { | |
var _marked = [callExpr].map(regeneratorRuntime.mark); | |
var a = this._gen(node.left); | |
var b = this._gen(node.right); | |
function callExpr(expr) { | |
var result; | |
return regeneratorRuntime.wrap(function callExpr$(_context) { | |
while (1) { | |
switch (_context.prev = _context.next) { | |
case 0: | |
if (!(expr.constructor.name == 'GeneratorFunction')) { | |
_context.next = 5; | |
break; | |
} | |
return _context.delegateYield(expr(), "t0", 2); | |
case 2: | |
result = _context.t0; | |
_context.next = 6; | |
break; | |
case 5: | |
result = expr(); | |
case 6: | |
return _context.abrupt("return", result); | |
case 7: | |
case "end": | |
return _context.stop(); | |
} | |
} | |
}, _marked[0], this); | |
} | |
var cmp = { | |
'==': regeneratorRuntime.mark(function _callee() { | |
return regeneratorRuntime.wrap(function _callee$(_context2) { | |
while (1) { | |
switch (_context2.prev = _context2.next) { | |
case 0: | |
return _context2.delegateYield(callExpr(a), "t0", 1); | |
case 1: | |
_context2.t1 = _context2.t0; | |
return _context2.delegateYield(callExpr(b), "t2", 3); | |
case 3: | |
_context2.t3 = _context2.t2; | |
return _context2.abrupt("return", _context2.t1 == _context2.t3); | |
case 5: | |
case "end": | |
return _context2.stop(); | |
} | |
} | |
}, _callee, this); | |
}), | |
'!=': regeneratorRuntime.mark(function _callee2() { | |
return regeneratorRuntime.wrap(function _callee2$(_context3) { | |
while (1) { | |
switch (_context3.prev = _context3.next) { | |
case 0: | |
return _context3.delegateYield(callExpr(a), "t0", 1); | |
case 1: | |
_context3.t1 = _context3.t0; | |
return _context3.delegateYield(callExpr(b), "t2", 3); | |
case 3: | |
_context3.t3 = _context3.t2; | |
return _context3.abrupt("return", _context3.t1 != _context3.t3); | |
case 5: | |
case "end": | |
return _context3.stop(); | |
} | |
} | |
}, _callee2, this); | |
}), | |
'===': regeneratorRuntime.mark(function _callee3() { | |
return regeneratorRuntime.wrap(function _callee3$(_context4) { | |
while (1) { | |
switch (_context4.prev = _context4.next) { | |
case 0: | |
return _context4.delegateYield(callExpr(a), "t0", 1); | |
case 1: | |
_context4.t1 = _context4.t0; | |
return _context4.delegateYield(callExpr(b), "t2", 3); | |
case 3: | |
_context4.t3 = _context4.t2; | |
return _context4.abrupt("return", _context4.t1 === _context4.t3); | |
case 5: | |
case "end": | |
return _context4.stop(); | |
} | |
} | |
}, _callee3, this); | |
}), | |
'!==': regeneratorRuntime.mark(function _callee4() { | |
return regeneratorRuntime.wrap(function _callee4$(_context5) { | |
while (1) { | |
switch (_context5.prev = _context5.next) { | |
case 0: | |
return _context5.delegateYield(callExpr(a), "t0", 1); | |
case 1: | |
_context5.t1 = _context5.t0; | |
return _context5.delegateYield(callExpr(b), "t2", 3); | |
case 3: | |
_context5.t3 = _context5.t2; | |
return _context5.abrupt("return", _context5.t1 !== _context5.t3); | |
case 5: | |
case "end": | |
return _context5.stop(); | |
} | |
} | |
}, _callee4, this); | |
}), | |
'<': regeneratorRuntime.mark(function _callee5() { | |
return regeneratorRuntime.wrap(function _callee5$(_context6) { | |
while (1) { | |
switch (_context6.prev = _context6.next) { | |
case 0: | |
return _context6.delegateYield(callExpr(a), "t0", 1); | |
case 1: | |
_context6.t1 = _context6.t0; | |
return _context6.delegateYield(callExpr(b), "t2", 3); | |
case 3: | |
_context6.t3 = _context6.t2; | |
return _context6.abrupt("return", _context6.t1 < _context6.t3); | |
case 5: | |
case "end": | |
return _context6.stop(); | |
} | |
} | |
}, _callee5, this); | |
}), | |
'<=': regeneratorRuntime.mark(function _callee6() { | |
return regeneratorRuntime.wrap(function _callee6$(_context7) { | |
while (1) { | |
switch (_context7.prev = _context7.next) { | |
case 0: | |
return _context7.delegateYield(callExpr(a), "t0", 1); | |
case 1: | |
_context7.t1 = _context7.t0; | |
return _context7.delegateYield(callExpr(b), "t2", 3); | |
case 3: | |
_context7.t3 = _context7.t2; | |
return _context7.abrupt("return", _context7.t1 <= _context7.t3); | |
case 5: | |
case "end": | |
return _context7.stop(); | |
} | |
} | |
}, _callee6, this); | |
}), | |
'>': regeneratorRuntime.mark(function _callee7() { | |
return regeneratorRuntime.wrap(function _callee7$(_context8) { | |
while (1) { | |
switch (_context8.prev = _context8.next) { | |
case 0: | |
return _context8.delegateYield(callExpr(a), "t0", 1); | |
case 1: | |
_context8.t1 = _context8.t0; | |
return _context8.delegateYield(callExpr(b), "t2", 3); | |
case 3: | |
_context8.t3 = _context8.t2; | |
return _context8.abrupt("return", _context8.t1 > _context8.t3); | |
case 5: | |
case "end": | |
return _context8.stop(); | |
} | |
} | |
}, _callee7, this); | |
}), | |
'>=': regeneratorRuntime.mark(function _callee8() { | |
return regeneratorRuntime.wrap(function _callee8$(_context9) { | |
while (1) { | |
switch (_context9.prev = _context9.next) { | |
case 0: | |
return _context9.delegateYield(callExpr(a), "t0", 1); | |
case 1: | |
_context9.t1 = _context9.t0; | |
return _context9.delegateYield(callExpr(b), "t2", 3); | |
case 3: | |
_context9.t3 = _context9.t2; | |
return _context9.abrupt("return", _context9.t1 >= _context9.t3); | |
case 5: | |
case "end": | |
return _context9.stop(); | |
} | |
} | |
}, _callee8, this); | |
}), | |
'<<': regeneratorRuntime.mark(function _callee9() { | |
return regeneratorRuntime.wrap(function _callee9$(_context10) { | |
while (1) { | |
switch (_context10.prev = _context10.next) { | |
case 0: | |
return _context10.delegateYield(callExpr(a), "t0", 1); | |
case 1: | |
_context10.t1 = _context10.t0; | |
return _context10.delegateYield(callExpr(b), "t2", 3); | |
case 3: | |
_context10.t3 = _context10.t2; | |
return _context10.abrupt("return", _context10.t1 << _context10.t3); | |
case 5: | |
case "end": | |
return _context10.stop(); | |
} | |
} | |
}, _callee9, this); | |
}), | |
'>>': regeneratorRuntime.mark(function _callee10() { | |
return regeneratorRuntime.wrap(function _callee10$(_context11) { | |
while (1) { | |
switch (_context11.prev = _context11.next) { | |
case 0: | |
return _context11.delegateYield(callExpr(a), "t0", 1); | |
case 1: | |
_context11.t1 = _context11.t0; | |
return _context11.delegateYield(callExpr(b), "t2", 3); | |
case 3: | |
_context11.t3 = _context11.t2; | |
return _context11.abrupt("return", _context11.t1 >> _context11.t3); | |
case 5: | |
case "end": | |
return _context11.stop(); | |
} | |
} | |
}, _callee10, this); | |
}), | |
'>>>': regeneratorRuntime.mark(function _callee11() { | |
return regeneratorRuntime.wrap(function _callee11$(_context12) { | |
while (1) { | |
switch (_context12.prev = _context12.next) { | |
case 0: | |
return _context12.delegateYield(callExpr(a), "t0", 1); | |
case 1: | |
_context12.t1 = _context12.t0; | |
return _context12.delegateYield(callExpr(b), "t2", 3); | |
case 3: | |
_context12.t3 = _context12.t2; | |
return _context12.abrupt("return", _context12.t1 >>> _context12.t3); | |
case 5: | |
case "end": | |
return _context12.stop(); | |
} | |
} | |
}, _callee11, this); | |
}), | |
'+': regeneratorRuntime.mark(function _callee12() { | |
return regeneratorRuntime.wrap(function _callee12$(_context13) { | |
while (1) { | |
switch (_context13.prev = _context13.next) { | |
case 0: | |
return _context13.delegateYield(callExpr(a), "t0", 1); | |
case 1: | |
_context13.t1 = _context13.t0; | |
return _context13.delegateYield(callExpr(b), "t2", 3); | |
case 3: | |
_context13.t3 = _context13.t2; | |
return _context13.abrupt("return", _context13.t1 + _context13.t3); | |
case 5: | |
case "end": | |
return _context13.stop(); | |
} | |
} | |
}, _callee12, this); | |
}), | |
'-': regeneratorRuntime.mark(function _callee13() { | |
return regeneratorRuntime.wrap(function _callee13$(_context14) { | |
while (1) { | |
switch (_context14.prev = _context14.next) { | |
case 0: | |
return _context14.delegateYield(callExpr(a), "t0", 1); | |
case 1: | |
_context14.t1 = _context14.t0; | |
return _context14.delegateYield(callExpr(b), "t2", 3); | |
case 3: | |
_context14.t3 = _context14.t2; | |
return _context14.abrupt("return", _context14.t1 - _context14.t3); | |
case 5: | |
case "end": | |
return _context14.stop(); | |
} | |
} | |
}, _callee13, this); | |
}), | |
'*': regeneratorRuntime.mark(function _callee14() { | |
return regeneratorRuntime.wrap(function _callee14$(_context15) { | |
while (1) { | |
switch (_context15.prev = _context15.next) { | |
case 0: | |
return _context15.delegateYield(callExpr(a), "t0", 1); | |
case 1: | |
_context15.t1 = _context15.t0; | |
return _context15.delegateYield(callExpr(b), "t2", 3); | |
case 3: | |
_context15.t3 = _context15.t2; | |
return _context15.abrupt("return", _context15.t1 * _context15.t3); | |
case 5: | |
case "end": | |
return _context15.stop(); | |
} | |
} | |
}, _callee14, this); | |
}), | |
'/': regeneratorRuntime.mark(function _callee15() { | |
return regeneratorRuntime.wrap(function _callee15$(_context16) { | |
while (1) { | |
switch (_context16.prev = _context16.next) { | |
case 0: | |
return _context16.delegateYield(callExpr(a), "t0", 1); | |
case 1: | |
_context16.t1 = _context16.t0; | |
return _context16.delegateYield(callExpr(b), "t2", 3); | |
case 3: | |
_context16.t3 = _context16.t2; | |
return _context16.abrupt("return", _context16.t1 / _context16.t3); | |
case 5: | |
case "end": | |
return _context16.stop(); | |
} | |
} | |
}, _callee15, this); | |
}), | |
'%': regeneratorRuntime.mark(function _callee16() { | |
return regeneratorRuntime.wrap(function _callee16$(_context17) { | |
while (1) { | |
switch (_context17.prev = _context17.next) { | |
case 0: | |
return _context17.delegateYield(callExpr(a), "t0", 1); | |
case 1: | |
_context17.t1 = _context17.t0; | |
return _context17.delegateYield(callExpr(b), "t2", 3); | |
case 3: | |
_context17.t3 = _context17.t2; | |
return _context17.abrupt("return", _context17.t1 % _context17.t3); | |
case 5: | |
case "end": | |
return _context17.stop(); | |
} | |
} | |
}, _callee16, this); | |
}), | |
'|': regeneratorRuntime.mark(function _callee17() { | |
return regeneratorRuntime.wrap(function _callee17$(_context18) { | |
while (1) { | |
switch (_context18.prev = _context18.next) { | |
case 0: | |
return _context18.delegateYield(callExpr(a), "t0", 1); | |
case 1: | |
_context18.t1 = _context18.t0; | |
return _context18.delegateYield(callExpr(b), "t2", 3); | |
case 3: | |
_context18.t3 = _context18.t2; | |
return _context18.abrupt("return", _context18.t1 | _context18.t3); | |
case 5: | |
case "end": | |
return _context18.stop(); | |
} | |
} | |
}, _callee17, this); | |
}), | |
'^': regeneratorRuntime.mark(function _callee18() { | |
return regeneratorRuntime.wrap(function _callee18$(_context19) { | |
while (1) { | |
switch (_context19.prev = _context19.next) { | |
case 0: | |
return _context19.delegateYield(callExpr(a), "t0", 1); | |
case 1: | |
_context19.t1 = _context19.t0; | |
return _context19.delegateYield(callExpr(b), "t2", 3); | |
case 3: | |
_context19.t3 = _context19.t2; | |
return _context19.abrupt("return", _context19.t1 ^ _context19.t3); | |
case 5: | |
case "end": | |
return _context19.stop(); | |
} | |
} | |
}, _callee18, this); | |
}), | |
'&': regeneratorRuntime.mark(function _callee19() { | |
return regeneratorRuntime.wrap(function _callee19$(_context20) { | |
while (1) { | |
switch (_context20.prev = _context20.next) { | |
case 0: | |
return _context20.delegateYield(callExpr(a), "t0", 1); | |
case 1: | |
_context20.t1 = _context20.t0; | |
return _context20.delegateYield(callExpr(b), "t2", 3); | |
case 3: | |
_context20.t3 = _context20.t2; | |
return _context20.abrupt("return", _context20.t1 & _context20.t3); | |
case 5: | |
case "end": | |
return _context20.stop(); | |
} | |
} | |
}, _callee19, this); | |
}), | |
'in': regeneratorRuntime.mark(function _callee20() { | |
return regeneratorRuntime.wrap(function _callee20$(_context21) { | |
while (1) { | |
switch (_context21.prev = _context21.next) { | |
case 0: | |
return _context21.delegateYield(callExpr(a), "t0", 1); | |
case 1: | |
_context21.t1 = _context21.t0; | |
return _context21.delegateYield(callExpr(b), "t2", 3); | |
case 3: | |
_context21.t3 = _context21.t2; | |
return _context21.abrupt("return", _context21.t1 in _context21.t3); | |
case 5: | |
case "end": | |
return _context21.stop(); | |
} | |
} | |
}, _callee20, this); | |
}), | |
'instanceof': regeneratorRuntime.mark(function _callee21() { | |
return regeneratorRuntime.wrap(function _callee21$(_context22) { | |
while (1) { | |
switch (_context22.prev = _context22.next) { | |
case 0: | |
return _context22.delegateYield(callExpr(a), "t0", 1); | |
case 1: | |
_context22.t1 = _context22.t0; | |
return _context22.delegateYield(callExpr(b), "t2", 3); | |
case 3: | |
_context22.t3 = _context22.t2; | |
return _context22.abrupt("return", _context22.t1 instanceof _context22.t3); | |
case 5: | |
case "end": | |
return _context22.stop(); | |
} | |
} | |
}, _callee21, this); | |
}), | |
// logic expressions | |
'||': regeneratorRuntime.mark(function _callee22() { | |
return regeneratorRuntime.wrap(function _callee22$(_context23) { | |
while (1) { | |
switch (_context23.prev = _context23.next) { | |
case 0: | |
return _context23.delegateYield(callExpr(a), "t1", 1); | |
case 1: | |
_context23.t0 = _context23.t1; | |
if (_context23.t0) { | |
_context23.next = 5; | |
break; | |
} | |
return _context23.delegateYield(callExpr(b), "t2", 4); | |
case 4: | |
_context23.t0 = _context23.t2; | |
case 5: | |
return _context23.abrupt("return", _context23.t0); | |
case 6: | |
case "end": | |
return _context23.stop(); | |
} | |
} | |
}, _callee22, this); | |
}), | |
'&&': regeneratorRuntime.mark(function _callee23() { | |
return regeneratorRuntime.wrap(function _callee23$(_context24) { | |
while (1) { | |
switch (_context24.prev = _context24.next) { | |
case 0: | |
return _context24.delegateYield(callExpr(a), "t1", 1); | |
case 1: | |
_context24.t0 = _context24.t1; | |
if (!_context24.t0) { | |
_context24.next = 5; | |
break; | |
} | |
return _context24.delegateYield(callExpr(b), "t2", 4); | |
case 4: | |
_context24.t0 = _context24.t2; | |
case 5: | |
return _context24.abrupt("return", _context24.t0); | |
case 6: | |
case "end": | |
return _context24.stop(); | |
} | |
} | |
}, _callee23, this); | |
}) | |
}[node.operator]; | |
return function () { | |
// FIXME: Convert to yield* | |
var iter = cmp(); | |
var res = iter.next(); | |
while (!res.done) { | |
res = iter.next(); | |
} | |
return res.value; | |
}; | |
}; | |
Environment.prototype._genUnaryExpr = function (node) { | |
if (node.operator === 'delete') { | |
return this._genDelete(node); | |
} | |
var a = this._gen(node.argument); | |
var op = { | |
'-': function () { | |
return -a(); | |
}, | |
'+': function () { | |
return +a(); | |
}, | |
'!': function () { | |
return !a(); | |
}, | |
'~': function () { | |
return ~a(); | |
}, | |
'typeof': function () { | |
return typeof a(); | |
}, | |
'void': function () { | |
return void a(); | |
} | |
}[node.operator]; | |
return function () { | |
return op(); | |
}; | |
}; | |
Environment.prototype._genDelete = function (node) { | |
var obj = this._genObj(node.argument); | |
var attr = this._genName(node.argument); | |
return function () { | |
return delete obj()[attr()]; | |
}; | |
}; | |
Environment.prototype._genObjExpr = function (node) { | |
//TODO property.kind: don't assume init when it can also be set/get | |
var self = this; | |
var items = []; | |
node.properties.forEach(function (property) { | |
// object expression keys are static so can be calculated | |
// immediately | |
var key = self._objKey(property.key)(); | |
items.push({ | |
key: key, | |
getVal: self._gen(property.value) | |
}); | |
}); | |
return function () { | |
var result = {}; | |
items.forEach(function (item) { | |
result[item.key] = item.getVal(); | |
}); | |
return result; | |
}; | |
}; | |
Environment.prototype._genArrExpr = function (node) { | |
var items = node.elements.map(this._boundGen); | |
return function () { | |
return items.map(execute); | |
}; | |
}; | |
Environment.prototype._objKey = function (node) { | |
var key; | |
if (node.type === 'Identifier') { | |
key = node.name; | |
} else { | |
key = this._gen(node)(); | |
} | |
return function () { | |
return key; | |
}; | |
}; | |
Environment.prototype._genCallExpr = function (node) { | |
var self = this; | |
var callee; | |
if (node.callee.type === 'MemberExpression') { | |
var obj = self._genObj(node.callee); | |
var name = self._genName(node.callee); | |
callee = function () { | |
var theObj = obj(); | |
return theObj[name()].bind(theObj); | |
}; | |
} else { | |
callee = self._gen(node.callee); | |
} | |
var args = node.arguments.map(self._gen.bind(self)); | |
return regeneratorRuntime.mark(function _callee24() { | |
var c, result, res; | |
return regeneratorRuntime.wrap(function _callee24$(_context25) { | |
while (1) { | |
switch (_context25.prev = _context25.next) { | |
case 0: | |
self.emit('line', node.loc.start.line); | |
c = callee(); | |
if (!(c === undefined)) { | |
_context25.next = 4; | |
break; | |
} | |
return _context25.abrupt("return", c); | |
case 4: | |
if (!c.next) { | |
_context25.next = 10; | |
break; | |
} | |
return _context25.delegateYield(c, "t0", 6); | |
case 6: | |
res = _context25.t0; | |
result = res.apply(self._globalObj, args.map(execute)); | |
_context25.next = 11; | |
break; | |
case 10: | |
result = c.apply(self._globalObj, args.map(execute)); | |
case 11: | |
if (!(result !== undefined)) { | |
_context25.next = 16; | |
break; | |
} | |
if (!result.next) { | |
_context25.next = 16; | |
break; | |
} | |
return _context25.delegateYield(result, "t1", 14); | |
case 14: | |
res = _context25.t1; | |
return _context25.abrupt("return", res); | |
case 16: | |
return _context25.abrupt("return", result); | |
case 17: | |
case "end": | |
return _context25.stop(); | |
} | |
} | |
}, _callee24, this); | |
}); | |
}; | |
Environment.prototype._genNewExpr = function (node) { | |
var callee = this._gen(node.callee); | |
var args = node.arguments.map(this._boundGen); | |
var self = this; | |
return regeneratorRuntime.mark(function _callee25() { | |
var cl, ar, newObject, constructor; | |
return regeneratorRuntime.wrap(function _callee25$(_context26) { | |
while (1) { | |
switch (_context26.prev = _context26.next) { | |
case 0: | |
self.emit('line', node.loc.start.line); | |
cl = callee(); | |
ar = args.map(execute); | |
newObject = Object.create(cl.prototype); | |
constructor = cl.apply(newObject, ar); | |
return _context26.delegateYield(constructor, "t0", 6); | |
case 6: | |
return _context26.abrupt("return", newObject); | |
case 7: | |
case "end": | |
return _context26.stop(); | |
} | |
} | |
}, _callee25, this); | |
}); | |
}; | |
Environment.prototype._genMemExpr = function (node) { | |
var self = this; | |
var obj = this._gen(node.object); | |
var property = this._memExprProperty(node); | |
return function () { | |
self.emit('line', node.loc.start.line); | |
return obj()[property()]; | |
}; | |
}; | |
Environment.prototype._memExprProperty = function (node) { | |
return node.computed ? this._gen(node.property) : this._objKey(node.property); | |
}; | |
Environment.prototype._genThisExpr = function () { | |
var self = this; | |
return function () { | |
return self._curThis; | |
}; | |
}; | |
Environment.prototype._genSeqExpr = function (node) { | |
var exprs = node.expressions.map(this._boundGen); | |
return function () { | |
var result; | |
exprs.forEach(function (expr) { | |
result = expr(); | |
}); | |
return result; | |
}; | |
}; | |
Environment.prototype._genUpdExpr = function (node) { | |
var self = this; | |
var update = { | |
'--true': function (obj, name) { | |
return --obj[name]; | |
}, | |
'--false': function (obj, name) { | |
return obj[name]--; | |
}, | |
'++true': function (obj, name) { | |
return ++obj[name]; | |
}, | |
'++false': function (obj, name) { | |
return obj[name]++; | |
} | |
}[node.operator + node.prefix]; | |
var obj = this._genObj(node.argument); | |
var name = this._genName(node.argument); | |
return regeneratorRuntime.mark(function _callee26() { | |
return regeneratorRuntime.wrap(function _callee26$(_context27) { | |
while (1) { | |
switch (_context27.prev = _context27.next) { | |
case 0: | |
self.emit('line', node.loc.start.line); | |
_context27.next = 3; | |
return; | |
case 3: | |
return _context27.abrupt("return", update(obj(), name())); | |
case 4: | |
case "end": | |
return _context27.stop(); | |
} | |
} | |
}, _callee26, this); | |
}); | |
}; | |
Environment.prototype._genObj = function (node) { | |
if (node.type === 'Identifier') { | |
return this._getVarStore.bind(this, node.name); | |
} else if (node.type === 'MemberExpression') { | |
return this._gen(node.object); | |
} else { | |
console.warn("Unknown _genObj() type: " + node.type); | |
return noop; | |
} | |
}; | |
Environment.prototype._genName = function (node) { | |
if (node.type === 'Identifier') { | |
return function () { | |
return node.name; | |
}; | |
} else if (node.type === 'MemberExpression') { | |
return this._memExprProperty(node); | |
} else { | |
console.warn("Unknown _genName() type: " + node.type); | |
return noop; | |
} | |
}; | |
Environment.prototype._genLit = function (node) { | |
return function () { | |
return node.value; | |
}; | |
}; | |
Environment.prototype._genIdent = function (node) { | |
var self = this; | |
return function () { | |
return self._getVarStore(node.name)[node.name]; | |
}; | |
}; | |
Environment.prototype._getVarStore = function (name) { | |
var store = this._curVarStore; | |
do { | |
if (store.vars.hasOwnProperty(name)) { | |
return store.vars; | |
} | |
} while (store = store.parent); | |
// global object as fallback | |
return this._globalObj; | |
}; | |
Environment.prototype._genAssignExpr = function (node) { | |
var self = this; | |
var setter = { | |
'=': function (obj, name, val) { | |
return obj[name] = val; | |
}, | |
'+=': function (obj, name, val) { | |
return obj[name] += val; | |
}, | |
'-=': function (obj, name, val) { | |
return obj[name] -= val; | |
}, | |
'*=': function (obj, name, val) { | |
return obj[name] *= val; | |
}, | |
'/=': function (obj, name, val) { | |
return obj[name] /= val; | |
}, | |
'%=': function (obj, name, val) { | |
return obj[name] %= val; | |
}, | |
'<<=': function (obj, name, val) { | |
return obj[name] <<= val; | |
}, | |
'>>=': function (obj, name, val) { | |
return obj[name] >>= val; | |
}, | |
'>>>=': function (obj, name, val) { | |
return obj[name] >>>= val; | |
}, | |
'|=': function (obj, name, val) { | |
return obj[name] |= val; | |
}, | |
'^=': function (obj, name, val) { | |
return obj[name] ^= val; | |
}, | |
'&=': function (obj, name, val) { | |
return obj[name] &= val; | |
} | |
}[node.operator]; | |
var obj = this._genObj(node.left); | |
var name = this._genName(node.left); | |
var val = this._gen(node.right); | |
return regeneratorRuntime.mark(function _callee27() { | |
var v; | |
return regeneratorRuntime.wrap(function _callee27$(_context28) { | |
while (1) { | |
switch (_context28.prev = _context28.next) { | |
case 0: | |
self.emit('line', node.left.loc.start.line); | |
v = val(); | |
if (!(v !== undefined)) { | |
_context28.next = 6; | |
break; | |
} | |
if (!v.next) { | |
_context28.next = 6; | |
break; | |
} | |
return _context28.delegateYield(v, "t0", 5); | |
case 5: | |
v = _context28.t0; | |
case 6: | |
return _context28.abrupt("return", setter(obj(), name(), v)); | |
case 7: | |
case "end": | |
return _context28.stop(); | |
} | |
} | |
}, _callee27, this); | |
}); | |
}; | |
Environment.prototype._genFuncDecl = function (node) { | |
this._curDeclarations[node.id.name] = this._genFuncExpr(node); | |
return regeneratorRuntime.mark(function _callee28() { | |
return regeneratorRuntime.wrap(function _callee28$(_context29) { | |
while (1) { | |
switch (_context29.prev = _context29.next) { | |
case 0: | |
return _context29.abrupt("return", noop); | |
case 1: | |
case "end": | |
return _context29.stop(); | |
} | |
} | |
}, _callee28, this); | |
}); | |
}; | |
Environment.prototype._genVarDecl = function (node) { | |
var assignments = []; | |
for (var i = 0; i < node.declarations.length; i++) { | |
var decl = node.declarations[i]; | |
this._curDeclarations[decl.id.name] = noop; | |
if (decl.init) { | |
assignments.push({ | |
type: 'AssignmentExpression', | |
operator: '=', | |
left: decl.id, | |
right: decl.init | |
}); | |
} | |
} | |
return this._gen({ | |
type: 'BlockStatement', | |
body: assignments | |
}); | |
}; | |
Environment.prototype.getState = function () { | |
return this.STATE; | |
}; | |
Environment.prototype.setState = function (state) { | |
this.STATE = state; | |
}; | |
Environment.prototype._genFuncExpr = function (node) { | |
var self = this; | |
var oldDeclarations = self._curDeclarations; | |
self._curDeclarations = {}; | |
var body = self._gen(node.body); | |
var declarations = self._curDeclarations; | |
self._curDeclarations = oldDeclarations; | |
// reset var store | |
return function () { | |
var parent = self._curVarStore; | |
return regeneratorRuntime.mark(function _callee29() { | |
var args, | |
i, | |
oldStore, | |
oldThis, | |
result, | |
_args30 = arguments; | |
return regeneratorRuntime.wrap(function _callee29$(_context30) { | |
while (1) { | |
switch (_context30.prev = _context30.next) { | |
case 0: | |
// build arguments object | |
args = new Arguments(); | |
args.length = _args30.length; | |
for (i = 0; i < _args30.length; i++) { | |
args[i] = _args30[i]; | |
} | |
// switch interpreter 'stack' | |
oldStore = self._curVarStore; | |
oldThis = self._curThis; | |
self._curVarStore = createVarStore(parent); | |
self._curThis = this; | |
addDeclarationsToStore(declarations, self._curVarStore); | |
self._curVarStore.vars.arguments = args; | |
// add function args to var store | |
node.params.forEach(function (param, i) { | |
self._curVarStore.vars[param.name] = args[i]; | |
}); | |
// run function body | |
return _context30.delegateYield(body(), "t0", 11); | |
case 11: | |
result = _context30.t0; | |
// switch 'stack' back | |
self._curThis = oldThis; | |
self._curVarStore = oldStore; | |
if (!(result instanceof Return)) { | |
_context30.next = 16; | |
break; | |
} | |
return _context30.abrupt("return", result.value); | |
case 16: | |
case "end": | |
return _context30.stop(); | |
} | |
} | |
}, _callee29, this); | |
}); | |
}; | |
}; | |
function addDeclarationsToStore(declarations, varStore) { | |
for (var key in declarations) { | |
if (declarations.hasOwnProperty(key) && !varStore.vars.hasOwnProperty(key)) { | |
varStore.vars[key] = declarations[key](); | |
} | |
} | |
} | |
Environment.prototype._genProgram = function (node) { | |
var self = this; | |
var stmtClosures = node.body.map(function (stmt) { | |
return self._gen(stmt); | |
}); | |
return regeneratorRuntime.mark(function _callee30() { | |
var result, i; | |
return regeneratorRuntime.wrap(function _callee30$(_context31) { | |
while (1) { | |
switch (_context31.prev = _context31.next) { | |
case 0: | |
i = 0; | |
case 1: | |
if (!(i < stmtClosures.length)) { | |
_context31.next = 17; | |
break; | |
} | |
if (!(stmtClosures[i].constructor.name === 'GeneratorFunction')) { | |
_context31.next = 9; | |
break; | |
} | |
return _context31.delegateYield(stmtClosures[i](), "t0", 4); | |
case 4: | |
result = _context31.t0; | |
_context31.next = 7; | |
return; | |
case 7: | |
_context31.next = 12; | |
break; | |
case 9: | |
result = stmtClosures[i](); | |
_context31.next = 12; | |
return; | |
case 12: | |
if (!(result === Break || result === Continue || result instanceof Return)) { | |
_context31.next = 14; | |
break; | |
} | |
return _context31.abrupt("break", 17); | |
case 14: | |
i++; | |
_context31.next = 1; | |
break; | |
case 17: | |
return _context31.abrupt("return", result); | |
case 18: | |
case "end": | |
return _context31.stop(); | |
} | |
} | |
}, _callee30, this); | |
}); | |
}; | |
Environment.prototype._genExprStmt = function (node) { | |
return this._gen(node.expression); | |
}; | |
Environment.prototype._genEmptyStmt = function () { | |
return noop; | |
}; | |
Environment.prototype._genRetStmt = function (node) { | |
var self = this; | |
var arg = node.argument ? this._gen(node.argument) : noop; | |
return function () { | |
self.emit('line', node.loc.start.line); | |
return new Return(arg()); | |
}; | |
}; | |
Environment.prototype._genIfStmt = function (node) { | |
var self = this; | |
var test = function () { | |
self.emit('line', node.loc.start.line); | |
return self._gen(node.test)(); | |
}; | |
var consequent = this._gen(node.consequent); | |
var alternate = node.alternate ? this._gen(node.alternate) : regeneratorRuntime.mark(function _callee31() { | |
return regeneratorRuntime.wrap(function _callee31$(_context32) { | |
while (1) { | |
switch (_context32.prev = _context32.next) { | |
case 0: | |
return _context32.abrupt("return", noop); | |
case 1: | |
case "end": | |
return _context32.stop(); | |
} | |
} | |
}, _callee31, this); | |
}); | |
return regeneratorRuntime.mark(function _callee32() { | |
var result; | |
return regeneratorRuntime.wrap(function _callee32$(_context33) { | |
while (1) { | |
switch (_context33.prev = _context33.next) { | |
case 0: | |
if (!test()) { | |
_context33.next = 5; | |
break; | |
} | |
return _context33.delegateYield(consequent(), "t1", 2); | |
case 2: | |
_context33.t0 = _context33.t1; | |
_context33.next = 7; | |
break; | |
case 5: | |
return _context33.delegateYield(alternate(), "t2", 6); | |
case 6: | |
_context33.t0 = _context33.t2; | |
case 7: | |
result = _context33.t0; | |
return _context33.abrupt("return", result); | |
case 9: | |
case "end": | |
return _context33.stop(); | |
} | |
} | |
}, _callee32, this); | |
}); | |
}; | |
Environment.prototype._genCondStmt = function (node) { | |
var self = this; | |
var test = function () { | |
self.emit('line', node.loc.start.line); | |
return self._gen(node.test)(); | |
}; | |
var consequent = this._gen(node.consequent); | |
var alternate = node.alternate ? this._gen(node.alternate) : noop; | |
return function () { | |
return test() ? consequent() : alternate(); | |
}; | |
}; | |
Environment.prototype._genLoopStmt = function (node, body) { | |
var self = this; | |
var init = node.init ? this._gen(node.init) : regeneratorRuntime.mark(function _callee33() { | |
return regeneratorRuntime.wrap(function _callee33$(_context34) { | |
while (1) { | |
switch (_context34.prev = _context34.next) { | |
case 0: | |
return _context34.abrupt("return", noop); | |
case 1: | |
case "end": | |
return _context34.stop(); | |
} | |
} | |
}, _callee33, this); | |
}); | |
var test = node.test ? regeneratorRuntime.mark(function _callee34() { | |
return regeneratorRuntime.wrap(function _callee34$(_context35) { | |
while (1) { | |
switch (_context35.prev = _context35.next) { | |
case 0: | |
self.emit('line', node.loc.start.line); | |
return _context35.abrupt("return", self._gen(node.test)()); | |
case 2: | |
case "end": | |
return _context35.stop(); | |
} | |
} | |
}, _callee34, this); | |
}) : regeneratorRuntime.mark(function _callee35() { | |
return regeneratorRuntime.wrap(function _callee35$(_context36) { | |
while (1) { | |
switch (_context36.prev = _context36.next) { | |
case 0: | |
return _context36.abrupt("return", true); | |
case 1: | |
case "end": | |
return _context36.stop(); | |
} | |
} | |
}, _callee35, this); | |
}); | |
var update = node.update ? this._gen(node.update) : regeneratorRuntime.mark(function _callee36() { | |
return regeneratorRuntime.wrap(function _callee36$(_context37) { | |
while (1) { | |
switch (_context37.prev = _context37.next) { | |
case 0: | |
return _context37.abrupt("return", noop); | |
case 1: | |
case "end": | |
return _context37.stop(); | |
} | |
} | |
}, _callee36, this); | |
}); | |
body = body || this._gen(node.body); | |
return regeneratorRuntime.mark(function _callee37() { | |
var resp, newResp; | |
return regeneratorRuntime.wrap(function _callee37$(_context38) { | |
while (1) { | |
switch (_context38.prev = _context38.next) { | |
case 0: | |
self.emit('line', node.loc.start.line); | |
return _context38.delegateYield(init(), "t0", 2); | |
case 2: | |
return _context38.delegateYield(test(), "t1", 3); | |
case 3: | |
if (!_context38.t1) { | |
_context38.next = 16; | |
break; | |
} | |
return _context38.delegateYield(body(), "t2", 5); | |
case 5: | |
newResp = _context38.t2; | |
if (!(newResp === Break)) { | |
_context38.next = 8; | |
break; | |
} | |
return _context38.abrupt("break", 16); | |
case 8: | |
if (!(newResp === Continue)) { | |
_context38.next = 10; | |
break; | |
} | |
return _context38.abrupt("continue", 13); | |
case 10: | |
resp = newResp; | |
if (!(newResp instanceof Return)) { | |
_context38.next = 13; | |
break; | |
} | |
return _context38.abrupt("break", 16); | |
case 13: | |
return _context38.delegateYield(update(), "t3", 14); | |
case 14: | |
_context38.next = 2; | |
break; | |
case 16: | |
return _context38.abrupt("return", resp); | |
case 17: | |
case "end": | |
return _context38.stop(); | |
} | |
} | |
}, _callee37, this); | |
}); | |
}; | |
Environment.prototype._genDoWhileStmt = function (node) { | |
var body = this._gen(node.body); | |
var loop = this._genLoopStmt(node, body); | |
return regeneratorRuntime.mark(function _callee38() { | |
return regeneratorRuntime.wrap(function _callee38$(_context39) { | |
while (1) { | |
switch (_context39.prev = _context39.next) { | |
case 0: | |
return _context39.delegateYield(body(), "t0", 1); | |
case 1: | |
return _context39.delegateYield(loop(), "t1", 2); | |
case 2: | |
case "end": | |
return _context39.stop(); | |
} | |
} | |
}, _callee38, this); | |
}); | |
}; | |
Environment.prototype._genForInStmt = function (node) { | |
var self = this; | |
var right = self._gen(node.right); | |
var body = self._gen(node.body); | |
var left = node.left; | |
if (left.type === 'VariableDeclaration') { | |
self._curDeclarations[left.declarations[0].id.name] = noop; | |
left = left.declarations[0].id; | |
} | |
return regeneratorRuntime.mark(function _callee39() { | |
var resp, x; | |
return regeneratorRuntime.wrap(function _callee39$(_context40) { | |
while (1) { | |
switch (_context40.prev = _context40.next) { | |
case 0: | |
self.emit('line', node.loc.start.line); | |
_context40.t0 = regeneratorRuntime.keys(right()); | |
case 2: | |
if ((_context40.t1 = _context40.t0()).done) { | |
_context40.next = 10; | |
break; | |
} | |
x = _context40.t1.value; | |
self.emit('line', node.loc.start.line); | |
return _context40.delegateYield(self._genAssignExpr({ | |
operator: '=', | |
left: left, | |
right: { | |
type: 'Literal', | |
value: x | |
} | |
})(), "t2", 6); | |
case 6: | |
return _context40.delegateYield(body(), "t3", 7); | |
case 7: | |
resp = _context40.t3; | |
_context40.next = 2; | |
break; | |
case 10: | |
return _context40.abrupt("return", resp); | |
case 11: | |
case "end": | |
return _context40.stop(); | |
} | |
} | |
}, _callee39, this); | |
}); | |
}; | |
Environment.prototype._genWithStmt = function (node) { | |
var self = this; | |
var obj = self._gen(node.object); | |
var body = self._gen(node.body); | |
return regeneratorRuntime.mark(function _callee40() { | |
var result; | |
return regeneratorRuntime.wrap(function _callee40$(_context41) { | |
while (1) { | |
switch (_context41.prev = _context41.next) { | |
case 0: | |
self._curVarStore = createVarStore(self._curVarStore, obj()); | |
return _context41.delegateYield(body(), "t0", 2); | |
case 2: | |
result = _context41.t0; | |
self._curVarStore = self._curVarStore.parent; | |
return _context41.abrupt("return", result); | |
case 5: | |
case "end": | |
return _context41.stop(); | |
} | |
} | |
}, _callee40, this); | |
}); | |
}; | |
Environment.prototype._genThrowStmt = function (node) { | |
var arg = this._gen(node.argument); | |
return function () { | |
throw arg(); | |
}; | |
}; | |
Environment.prototype._genTryStmt = function (node) { | |
var block = this._gen(node.block); | |
var handler = this._genCatchHandler(node.handler); | |
var finalizer = node.finalizer ? this._gen(node.finalizer) : function (x) { | |
return x; | |
}; | |
return function () { | |
try { | |
return finalizer(block()); | |
} catch (err) { | |
return finalizer(handler(err)); | |
} | |
}; | |
}; | |
Environment.prototype._genCatchHandler = function (node) { | |
if (!node) { | |
return noop; | |
} | |
var self = this; | |
var body = self._gen(node.body); | |
return function (err) { | |
var old = self._curVarStore.vars[node.param.name]; | |
self._curVarStore.vars[node.param.name] = err; | |
var resp = body(); | |
self._curVarStore.vars[node.param.name] = old; | |
return resp; | |
}; | |
}; | |
Environment.prototype._genContStmt = function () { | |
return function () { | |
return Continue; | |
}; | |
}; | |
Environment.prototype._genBreakStmt = function () { | |
return function () { | |
return Break; | |
}; | |
}; | |
Environment.prototype._genSwitchStmt = function (node) { | |
var self = this; | |
var discriminant = self._gen(node.discriminant); | |
var cases = node.cases.map(function (curCase) { | |
return { | |
test: curCase.test ? self._gen(curCase.test) : null, | |
code: self._genProgram({ body: curCase.consequent }) | |
}; | |
}); | |
return regeneratorRuntime.mark(function _callee41() { | |
var foundMatch, discriminantVal, resp, defaultCase, i, curCase, newResp; | |
return regeneratorRuntime.wrap(function _callee41$(_context42) { | |
while (1) { | |
switch (_context42.prev = _context42.next) { | |
case 0: | |
foundMatch = false; | |
discriminantVal = discriminant(); | |
i = 0; | |
case 3: | |
if (!(i < cases.length)) { | |
_context42.next = 22; | |
break; | |
} | |
curCase = cases[i]; | |
if (foundMatch) { | |
_context42.next = 12; | |
break; | |
} | |
if (curCase.test) { | |
_context42.next = 9; | |
break; | |
} | |
defaultCase = curCase; | |
return _context42.abrupt("continue", 19); | |
case 9: | |
if (!(discriminantVal !== curCase.test())) { | |
_context42.next = 11; | |
break; | |
} | |
return _context42.abrupt("continue", 19); | |
case 11: | |
foundMatch = true; | |
case 12: | |
return _context42.delegateYield(curCase.code(), "t0", 13); | |
case 13: | |
newResp = _context42.t0; | |
if (!(newResp === Break)) { | |
_context42.next = 16; | |
break; | |
} | |
return _context42.abrupt("return", resp); | |
case 16: | |
resp = newResp; | |
if (!(resp === Continue || resp instanceof Return)) { | |
_context42.next = 19; | |
break; | |
} | |
return _context42.abrupt("return", resp); | |
case 19: | |
i++; | |
_context42.next = 3; | |
break; | |
case 22: | |
if (!(!foundMatch && defaultCase)) { | |
_context42.next = 25; | |
break; | |
} | |
return _context42.delegateYield(defaultCase.code(), "t1", 24); | |
case 24: | |
return _context42.abrupt("return", _context42.t1); | |
case 25: | |
case "end": | |
return _context42.stop(); | |
} | |
} | |
}, _callee41, this); | |
}); | |
}; | |
exports.Environment = Environment; | |
exports.evaluate = function (code) { | |
var env = new Environment(global); | |
var iterator = env.gen(code)(); | |
var result = iterator.next(); | |
while (!result.done) { | |
result = iterator.next(); | |
} | |
return result.value; | |
}; | |
//console.log(exports.evaluate("1 + 1")); | |
}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) | |
},{"_process":2,"acorn":"acorn","events":1,"util":5}]},{},[]); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<script src="eval.js"></script> | |
</head> | |
<body> | |
<script> | |
var evaljs = require('evaljs'); | |
var env = new evaljs.Environment([{console: console}]); | |
var script = "console.log(5);" + | |
"console.log(4);" + | |
"console.log(3);" + | |
"console.log(2);" + | |
"console.log(1);" + | |
"console.log('Done!');" | |
var iterator = env.gen(script)(); | |
play = function(iter, delay) { | |
var playChunk = function(delay){ | |
var result = iter.next() | |
if (result.done) { | |
return | |
} else { | |
setTimeout(playChunk, delay, delay) | |
} | |
} | |
playChunk(delay) | |
} | |
play(iterator, 500) | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment