aboutsummaryrefslogtreecommitdiff
path: root/contexts/data/lib/ace/worker-javascript.js
diff options
context:
space:
mode:
Diffstat (limited to 'contexts/data/lib/ace/worker-javascript.js')
-rw-r--r--contexts/data/lib/ace/worker-javascript.js12615
1 files changed, 4635 insertions, 7980 deletions
diff --git a/contexts/data/lib/ace/worker-javascript.js b/contexts/data/lib/ace/worker-javascript.js
index e48c6e8..8fa92b6 100644
--- a/contexts/data/lib/ace/worker-javascript.js
+++ b/contexts/data/lib/ace/worker-javascript.js
@@ -1,8 +1,16 @@
"no use strict";
+if (typeof window != "undefined" && window.document)
+ throw "atempt to load ace worker into main window instead of webWorker";
+
var console = {
- log: function(msg) {
- postMessage({type: "log", data: msg});
+ log: function() {
+ var msgs = Array.prototype.slice.call(arguments, 0);
+ postMessage({type: "log", data: msgs});
+ },
+ error: function() {
+ var msgs = Array.prototype.slice.call(arguments, 0);
+ postMessage({type: "log", data: msgs});
}
};
var window = {
@@ -18,11 +26,11 @@ var normalizeModule = function(parentId, moduleName) {
// normalize relative requires
if (moduleName.charAt(0) == ".") {
var base = parentId.split("/").slice(0, -1).join("/");
- var moduleName = base + "/" + moduleName;
+ moduleName = base + "/" + moduleName;
while(moduleName.indexOf(".") !== -1 && previous != moduleName) {
var previous = moduleName;
- var moduleName = moduleName.replace(/\/\.\//, "/").replace(/[^\/]+\/\.\.\//, "");
+ moduleName = moduleName.replace(/\/\.\//, "/").replace(/[^\/]+\/\.\.\//, "");
}
}
@@ -30,13 +38,16 @@ var normalizeModule = function(parentId, moduleName) {
};
var require = function(parentId, id) {
- var id = normalizeModule(parentId, id);
-
+ if (!id.charAt)
+ throw new Error("worker.js require() accepts only (parentId, id) as arguments");
+
+ id = normalizeModule(parentId, id);
+
var module = require.modules[id];
if (module) {
if (!module.initialized) {
- module.exports = module.factory().exports;
module.initialized = true;
+ module.exports = module.factory().exports;
}
return module.exports;
}
@@ -56,6 +67,10 @@ require.tlns = {};
var define = function(id, deps, factory) {
if (arguments.length == 2) {
factory = deps;
+ if (typeof id != "string") {
+ deps = id;
+ id = require.id;
+ }
} else if (arguments.length == 1) {
factory = id;
id = require.id;
@@ -123,7 +138,10 @@ var sender;
onmessage = function(e) {
var msg = e.data;
if (msg.command) {
- main[msg.command].apply(main, msg.args);
+ if (main[msg.command])
+ main[msg.command].apply(main, msg.args);
+ else
+ throw new Error("Unknown command:" + msg.command);
}
else if (msg.init) {
initBaseUrls(msg.tlns);
@@ -137,40 +155,16 @@ onmessage = function(e) {
}
};
// vim:set ts=4 sts=4 sw=4 st:
-// -- kriskowal Kris Kowal Copyright (C) 2009-2010 MIT License
-// -- tlrobinson Tom Robinson Copyright (C) 2009-2010 MIT License (Narwhal Project)
-// -- dantman Daniel Friesen Copyright(C) 2010 XXX No License Specified
-// -- fschaefer Florian Schäfer Copyright (C) 2010 MIT License
-// -- Irakli Gozalishvili Copyright (C) 2010 MIT License
-
-/*!
- Copyright (c) 2009, 280 North Inc. http://280north.com/
- MIT License. http://github.com/280north/narwhal/blob/master/README.md
-*/
define('ace/lib/fixoldbrowsers', ['require', 'exports', 'module' , 'ace/lib/regexp', 'ace/lib/es5-shim'], function(require, exports, module) {
-"use strict";
+
require("./regexp");
require("./es5-shim");
-});/**
- * Based on code from:
- *
- * XRegExp 1.5.0
- * (c) 2007-2010 Steven Levithan
- * MIT License
- * <http://xregexp.com>
- * Provides an augmented, extensible, cross-browser implementation of regular expressions,
- * including support for additional syntax, flags, and methods
- */
+});
define('ace/lib/regexp', ['require', 'exports', 'module' ], function(require, exports, module) {
-"use strict";
-
- //---------------------------------
- // Private variables
- //---------------------------------
var real = {
exec: RegExp.prototype.exec,
@@ -186,25 +180,14 @@ define('ace/lib/regexp', ['require', 'exports', 'module' ], function(require, ex
return !x.lastIndex;
}();
- //---------------------------------
- // Overriden native methods
- //---------------------------------
-
- // Adds named capture support (with backreferences returned as `result.name`), and fixes two
- // cross-browser issues per ES3:
- // - Captured values for nonparticipating capturing groups should be returned as `undefined`,
- // rather than the empty string.
- // - `lastIndex` should not be incremented after zero-length matches.
+ if (compliantLastIndexIncrement && compliantExecNpcg)
+ return;
RegExp.prototype.exec = function (str) {
var match = real.exec.apply(this, arguments),
name, r2;
- if (match) {
- // Fix browsers whose `exec` methods don't consistently return `undefined` for
- // nonparticipating capturing groups
+ if ( typeof(str) == 'string' && match) {
if (!compliantExecNpcg && match.length > 1 && indexOf(match, "") > -1) {
r2 = RegExp(this.source, real.replace.call(getNativeFlags(this), "g", ""));
- // Using `str.slice(match.index)` rather than `match[0]` in case lookahead allowed
- // matching due to characters outside the match
real.replace.call(str.slice(match.index), r2, function () {
for (var i = 1; i < arguments.length - 2; i++) {
if (arguments[i] === undefined)
@@ -212,7 +195,6 @@ define('ace/lib/regexp', ['require', 'exports', 'module' ], function(require, ex
}
});
}
- // Attach named capture properties
if (this._xregexp && this._xregexp.captureNames) {
for (var i = 1; i < match.length; i++) {
name = this._xregexp.captureNames[i - 1];
@@ -220,38 +202,27 @@ define('ace/lib/regexp', ['require', 'exports', 'module' ], function(require, ex
match[name] = match[i];
}
}
- // Fix browsers that increment `lastIndex` after zero-length matches
if (!compliantLastIndexIncrement && this.global && !match[0].length && (this.lastIndex > match.index))
this.lastIndex--;
}
return match;
};
-
- // Don't override `test` if it won't change anything
if (!compliantLastIndexIncrement) {
- // Fix browser bug in native method
RegExp.prototype.test = function (str) {
- // Use the native `exec` to skip some processing overhead, even though the overriden
- // `exec` would take care of the `lastIndex` fix
var match = real.exec.call(this, str);
- // Fix browsers that increment `lastIndex` after zero-length matches
if (match && this.global && !match[0].length && (this.lastIndex > match.index))
this.lastIndex--;
return !!match;
};
}
- //---------------------------------
- // Private helper functions
- //---------------------------------
-
function getNativeFlags (regex) {
return (regex.global ? "g" : "") +
(regex.ignoreCase ? "i" : "") +
(regex.multiline ? "m" : "") +
(regex.extended ? "x" : "") + // Proposed for ES4; included in AS3
(regex.sticky ? "y" : "");
- };
+ }
function indexOf (array, item, from) {
if (Array.prototype.indexOf) // Use the native array method if available
@@ -261,94 +232,21 @@ define('ace/lib/regexp', ['require', 'exports', 'module' ], function(require, ex
return i;
}
return -1;
- };
+ }
-});// vim: ts=4 sts=4 sw=4 expandtab
-// -- kriskowal Kris Kowal Copyright (C) 2009-2011 MIT License
-// -- tlrobinson Tom Robinson Copyright (C) 2009-2010 MIT License (Narwhal Project)
-// -- dantman Daniel Friesen Copyright (C) 2010 XXX TODO License or CLA
-// -- fschaefer Florian Schäfer Copyright (C) 2010 MIT License
-// -- Gozala Irakli Gozalishvili Copyright (C) 2010 MIT License
-// -- kitcambridge Kit Cambridge Copyright (C) 2011 MIT License
-// -- kossnocorp Sasha Koss XXX TODO License or CLA
-// -- bryanforbes Bryan Forbes XXX TODO License or CLA
-// -- killdream Quildreen Motta Copyright (C) 2011 MIT Licence
-// -- michaelficarra Michael Ficarra Copyright (C) 2011 3-clause BSD License
-// -- sharkbrainguy Gerard Paapu Copyright (C) 2011 MIT License
-// -- bbqsrc Brendan Molloy (C) 2011 Creative Commons Zero (public domain)
-// -- iwyg XXX TODO License or CLA
-// -- DomenicDenicola Domenic Denicola Copyright (C) 2011 MIT License
-// -- xavierm02 Montillet Xavier XXX TODO License or CLA
-// -- Raynos Raynos XXX TODO License or CLA
-// -- samsonjs Sami Samhuri Copyright (C) 2010 MIT License
-// -- rwldrn Rick Waldron Copyright (C) 2011 MIT License
-// -- lexer Alexey Zakharov XXX TODO License or CLA
-
-/*!
- Copyright (c) 2009, 280 North Inc. http://280north.com/
- MIT License. http://github.com/280north/narwhal/blob/master/README.md
-*/
+});
define('ace/lib/es5-shim', ['require', 'exports', 'module' ], function(require, exports, module) {
-/**
- * Brings an environment as close to ECMAScript 5 compliance
- * as is possible with the facilities of erstwhile engines.
- *
- * Annotated ES5: http://es5.github.com/ (specific links below)
- * ES5 Spec: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
- *
- * @module
- */
-
-/*whatsupdoc*/
-
-//
-// Function
-// ========
-//
-
-// ES-5 15.3.4.5
-// http://es5.github.com/#x15.3.4.5
-
if (!Function.prototype.bind) {
Function.prototype.bind = function bind(that) { // .length is 1
- // 1. Let Target be the this value.
var target = this;
- // 2. If IsCallable(Target) is false, throw a TypeError exception.
if (typeof target != "function")
throw new TypeError(); // TODO message
- // 3. Let A be a new (possibly empty) internal list of all of the
- // argument values provided after thisArg (arg1, arg2 etc), in order.
- // XXX slicedArgs will stand in for "A" if used
var args = slice.call(arguments, 1); // for normal call
- // 4. Let F be a new native ECMAScript object.
- // 11. Set the [[Prototype]] internal property of F to the standard
- // built-in Function prototype object as specified in 15.3.3.1.
- // 12. Set the [[Call]] internal property of F as described in
- // 15.3.4.5.1.
- // 13. Set the [[Construct]] internal property of F as described in
- // 15.3.4.5.2.
- // 14. Set the [[HasInstance]] internal property of F as described in
- // 15.3.4.5.3.
var bound = function () {
if (this instanceof bound) {
- // 15.3.4.5.2 [[Construct]]
- // When the [[Construct]] internal method of a function object,
- // F that was created using the bind function is called with a
- // list of arguments ExtraArgs, the following steps are taken:
- // 1. Let target be the value of F's [[TargetFunction]]
- // internal property.
- // 2. If target has no [[Construct]] internal method, a
- // TypeError exception is thrown.
- // 3. Let boundArgs be the value of F's [[BoundArgs]] internal
- // property.
- // 4. Let args be a new list containing the same values as the
- // list boundArgs in the same order followed by the same
- // values as the list ExtraArgs in the same order.
- // 5. Return the result of calling the [[Construct]] internal
- // method of target providing args as the arguments.
var F = function(){};
F.prototype = target.prototype;
@@ -363,25 +261,6 @@ if (!Function.prototype.bind) {
return self;
} else {
- // 15.3.4.5.1 [[Call]]
- // When the [[Call]] internal method of a function object, F,
- // which was created using the bind function is called with a
- // this value and a list of arguments ExtraArgs, the following
- // steps are taken:
- // 1. Let boundArgs be the value of F's [[BoundArgs]] internal
- // property.
- // 2. Let boundThis be the value of F's [[BoundThis]] internal
- // property.
- // 3. Let target be the value of F's [[TargetFunction]] internal
- // property.
- // 4. Let args be a new list containing the same values as the
- // list boundArgs in the same order followed by the same
- // values as the list ExtraArgs in the same order.
- // 5. Return the result of calling the [[Call]] internal method
- // of target providing boundThis as the this value and
- // providing args as the arguments.
-
- // equiv: target.call(this, ...boundArgs, ...args)
return target.apply(
that,
args.concat(slice.call(arguments))
@@ -390,53 +269,15 @@ if (!Function.prototype.bind) {
}
};
- // XXX bound.length is never writable, so don't even try
- //
- // 15. If the [[Class]] internal property of Target is "Function", then
- // a. Let L be the length property of Target minus the length of A.
- // b. Set the length own property of F to either 0 or L, whichever is
- // larger.
- // 16. Else set the length own property of F to 0.
- // 17. Set the attributes of the length own property of F to the values
- // specified in 15.3.5.1.
-
- // TODO
- // 18. Set the [[Extensible]] internal property of F to true.
-
- // TODO
- // 19. Let thrower be the [[ThrowTypeError]] function Object (13.2.3).
- // 20. Call the [[DefineOwnProperty]] internal method of F with
- // arguments "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]:
- // thrower, [[Enumerable]]: false, [[Configurable]]: false}, and
- // false.
- // 21. Call the [[DefineOwnProperty]] internal method of F with
- // arguments "arguments", PropertyDescriptor {[[Get]]: thrower,
- // [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false},
- // and false.
-
- // TODO
- // NOTE Function objects created using Function.prototype.bind do not
- // have a prototype property or the [[Code]], [[FormalParameters]], and
- // [[Scope]] internal properties.
- // XXX can't delete prototype in pure-js.
-
- // 22. Return F.
return bound;
};
}
-
-// Shortcut to an often accessed properties, in order to avoid multiple
-// dereference that costs universally.
-// _Please note: Shortcuts are defined after `Function.prototype.bind` as we
-// us it in defining shortcuts.
var call = Function.prototype.call;
var prototypeOfArray = Array.prototype;
var prototypeOfObject = Object.prototype;
var slice = prototypeOfArray.slice;
var toString = call.bind(prototypeOfObject.toString);
var owns = call.bind(prototypeOfObject.hasOwnProperty);
-
-// If JS engine supports accessors creating shortcuts.
var defineGetter;
var defineSetter;
var lookupGetter;
@@ -448,70 +289,35 @@ if ((supportsAccessors = owns(prototypeOfObject, "__defineGetter__"))) {
lookupGetter = call.bind(prototypeOfObject.__lookupGetter__);
lookupSetter = call.bind(prototypeOfObject.__lookupSetter__);
}
-
-//
-// Array
-// =====
-//
-
-// ES5 15.4.3.2
-// http://es5.github.com/#x15.4.3.2
-// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/isArray
if (!Array.isArray) {
Array.isArray = function isArray(obj) {
return toString(obj) == "[object Array]";
};
}
-
-// The IsCallable() check in the Array functions
-// has been replaced with a strict check on the
-// internal class of the object to trap cases where
-// the provided function was actually a regular
-// expression literal, which in V8 and
-// JavaScriptCore is a typeof "function". Only in
-// V8 are regular expression literals permitted as
-// reduce parameters, so it is desirable in the
-// general case for the shim to match the more
-// strict and common behavior of rejecting regular
-// expressions.
-
-// ES5 15.4.4.18
-// http://es5.github.com/#x15.4.4.18
-// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/forEach
if (!Array.prototype.forEach) {
Array.prototype.forEach = function forEach(fun /*, thisp*/) {
var self = toObject(this),
thisp = arguments[1],
i = 0,
length = self.length >>> 0;
-
- // If no callback function or if callback is not a callable function
if (toString(fun) != "[object Function]") {
throw new TypeError(); // TODO message
}
while (i < length) {
if (i in self) {
- // Invoke the callback function with call, passing arguments:
- // context, property value, property key, thisArg object context
fun.call(thisp, self[i], i, self);
}
i++;
}
};
}
-
-// ES5 15.4.4.19
-// http://es5.github.com/#x15.4.4.19
-// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map
if (!Array.prototype.map) {
Array.prototype.map = function map(fun /*, thisp*/) {
var self = toObject(this),
length = self.length >>> 0,
result = Array(length),
thisp = arguments[1];
-
- // If no callback function or if callback is not a callable function
if (toString(fun) != "[object Function]") {
throw new TypeError(); // TODO message
}
@@ -523,18 +329,12 @@ if (!Array.prototype.map) {
return result;
};
}
-
-// ES5 15.4.4.20
-// http://es5.github.com/#x15.4.4.20
-// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/filter
if (!Array.prototype.filter) {
Array.prototype.filter = function filter(fun /*, thisp */) {
var self = toObject(this),
length = self.length >>> 0,
result = [],
thisp = arguments[1];
-
- // If no callback function or if callback is not a callable function
if (toString(fun) != "[object Function]") {
throw new TypeError(); // TODO message
}
@@ -546,17 +346,11 @@ if (!Array.prototype.filter) {
return result;
};
}
-
-// ES5 15.4.4.16
-// http://es5.github.com/#x15.4.4.16
-// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/every
if (!Array.prototype.every) {
Array.prototype.every = function every(fun /*, thisp */) {
var self = toObject(this),
length = self.length >>> 0,
thisp = arguments[1];
-
- // If no callback function or if callback is not a callable function
if (toString(fun) != "[object Function]") {
throw new TypeError(); // TODO message
}
@@ -568,17 +362,11 @@ if (!Array.prototype.every) {
return true;
};
}
-
-// ES5 15.4.4.17
-// http://es5.github.com/#x15.4.4.17
-// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some
if (!Array.prototype.some) {
Array.prototype.some = function some(fun /*, thisp */) {
var self = toObject(this),
length = self.length >>> 0,
thisp = arguments[1];
-
- // If no callback function or if callback is not a callable function
if (toString(fun) != "[object Function]") {
throw new TypeError(); // TODO message
}
@@ -590,21 +378,13 @@ if (!Array.prototype.some) {
return false;
};
}
-
-// ES5 15.4.4.21
-// http://es5.github.com/#x15.4.4.21
-// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduce
if (!Array.prototype.reduce) {
Array.prototype.reduce = function reduce(fun /*, initial*/) {
var self = toObject(this),
length = self.length >>> 0;
-
- // If no callback function or if callback is not a callable function
if (toString(fun) != "[object Function]") {
throw new TypeError(); // TODO message
}
-
- // no value to return if no initial value and an empty array
if (!length && arguments.length == 1)
throw new TypeError(); // TODO message
@@ -618,8 +398,6 @@ if (!Array.prototype.reduce) {
result = self[i++];
break;
}
-
- // if array contains no values, no initial value to return
if (++i >= length)
throw new TypeError(); // TODO message
} while (true);
@@ -633,21 +411,13 @@ if (!Array.prototype.reduce) {
return result;
};
}
-
-// ES5 15.4.4.22
-// http://es5.github.com/#x15.4.4.22
-// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduceRight
if (!Array.prototype.reduceRight) {
Array.prototype.reduceRight = function reduceRight(fun /*, initial*/) {
var self = toObject(this),
length = self.length >>> 0;
-
- // If no callback function or if callback is not a callable function
if (toString(fun) != "[object Function]") {
throw new TypeError(); // TODO message
}
-
- // no value to return if no initial value, empty array
if (!length && arguments.length == 1)
throw new TypeError(); // TODO message
@@ -660,8 +430,6 @@ if (!Array.prototype.reduceRight) {
result = self[i--];
break;
}
-
- // if array contains no values, no initial value to return
if (--i < 0)
throw new TypeError(); // TODO message
} while (true);
@@ -675,10 +443,6 @@ if (!Array.prototype.reduceRight) {
return result;
};
}
-
-// ES5 15.4.4.14
-// http://es5.github.com/#x15.4.4.14
-// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function indexOf(sought /*, fromIndex */ ) {
var self = toObject(this),
@@ -690,8 +454,6 @@ if (!Array.prototype.indexOf) {
var i = 0;
if (arguments.length > 1)
i = toInteger(arguments[1]);
-
- // handle negative indices
i = i >= 0 ? i : Math.max(0, length + i);
for (; i < length; i++) {
if (i in self && self[i] === sought) {
@@ -701,10 +463,6 @@ if (!Array.prototype.indexOf) {
return -1;
};
}
-
-// ES5 15.4.4.15
-// http://es5.github.com/#x15.4.4.15
-// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/lastIndexOf
if (!Array.prototype.lastIndexOf) {
Array.prototype.lastIndexOf = function lastIndexOf(sought /*, fromIndex */) {
var self = toObject(this),
@@ -715,7 +473,6 @@ if (!Array.prototype.lastIndexOf) {
var i = length - 1;
if (arguments.length > 1)
i = Math.min(i, toInteger(arguments[1]));
- // handle negative indices
i = i >= 0 ? i : length - Math.abs(i);
for (; i >= 0; i--) {
if (i in self && sought === self[i])
@@ -724,18 +481,7 @@ if (!Array.prototype.lastIndexOf) {
return -1;
};
}
-
-//
-// Object
-// ======
-//
-
-// ES5 15.2.3.2
-// http://es5.github.com/#x15.2.3.2
if (!Object.getPrototypeOf) {
- // https://github.com/kriskowal/es5-shim/issues#issue/2
- // http://ejohn.org/blog/objectgetprototypeof/
- // recommended by fschaefer on github
Object.getPrototypeOf = function getPrototypeOf(object) {
return object.__proto__ || (
object.constructor ?
@@ -744,84 +490,73 @@ if (!Object.getPrototypeOf) {
);
};
}
-
-// ES5 15.2.3.3
-// http://es5.github.com/#x15.2.3.3
if (!Object.getOwnPropertyDescriptor) {
var ERR_NON_OBJECT = "Object.getOwnPropertyDescriptor called on a " +
"non-object: ";
Object.getOwnPropertyDescriptor = function getOwnPropertyDescriptor(object, property) {
if ((typeof object != "object" && typeof object != "function") || object === null)
throw new TypeError(ERR_NON_OBJECT + object);
- // If object does not owns property return undefined immediately.
if (!owns(object, property))
return;
var descriptor, getter, setter;
-
- // If object has a property then it's for sure both `enumerable` and
- // `configurable`.
descriptor = { enumerable: true, configurable: true };
-
- // If JS engine supports accessor properties then property may be a
- // getter or setter.
if (supportsAccessors) {
- // Unfortunately `__lookupGetter__` will return a getter even
- // if object has own non getter property along with a same named
- // inherited getter. To avoid misbehavior we temporary remove
- // `__proto__` so that `__lookupGetter__` will return getter only
- // if it's owned by an object.
var prototype = object.__proto__;
object.__proto__ = prototypeOfObject;
var getter = lookupGetter(object, property);
var setter = lookupSetter(object, property);
-
- // Once we have getter and setter we can put values back.
object.__proto__ = prototype;
if (getter || setter) {
if (getter) descriptor.get = getter;
if (setter) descriptor.set = setter;
-
- // If it was accessor property we're done and return here
- // in order to avoid adding `value` to the descriptor.
return descriptor;
}
}
-
- // If we got this far we know that object has an own property that is
- // not an accessor so we set it as a value and return descriptor.
descriptor.value = object[property];
return descriptor;
};
}
-
-// ES5 15.2.3.4
-// http://es5.github.com/#x15.2.3.4
if (!Object.getOwnPropertyNames) {
Object.getOwnPropertyNames = function getOwnPropertyNames(object) {
return Object.keys(object);
};
}
-
-// ES5 15.2.3.5
-// http://es5.github.com/#x15.2.3.5
if (!Object.create) {
+ var createEmpty;
+ if (Object.prototype.__proto__ === null) {
+ createEmpty = function () {
+ return { "__proto__": null };
+ };
+ } else {
+ createEmpty = function () {
+ var empty = {};
+ for (var i in empty)
+ empty[i] = null;
+ empty.constructor =
+ empty.hasOwnProperty =
+ empty.propertyIsEnumerable =
+ empty.isPrototypeOf =
+ empty.toLocaleString =
+ empty.toString =
+ empty.valueOf =
+ empty.__proto__ = null;
+ return empty;
+ }
+ }
+
Object.create = function create(prototype, properties) {
var object;
if (prototype === null) {
- object = { "__proto__": null };
+ object = createEmpty();
} else {
if (typeof prototype != "object")
throw new TypeError("typeof prototype["+(typeof prototype)+"] != 'object'");
var Type = function () {};
Type.prototype = prototype;
object = new Type();
- // IE has no built-in implementation of `Object.getPrototypeOf`
- // neither `__proto__`, but this manually setting `__proto__` will
- // guarantee that `Object.getPrototypeOf` will work as expected with
- // objects created using `Object.create`
object.__proto__ = prototype;
}
if (properties !== void 0)
@@ -830,29 +565,13 @@ if (!Object.create) {
};
}
-// ES5 15.2.3.6
-// http://es5.github.com/#x15.2.3.6
-
-// Patch for WebKit and IE8 standard mode
-// Designed by hax <hax.github.com>
-// related issue: https://github.com/kriskowal/es5-shim/issues#issue/5
-// IE8 Reference:
-// http://msdn.microsoft.com/en-us/library/dd282900.aspx
-// http://msdn.microsoft.com/en-us/library/dd229916.aspx
-// WebKit Bugs:
-// https://bugs.webkit.org/show_bug.cgi?id=36423
-
function doesDefinePropertyWork(object) {
try {
Object.defineProperty(object, "sentinel", {});
return "sentinel" in object;
} catch (exception) {
- // returns falsy
}
}
-
-// check whether defineProperty works if it's given. Otherwise,
-// shim partially.
if (Object.defineProperty) {
var definePropertyWorksOnObject = doesDefinePropertyWork({});
var definePropertyWorksOnDom = typeof document == "undefined" ||
@@ -873,48 +592,21 @@ if (!Object.defineProperty || definePropertyFallback) {
throw new TypeError(ERR_NON_OBJECT_TARGET + object);
if ((typeof descriptor != "object" && typeof descriptor != "function") || descriptor === null)
throw new TypeError(ERR_NON_OBJECT_DESCRIPTOR + descriptor);
-
- // make a valiant attempt to use the real defineProperty
- // for I8's DOM elements.
if (definePropertyFallback) {
try {
return definePropertyFallback.call(Object, object, property, descriptor);
} catch (exception) {
- // try the shim if the real one doesn't work
}
}
-
- // If it's a data property.
if (owns(descriptor, "value")) {
- // fail silently if "writable", "enumerable", or "configurable"
- // are requested but not supported
- /*
- // alternate approach:
- if ( // can't implement these features; allow false but not true
- !(owns(descriptor, "writable") ? descriptor.writable : true) ||
- !(owns(descriptor, "enumerable") ? descriptor.enumerable : true) ||
- !(owns(descriptor, "configurable") ? descriptor.configurable : true)
- )
- throw new RangeError(
- "This implementation of Object.defineProperty does not " +
- "support configurable, enumerable, or writable."
- );
- */
if (supportsAccessors && (lookupGetter(object, property) ||
lookupSetter(object, property)))
{
- // As accessors are supported only on engines implementing
- // `__proto__` we can safely override `__proto__` while defining
- // a property to make sure that we don't hit an inherited
- // accessor.
var prototype = object.__proto__;
object.__proto__ = prototypeOfObject;
- // Deleting a property anyway since getter / setter may be
- // defined on object itself.
delete object[property];
object[property] = descriptor.value;
- // Setting original `__proto__` back now.
object.__proto__ = prototype;
} else {
object[property] = descriptor.value;
@@ -922,7 +614,6 @@ if (!Object.defineProperty || definePropertyFallback) {
} else {
if (!supportsAccessors)
throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED);
- // If we got that far then getters and setters can be defined !!
if (owns(descriptor, "get"))
defineGetter(object, property, descriptor.get);
if (owns(descriptor, "set"))
@@ -932,9 +623,6 @@ if (!Object.defineProperty || definePropertyFallback) {
return object;
};
}
-
-// ES5 15.2.3.7
-// http://es5.github.com/#x15.2.3.7
if (!Object.defineProperties) {
Object.defineProperties = function defineProperties(object, properties) {
for (var property in properties) {
@@ -944,30 +632,16 @@ if (!Object.defineProperties) {
return object;
};
}
-
-// ES5 15.2.3.8
-// http://es5.github.com/#x15.2.3.8
if (!Object.seal) {
Object.seal = function seal(object) {
- // this is misleading and breaks feature-detection, but
- // allows "securable" code to "gracefully" degrade to working
- // but insecure code.
return object;
};
}
-
-// ES5 15.2.3.9
-// http://es5.github.com/#x15.2.3.9
if (!Object.freeze) {
Object.freeze = function freeze(object) {
- // this is misleading and breaks feature-detection, but
- // allows "securable" code to "gracefully" degrade to working
- // but insecure code.
return object;
};
}
-
-// detect a Rhino bug and patch it
try {
Object.freeze(function () {});
} catch (exception) {
@@ -981,43 +655,26 @@ try {
};
})(Object.freeze);
}
-
-// ES5 15.2.3.10
-// http://es5.github.com/#x15.2.3.10
if (!Object.preventExtensions) {
Object.preventExtensions = function preventExtensions(object) {
- // this is misleading and breaks feature-detection, but
- // allows "securable" code to "gracefully" degrade to working
- // but insecure code.
return object;
};
}
-
-// ES5 15.2.3.11
-// http://es5.github.com/#x15.2.3.11
if (!Object.isSealed) {
Object.isSealed = function isSealed(object) {
return false;
};
}
-
-// ES5 15.2.3.12
-// http://es5.github.com/#x15.2.3.12
if (!Object.isFrozen) {
Object.isFrozen = function isFrozen(object) {
return false;
};
}
-
-// ES5 15.2.3.13
-// http://es5.github.com/#x15.2.3.13
if (!Object.isExtensible) {
Object.isExtensible = function isExtensible(object) {
- // 1. If Type(O) is not Object throw a TypeError exception.
if (Object(object) === object) {
throw new TypeError(); // TODO message
}
- // 2. Return the Boolean value of the [[Extensible]] internal property of O.
var name = '';
while (owns(object, name)) {
name += '?';
@@ -1028,11 +685,7 @@ if (!Object.isExtensible) {
return returnValue;
};
}
-
-// ES5 15.2.3.14
-// http://es5.github.com/#x15.2.3.14
if (!Object.keys) {
- // http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation
var hasDontEnumBug = true,
dontEnums = [
"toString",
@@ -1073,26 +726,11 @@ if (!Object.keys) {
};
}
-
-//
-// Date
-// ====
-//
-
-// ES5 15.9.5.43
-// http://es5.github.com/#x15.9.5.43
-// This function returns a String value represent the instance in time
-// represented by this Date object. The format of the String is the Date Time
-// string format defined in 15.9.1.15. All fields are present in the String.
-// The time zone is always UTC, denoted by the suffix Z. If the time value of
-// this object is not a finite Number a RangeError exception is thrown.
if (!Date.prototype.toISOString || (new Date(-62198755200000).toISOString().indexOf('-000001') === -1)) {
Date.prototype.toISOString = function toISOString() {
var result, length, value, year;
if (!isFinite(this))
throw new RangeError;
-
- // the date time string format is specified in 15.9.1.15.
result = [this.getUTCMonth() + 1, this.getUTCDate(),
this.getUTCHours(), this.getUTCMinutes(), this.getUTCSeconds()];
year = this.getUTCFullYear();
@@ -1101,76 +739,32 @@ if (!Date.prototype.toISOString || (new Date(-62198755200000).toISOString().inde
length = result.length;
while (length--) {
value = result[length];
- // pad months, days, hours, minutes, and seconds to have two digits.
if (value < 10)
result[length] = "0" + value;
}
- // pad milliseconds to have three digits.
return year + "-" + result.slice(0, 2).join("-") + "T" + result.slice(2).join(":") + "." +
("000" + this.getUTCMilliseconds()).slice(-3) + "Z";
}
}
-
-// ES5 15.9.4.4
-// http://es5.github.com/#x15.9.4.4
if (!Date.now) {
Date.now = function now() {
return new Date().getTime();
};
}
-
-// ES5 15.9.5.44
-// http://es5.github.com/#x15.9.5.44
-// This function provides a String representation of a Date object for use by
-// JSON.stringify (15.12.3).
if (!Date.prototype.toJSON) {
Date.prototype.toJSON = function toJSON(key) {
- // When the toJSON method is called with argument key, the following
- // steps are taken:
-
- // 1. Let O be the result of calling ToObject, giving it the this
- // value as its argument.
- // 2. Let tv be ToPrimitive(O, hint Number).
- // 3. If tv is a Number and is not finite, return null.
- // XXX
- // 4. Let toISO be the result of calling the [[Get]] internal method of
- // O with argument "toISOString".
- // 5. If IsCallable(toISO) is false, throw a TypeError exception.
if (typeof this.toISOString != "function")
throw new TypeError(); // TODO message
- // 6. Return the result of calling the [[Call]] internal method of
- // toISO with O as the this value and an empty argument list.
return this.toISOString();
-
- // NOTE 1 The argument is ignored.
-
- // NOTE 2 The toJSON function is intentionally generic; it does not
- // require that its this value be a Date object. Therefore, it can be
- // transferred to other kinds of objects for use as a method. However,
- // it does require that any such object have a toISOString method. An
- // object is free to use the argument key to filter its
- // stringification.
};
}
-
-// ES5 15.9.4.2
-// http://es5.github.com/#x15.9.4.2
-// based on work shared by Daniel Friesen (dantman)
-// http://gist.github.com/303249
if (Date.parse("+275760-09-13T00:00:00.000Z") !== 8.64e15) {
- // XXX global assignment won't work in embeddings that use
- // an alternate object for the context.
Date = (function(NativeDate) {
-
- // Date.length === 7
var Date = function Date(Y, M, D, h, m, s, ms) {
var length = arguments.length;
if (this instanceof NativeDate) {
var date = length == 1 && String(Y) === Y ? // isString(Y)
- // We explicitly pass it through parse:
new NativeDate(Date.parse(Y)) :
- // We have to manually make calls depending on argument
- // length here
length >= 7 ? new NativeDate(Y, M, D, h, m, s, ms) :
length >= 6 ? new NativeDate(Y, M, D, h, m, s) :
length >= 5 ? new NativeDate(Y, M, D, h, m) :
@@ -1179,14 +773,11 @@ if (Date.parse("+275760-09-13T00:00:00.000Z") !== 8.64e15) {
length >= 2 ? new NativeDate(Y, M) :
length >= 1 ? new NativeDate(Y) :
new NativeDate();
- // Prevent mixups with unfixed Date object
date.constructor = Date;
return date;
}
return NativeDate.apply(this, arguments);
};
-
- // 15.9.1.15 Date Time String Format.
var isoDateExpression = new RegExp("^" +
"(\\d{4}|[\+\-]\\d{6})" + // four-digit year capture or sign + 6-digit extended year
"(?:-(\\d{2})" + // optional month capture
@@ -1207,59 +798,33 @@ if (Date.parse("+275760-09-13T00:00:00.000Z") !== 8.64e15) {
")" +
")?)?)?)?" +
"$");
-
- // Copy any custom methods a 3rd party library may have added
for (var key in NativeDate)
Date[key] = NativeDate[key];
-
- // Copy "native" methods explicitly; they may be non-enumerable
Date.now = NativeDate.now;
Date.UTC = NativeDate.UTC;
Date.prototype = NativeDate.prototype;
Date.prototype.constructor = Date;
-
- // Upgrade Date.parse to handle simplified ISO 8601 strings
Date.parse = function parse(string) {
var match = isoDateExpression.exec(string);
if (match) {
match.shift(); // kill match[0], the full match
- // parse months, days, hours, minutes, seconds, and milliseconds
for (var i = 1; i < 7; i++) {
- // provide default values if necessary
match[i] = +(match[i] || (i < 3 ? 1 : 0));
- // match[1] is the month. Months are 0-11 in JavaScript
- // `Date` objects, but 1-12 in ISO notation, so we
- // decrement.
if (i == 1)
match[i]--;
}
-
- // parse the UTC offset component
var minuteOffset = +match.pop(), hourOffset = +match.pop(), sign = match.pop();
-
- // compute the explicit time zone offset if specified
var offset = 0;
if (sign) {
- // detect invalid offsets and return early
if (hourOffset > 23 || minuteOffset > 59)
return NaN;
-
- // express the provided time zone offset in minutes. The offset is
- // negative for time zones west of UTC; positive otherwise.
offset = (hourOffset * 60 + minuteOffset) * 6e4 * (sign == "+" ? -1 : 1);
}
-
- // Date.UTC for years between 0 and 99 converts year to 1900 + year
- // The Gregorian calendar has a 400-year cycle, so
- // to Date.UTC(year + 400, .... ) - 12622780800000 == Date.UTC(year, ...),
- // where 12622780800000 - number of milliseconds in Gregorian calendar 400 years
var year = +match[0];
if (0 <= year && year <= 99) {
match[0] = year + 400;
return NativeDate.UTC.apply(this, match) + offset - 12622780800000;
}
-
- // compute a new UTC date value, accounting for the optional offset
return NativeDate.UTC.apply(this, match) + offset;
}
return NativeDate.parse.apply(this, arguments);
@@ -1268,20 +833,10 @@ if (Date.parse("+275760-09-13T00:00:00.000Z") !== 8.64e15) {
return Date;
})(Date);
}
-
-//
-// String
-// ======
-//
-
-// ES5 15.5.4.20
-// http://es5.github.com/#x15.5.4.20
var ws = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003" +
"\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028" +
"\u2029\uFEFF";
if (!String.prototype.trim || ws.trim()) {
- // http://blog.stevenlevithan.com/archives/faster-trim-javascript
- // http://perfectionkills.com/whitespace-deviations/
ws = "[" + ws + "]";
var trimBeginRegexp = new RegExp("^" + ws + ws + "*"),
trimEndRegexp = new RegExp(ws + ws + "*$");
@@ -1289,15 +844,6 @@ if (!String.prototype.trim || ws.trim()) {
return String(this).replace(trimBeginRegexp, "").replace(trimEndRegexp, "");
};
}
-
-//
-// Util
-// ======
-//
-
-// ES5 9.4
-// http://es5.github.com/#x9.4
-// http://jsperf.com/to-integer
var toInteger = function (n) {
n = +n;
if (n !== n) // isNaN
@@ -1308,61 +854,19 @@ var toInteger = function (n) {
};
var prepareString = "a"[0] != "a",
- // ES5 9.9
- // http://es5.github.com/#x9.9
toObject = function (o) {
if (o == null) { // this matches both null and undefined
throw new TypeError(); // TODO message
}
- // If the implementation doesn't support by-index access of
- // string characters (ex. IE < 7), split the string
if (prepareString && typeof o == "string" && o) {
return o.split("");
}
return Object(o);
};
-});/* vim:ts=4:sts=4:sw=4:
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Ajax.org Code Editor (ACE).
- *
- * The Initial Developer of the Original Code is
- * Ajax.org B.V.
- * Portions created by the Initial Developer are Copyright (C) 2010
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Fabian Jakobs <fabian AT ajax DOT org>
- * Irakli Gozalishvili <rfobic@gmail.com> (http://jeditoolkit.com)
- * Mike de Boer <mike AT ajax DOT org>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
+});
define('ace/lib/event_emitter', ['require', 'exports', 'module' ], function(require, exports, module) {
-"use strict";
+
var EventEmitter = {};
@@ -1376,8 +880,11 @@ EventEmitter._dispatchEvent = function(eventName, e) {
if (!listeners.length && !defaultHandler)
return;
- e = e || {};
- e.type = eventName;
+ if (typeof e != "object" || !e)
+ e = {};
+
+ if (!e.type)
+ e.type = eventName;
if (!e.stopPropagation) {
e.stopPropagation = function() {
@@ -1398,7 +905,7 @@ EventEmitter._dispatchEvent = function(eventName, e) {
}
if (defaultHandler && !e.defaultPrevented)
- defaultHandler(e);
+ return defaultHandler(e);
};
EventEmitter.setDefaultHandler = function(eventName, callback) {
@@ -1416,7 +923,7 @@ EventEmitter.addEventListener = function(eventName, callback) {
var listeners = this._eventRegistry[eventName];
if (!listeners)
- var listeners = this._eventRegistry[eventName] = [];
+ listeners = this._eventRegistry[eventName] = [];
if (listeners.indexOf(callback) == -1)
listeners.push(callback);
@@ -1441,45 +948,10 @@ EventEmitter.removeAllListeners = function(eventName) {
exports.EventEmitter = EventEmitter;
-});/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Ajax.org Code Editor (ACE).
- *
- * The Initial Developer of the Original Code is
- * Ajax.org B.V.
- * Portions created by the Initial Developer are Copyright (C) 2010
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Fabian Jakobs <fabian AT ajax DOT org>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
+});
define('ace/lib/oop', ['require', 'exports', 'module' ], function(require, exports, module) {
-"use strict";
+
exports.inherits = (function() {
var tempCtor = function() {};
@@ -1502,95 +974,156 @@ exports.implement = function(proto, mixin) {
};
});
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Ajax.org Code Editor (ACE).
- *
- * The Initial Developer of the Original Code is
- * Ajax.org B.V.
- * Portions created by the Initial Developer are Copyright (C) 2010
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Fabian Jakobs <fabian AT ajax DOT org>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-define('ace/mode/javascript_worker', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/worker/mirror', 'ace/worker/jshint', 'ace/narcissus/jsparse'], function(require, exports, module) {
-"use strict";
-
+
+define('ace/mode/javascript_worker', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/worker/mirror', 'ace/mode/javascript/jshint'], function(require, exports, module) {
+
+
var oop = require("../lib/oop");
var Mirror = require("../worker/mirror").Mirror;
-var lint = require("../worker/jshint").JSHINT;
-
+var lint = require("./javascript/jshint").JSHINT;
+
+function startRegex(arr) {
+ return RegExp("^(" + arr.join("|") + ")");
+}
+
+var disabledWarningsRe = startRegex([
+ "Bad for in variable '(.+)'.",
+ 'Missing "use strict"'
+]);
+var errorsRe = startRegex([
+ "Unexpected",
+ "Expected ",
+ "Confusing (plus|minus)",
+ "\\{a\\} unterminated regular expression",
+ "Unclosed ",
+ "Unmatched ",
+ "Unbegun comment",
+ "Bad invocation",
+ "Missing space after",
+ "Missing operator at"
+]);
+var infoRe = startRegex([
+ "Expected an assignment",
+ "Bad escapement of EOL",
+ "Unexpected comma",
+ "Unexpected space",
+ "Missing radix parameter.",
+ "A leading decimal point can",
+ "\\['{a}'\\] is better written in dot notation.",
+ "'{a}' used out of scope"
+]);
+
var JavaScriptWorker = exports.JavaScriptWorker = function(sender) {
Mirror.call(this, sender);
this.setTimeout(500);
+ this.setOptions();
};
oop.inherits(JavaScriptWorker, Mirror);
(function() {
-
+ this.setOptions = function(options) {
+ this.options = options || {
+ es5: true,
+ esnext: true,
+ devel: true,
+ browser: true,
+ node: true,
+ laxcomma: true,
+ laxbreak: true,
+ lastsemic: true,
+ onevar: false,
+ passfail: false,
+ maxerr: 100,
+ expr: true,
+ multistr: true,
+ globalstrict: true
+ };
+ this.doc.getValue() && this.deferredUpdate.schedule(100);
+ };
+
+ this.changeOptions = function(newOptions) {
+ oop.mixin(this.options, newOptions);
+ this.doc.getValue() && this.deferredUpdate.schedule(100);
+ };
+
+ this.isValidJS = function(str) {
+ try {
+ eval("throw 0;" + str);
+ } catch(e) {
+ if (e === 0)
+ return true;
+ }
+ return false
+ };
+
this.onUpdate = function() {
var value = this.doc.getValue();
value = value.replace(/^#!.*\n/, "\n");
-
-// var start = new Date();
- var parser = require("../narcissus/jsparse");
- try {
- parser.parse(value);
- } catch(e) {
-// console.log("narcissus")
-// console.log(e);
- var chunks = e.message.split(":")
- var message = chunks.pop().trim();
- var lineNumber = parseInt(chunks.pop().trim()) - 1;
- this.sender.emit("narcissus", {
- row: lineNumber,
- column: null, // TODO convert e.cursor
- text: message,
- type: "error"
- });
+ if (!value) {
+ this.sender.emit("jslint", []);
return;
- } finally {
-// console.log("parse time: " + (new Date() - start));
}
-
-// var start = new Date();
-// console.log("jslint")
- lint(value, {undef: false, onevar: false, passfail: false});
- this.sender.emit("jslint", lint.errors);
-// console.log("lint time: " + (new Date() - start));
- }
-
+ var errors = [];
+ var maxErrorLevel = this.isValidJS(value) ? "warning" : "error";
+ lint(value, this.options);
+ var results = lint.errors;
+
+ var errorAdded = false
+ for (var i = 0; i < results.length; i++) {
+ var error = results[i];
+ if (!error)
+ continue;
+ var raw = error.raw;
+ var type = "warning";
+
+ if (raw == "Missing semicolon.") {
+ var str = error.evidence.substr(error.character);
+ str = str.charAt(str.search(/\S/));
+ if (maxErrorLevel == "error" && str && /[\w\d{(['"]/.test(str)) {
+ error.reason = 'Missing ";" before statement';
+ type = "error";
+ } else {
+ type = "info";
+ }
+ }
+ else if (disabledWarningsRe.test(raw)) {
+ continue;
+ }
+ else if (infoRe.test(raw)) {
+ type = "info"
+ }
+ else if (errorsRe.test(raw)) {
+ errorAdded = true;
+ type = maxErrorLevel;
+ }
+ else if (raw == "'{a}' is not defined.") {
+ type = "warning";
+ }
+ else if (raw == "'{a}' is defined but never used.") {
+ type = "info";
+ }
+
+ errors.push({
+ row: error.line-1,
+ column: error.character-1,
+ text: error.reason,
+ type: type,
+ raw: raw
+ });
+
+ if (errorAdded) {
+ }
+ }
+
+ this.sender.emit("jslint", errors);
+ };
+
}).call(JavaScriptWorker.prototype);
-});define('ace/worker/mirror', ['require', 'exports', 'module' , 'ace/document', 'ace/lib/lang'], function(require, exports, module) {
-"use strict";
+});
+define('ace/worker/mirror', ['require', 'exports', 'module' , 'ace/document', 'ace/lib/lang'], function(require, exports, module) {
+
var Document = require("../document").Document;
var lang = require("../lib/lang");
@@ -1626,50 +1159,14 @@ var Mirror = exports.Mirror = function(sender) {
};
this.onUpdate = function() {
- // abstract method
};
}).call(Mirror.prototype);
-});/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Ajax.org Code Editor (ACE).
- *
- * The Initial Developer of the Original Code is
- * Ajax.org B.V.
- * Portions created by the Initial Developer are Copyright (C) 2010
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Fabian Jakobs <fabian AT ajax DOT org>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
+});
define('ace/document', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/event_emitter', 'ace/range', 'ace/anchor'], function(require, exports, module) {
-"use strict";
+
var oop = require("./lib/oop");
var EventEmitter = require("./lib/event_emitter").EventEmitter;
@@ -1678,14 +1175,10 @@ var Anchor = require("./anchor").Anchor;
var Document = function(text) {
this.$lines = [];
-
- if (Array.isArray(text)) {
- this.insertLines(0, text);
- }
- // There has to be one line at least in the document. If you pass an empty
- // string to the insert function, nothing will happen. Workaround.
- else if (text.length == 0) {
+ if (text.length == 0) {
this.$lines = [""];
+ } else if (Array.isArray(text)) {
+ this.insertLines(0, text);
} else {
this.insert({row: 0, column:0}, text);
}
@@ -1694,22 +1187,17 @@ var Document = function(text) {
(function() {
oop.implement(this, EventEmitter);
-
this.setValue = function(text) {
var len = this.getLength();
this.remove(new Range(0, 0, len, this.getLine(len-1).length));
this.insert({row: 0, column:0}, text);
};
-
this.getValue = function() {
return this.getAllLines().join(this.getNewLineCharacter());
};
-
this.createAnchor = function(row, column) {
return new Anchor(this, row, column);
};
-
- // check for IE split bug
if ("aaa".split(/a/).length == 0)
this.$split = function(text) {
return text.replace(/\r\n|\r/g, "\n").split("\n");
@@ -1720,6 +1208,7 @@ var Document = function(text) {
};
+
this.$detectNewLine = function(text) {
var match = text.match(/^.*?(\r\n|\r|\n)/m);
if (match) {
@@ -1728,18 +1217,17 @@ var Document = function(text) {
this.$autoNewLine = "\n";
}
};
-
this.getNewLineCharacter = function() {
- switch (this.$newLineMode) {
+ switch (this.$newLineMode) {
case "windows":
- return "\r\n";
+ return "\r\n";
case "unix":
- return "\n";
+ return "\n";
- case "auto":
- return this.$autoNewLine;
- }
+ default:
+ return this.$autoNewLine;
+ }
};
this.$autoNewLine = "\n";
@@ -1750,48 +1238,33 @@ var Document = function(text) {
this.$newLineMode = newLineMode;
};
-
this.getNewLineMode = function() {
return this.$newLineMode;
};
-
this.isNewLine = function(text) {
return (text == "\r\n" || text == "\r" || text == "\n");
};
-
- /**
- * Get a verbatim copy of the given line as it is in the document
- */
this.getLine = function(row) {
return this.$lines[row] || "";
};
-
this.getLines = function(firstRow, lastRow) {
return this.$lines.slice(firstRow, lastRow + 1);
};
-
- /**
- * Returns all lines in the document as string array. Warning: The caller
- * should not modify this array!
- */
this.getAllLines = function() {
return this.getLines(0, this.getLength());
};
-
this.getLength = function() {
return this.$lines.length;
};
-
this.getTextRange = function(range) {
if (range.start.row == range.end.row) {
return this.$lines[range.start.row].substring(range.start.column,
range.end.column);
}
else {
- var lines = [];
- lines.push(this.$lines[range.start.row].substring(range.start.column));
- lines.push.apply(lines, this.getLines(range.start.row+1, range.end.row-1));
- lines.push(this.$lines[range.end.row].substring(0, range.end.column));
+ var lines = this.getLines(range.start.row+1, range.end.row-1);
+ lines.unshift((this.$lines[range.start.row] || "").substring(range.start.column));
+ lines.push((this.$lines[range.end.row] || "").substring(0, range.end.column));
return lines.join(this.getNewLineCharacter());
}
};
@@ -1804,13 +1277,11 @@ var Document = function(text) {
}
return position;
};
-
this.insert = function(position, text) {
- if (text.length == 0)
+ if (!text || text.length === 0)
return position;
position = this.$clipPosition(position);
-
if (this.getLength() <= 1)
this.$detectNewLine(text);
@@ -1826,10 +1297,13 @@ var Document = function(text) {
}
return position;
};
-
this.insertLines = function(row, lines) {
if (lines.length == 0)
return {row: row, column: 0};
+ if (lines.length > 0xFFFF) {
+ var end = this.insertLines(row, lines.slice(0xFFFF));
+ lines = lines.slice(0, 0xFFFF);
+ }
var args = [row, 0];
args.push.apply(args, lines);
@@ -1842,9 +1316,8 @@ var Document = function(text) {
lines: lines
};
this._emit("change", { data: delta });
- return range.end;
+ return end || range.end;
};
-
this.insertNewLine = function(position) {
position = this.$clipPosition(position);
var line = this.$lines[position.row] || "";
@@ -1866,7 +1339,6 @@ var Document = function(text) {
return end;
};
-
this.insertInLine = function(position, text) {
if (text.length == 0)
return position;
@@ -1890,9 +1362,7 @@ var Document = function(text) {
return end;
};
-
this.remove = function(range) {
- // clip to document
range.start = this.$clipPosition(range.start);
range.end = this.$clipPosition(range.end);
@@ -1922,7 +1392,6 @@ var Document = function(text) {
}
return range.start;
};
-
this.removeInLine = function(row, startColumn, endColumn) {
if (startColumn == endColumn)
return;
@@ -1941,14 +1410,6 @@ var Document = function(text) {
this._emit("change", { data: delta });
return range.start;
};
-
- /**
- * Removes a range of full lines
- *
- * @param firstRow {Integer} The first row to be removed
- * @param lastRow {Integer} The last row to be removed
- * @return {String[]} The removed lines
- */
this.removeLines = function(firstRow, lastRow) {
var range = new Range(firstRow, 0, lastRow + 1, 0);
var removed = this.$lines.splice(firstRow, lastRow - firstRow + 1);
@@ -1962,7 +1423,6 @@ var Document = function(text) {
this._emit("change", { data: delta });
return removed;
};
-
this.removeNewLine = function(row) {
var firstLine = this.getLine(row);
var secondLine = this.getLine(row+1);
@@ -1979,13 +1439,9 @@ var Document = function(text) {
};
this._emit("change", { data: delta });
};
-
this.replace = function(range, text) {
if (text.length == 0 && range.isEmpty())
return range.start;
-
- // Shortcut: If the text we want to insert is the same as it is already
- // in the document, we don't have to replace anything.
if (text == this.getTextRange(range))
return range.end;
@@ -1999,7 +1455,6 @@ var Document = function(text) {
return end;
};
-
this.applyDeltas = function(deltas) {
for (var i=0; i<deltas.length; i++) {
var delta = deltas[i];
@@ -2015,7 +1470,6 @@ var Document = function(text) {
this.remove(range);
}
};
-
this.revertDeltas = function(deltas) {
for (var i=deltas.length-1; i>=0; i--) {
var delta = deltas[i];
@@ -2032,51 +1486,33 @@ var Document = function(text) {
this.insert(range.start, delta.text);
}
};
+ this.indexToPosition = function(index, startRow) {
+ var lines = this.$lines || this.getAllLines();
+ var newlineLength = this.getNewLineCharacter().length;
+ for (var i = startRow || 0, l = lines.length; i < l; i++) {
+ index -= lines[i].length + newlineLength;
+ if (index < 0)
+ return {row: i, column: index + lines[i].length + newlineLength};
+ }
+ return {row: l-1, column: lines[l-1].length};
+ };
+ this.positionToIndex = function(pos, startRow) {
+ var lines = this.$lines || this.getAllLines();
+ var newlineLength = this.getNewLineCharacter().length;
+ var index = 0;
+ var row = Math.min(pos.row, lines.length);
+ for (var i = startRow || 0; i < row; ++i)
+ index += lines[i].length;
+
+ return index + newlineLength * i + pos.column;
+ };
}).call(Document.prototype);
exports.Document = Document;
});
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Ajax.org Code Editor (ACE).
- *
- * The Initial Developer of the Original Code is
- * Ajax.org B.V.
- * Portions created by the Initial Developer are Copyright (C) 2010
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Fabian Jakobs <fabian AT ajax DOT org>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
define('ace/range', ['require', 'exports', 'module' ], function(require, exports, module) {
-"use strict";
-
var Range = function(startRow, startColumn, endRow, endColumn) {
this.start = {
row: startRow,
@@ -2089,36 +1525,21 @@ var Range = function(startRow, startColumn, endRow, endColumn) {
};
};
-(function() {
- this.isEequal = function(range) {
+(function() {
+ this.isEqual = function(range) {
return this.start.row == range.start.row &&
this.end.row == range.end.row &&
this.start.column == range.start.column &&
this.end.column == range.end.column
- };
-
+ };
this.toString = function() {
return ("Range: [" + this.start.row + "/" + this.start.column +
"] -> [" + this.end.row + "/" + this.end.column + "]");
- };
+ };
this.contains = function(row, column) {
return this.compare(row, column) == 0;
- };
-
- /**
- * Compares this range (A) with another range (B), where B is the passed in
- * range.
- *
- * Return values:
- * -2: (B) is infront of (A) and doesn't intersect with (A)
- * -1: (B) begins before (A) but ends inside of (A)
- * 0: (B) is completly inside of (A) OR (A) is complety inside of (B)
- * +1: (B) begins inside of (A) but ends outside of (A)
- * +2: (B) is after (A) and doesn't intersect with (A)
- *
- * 42: FTW state: (B) ends in (A) but starts outside of (A)
- */
+ };
this.compareRange = function(range) {
var cmp,
end = range.end,
@@ -2146,24 +1567,23 @@ var Range = function(startRow, startColumn, endRow, endColumn) {
return 0;
}
}
- }
-
+ };
this.comparePoint = function(p) {
return this.compare(p.row, p.column);
- }
-
+ };
this.containsRange = function(range) {
return this.comparePoint(range.start) == 0 && this.comparePoint(range.end) == 0;
- }
-
+ };
+ this.intersects = function(range) {
+ var cmp = this.compareRange(range);
+ return (cmp == -1 || cmp == 0 || cmp == 1);
+ };
this.isEnd = function(row, column) {
return this.end.row == row && this.end.column == column;
- }
-
+ };
this.isStart = function(row, column) {
return this.start.row == row && this.start.column == column;
- }
-
+ };
this.setStart = function(row, column) {
if (typeof row == "object") {
this.start.column = row.column;
@@ -2172,8 +1592,7 @@ var Range = function(startRow, startColumn, endRow, endColumn) {
this.start.row = row;
this.start.column = column;
}
- }
-
+ };
this.setEnd = function(row, column) {
if (typeof row == "object") {
this.end.column = row.column;
@@ -2182,8 +1601,7 @@ var Range = function(startRow, startColumn, endRow, endColumn) {
this.end.row = row;
this.end.column = column;
}
- }
-
+ };
this.inside = function(row, column) {
if (this.compare(row, column) == 0) {
if (this.isEnd(row, column) || this.isStart(row, column)) {
@@ -2193,8 +1611,7 @@ var Range = function(startRow, startColumn, endRow, endColumn) {
}
}
return false;
- }
-
+ };
this.insideStart = function(row, column) {
if (this.compare(row, column) == 0) {
if (this.isEnd(row, column)) {
@@ -2204,8 +1621,7 @@ var Range = function(startRow, startColumn, endRow, endColumn) {
}
}
return false;
- }
-
+ };
this.insideEnd = function(row, column) {
if (this.compare(row, column) == 0) {
if (this.isStart(row, column)) {
@@ -2215,8 +1631,7 @@ var Range = function(startRow, startColumn, endRow, endColumn) {
}
}
return false;
- }
-
+ };
this.compare = function(row, column) {
if (!this.isMultiLine()) {
if (row === this.start.row) {
@@ -2238,29 +1653,20 @@ var Range = function(startRow, startColumn, endRow, endColumn) {
return 0;
};
-
- /**
- * Like .compare(), but if isStart is true, return -1;
- */
this.compareStart = function(row, column) {
if (this.start.row == row && this.start.column == column) {
return -1;
} else {
return this.compare(row, column);
}
- }
-
- /**
- * Like .compare(), but if isEnd is true, return 1;
- */
+ };
this.compareEnd = function(row, column) {
if (this.end.row == row && this.end.column == column) {
return 1;
} else {
return this.compare(row, column);
}
- }
-
+ };
this.compareInside = function(row, column) {
if (this.end.row == row && this.end.column == column) {
return 1;
@@ -2269,8 +1675,7 @@ var Range = function(startRow, startColumn, endRow, endColumn) {
} else {
return this.compare(row, column);
}
- }
-
+ };
this.clipRows = function(firstRow, lastRow) {
if (this.end.row > lastRow) {
var end = {
@@ -2301,7 +1706,6 @@ var Range = function(startRow, startColumn, endRow, endColumn) {
}
return Range.fromPoints(start || this.start, end || this.end);
};
-
this.extend = function(row, column) {
var cmp = this.compare(row, column);
@@ -2318,22 +1722,18 @@ var Range = function(startRow, startColumn, endRow, endColumn) {
this.isEmpty = function() {
return (this.start.row == this.end.row && this.start.column == this.end.column);
};
-
this.isMultiLine = function() {
return (this.start.row !== this.end.row);
};
-
this.clone = function() {
return Range.fromPoints(this.start, this.end);
};
-
this.collapseRows = function() {
if (this.end.column == 0)
return new Range(this.start.row, 0, Math.max(this.start.row, this.end.row-1), 0)
else
return new Range(this.start.row, 0, this.end.row, 0)
};
-
this.toScreenRange = function(session) {
var screenPosStart =
session.documentToScreenPosition(this.start);
@@ -2347,61 +1747,19 @@ var Range = function(startRow, startColumn, endRow, endColumn) {
};
}).call(Range.prototype);
-
-
Range.fromPoints = function(start, end) {
return new Range(start.row, start.column, end.row, end.column);
};
exports.Range = Range;
});
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Ajax.org Code Editor (ACE).
- *
- * The Initial Developer of the Original Code is
- * Ajax.org B.V.
- * Portions created by the Initial Developer are Copyright (C) 2010
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Fabian Jakobs <fabian AT ajax DOT org>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
define('ace/anchor', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/event_emitter'], function(require, exports, module) {
-"use strict";
+
var oop = require("./lib/oop");
var EventEmitter = require("./lib/event_emitter").EventEmitter;
-/**
- * An Anchor is a floating pointer in the document. Whenever text is inserted or
- * deleted before the cursor, the position of the cursor is updated
- */
var Anchor = exports.Anchor = function(doc, row, column) {
this.document = doc;
@@ -2417,15 +1775,15 @@ var Anchor = exports.Anchor = function(doc, row, column) {
(function() {
oop.implement(this, EventEmitter);
-
+
this.getPosition = function() {
return this.$clipPositionToDocument(this.row, this.column);
};
-
+
this.getDocument = function() {
return this.document;
};
-
+
this.onChange = function(e) {
var delta = e.data;
var range = delta.range;
@@ -2518,11 +1876,10 @@ var Anchor = exports.Anchor = function(doc, row, column) {
value: pos
});
};
-
+
this.detach = function() {
this.document.removeEventListener("change", this.$onChange);
};
-
this.$clipPositionToDocument = function(row, column) {
var pos = {};
@@ -2548,45 +1905,9 @@ var Anchor = exports.Anchor = function(doc, row, column) {
}).call(Anchor.prototype);
});
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Ajax.org Code Editor (ACE).
- *
- * The Initial Developer of the Original Code is
- * Ajax.org B.V.
- * Portions created by the Initial Developer are Copyright (C) 2010
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Fabian Jakobs <fabian AT ajax DOT org>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
define('ace/lib/lang', ['require', 'exports', 'module' ], function(require, exports, module) {
-"use strict";
+
exports.stringReverse = function(string) {
return string.split("").reverse().join("");
@@ -2651,9 +1972,13 @@ exports.arrayToMap = function(arr) {
};
-/**
- * splice out of 'array' anything that === 'value'
- */
+exports.createMap = function(props) {
+ var map = Object.create(null);
+ for (var i in props) {
+ map[i] = props[i];
+ }
+ return map;
+};
exports.arrayRemove = function(array, value) {
for (var i = 0; i <= array.length; i++) {
if (value === array[i]) {
@@ -2666,6 +1991,22 @@ exports.escapeRegExp = function(str) {
return str.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1');
};
+exports.escapeHTML = function(str) {
+ return str.replace(/&/g, "&#38;").replace(/"/g, "&#34;").replace(/'/g, "&#39;").replace(/</g, "&#60;");
+};
+
+exports.getMatchOffsets = function(string, regExp) {
+ var matches = [];
+
+ string.replace(regExp, function(str) {
+ matches.push({
+ offset: arguments[arguments.length-2],
+ length: str.length
+ });
+ });
+
+ return matches;
+};
exports.deferredCall = function(fcn) {
var timer = null;
@@ -2697,7056 +2038,4370 @@ exports.deferredCall = function(fcn) {
return deferred;
};
-});
-define('ace/worker/jshint', ['require', 'exports', 'module' ], function(require, exports, module) {
-/*!
- * JSHint, by JSHint Community.
- *
- * Licensed under the same slightly modified MIT license that JSLint is.
- * It stops evil-doers everywhere.
- *
- * JSHint is a derivative work of JSLint:
- *
- * Copyright (c) 2002 Douglas Crockford (www.JSLint.com)
- *
- * 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 shall be used for Good, not Evil.
- *
- * 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.
- *
- * JSHint was forked from 2010-12-16 edition of JSLint.
- *
- */
-
-/*
- JSHINT is a global function. It takes two parameters.
-
- var myResult = JSHINT(source, option);
-
- The first parameter is either a string or an array of strings. If it is a
- string, it will be split on '\n' or '\r'. If it is an array of strings, it
- is assumed that each string represents one line. The source can be a
- JavaScript text or a JSON text.
-
- The second parameter is an optional object of options which control the
- operation of JSHINT. Most of the options are booleans: They are all
- optional and have a default value of false. One of the options, predef,
- can be an array of names, which will be used to declare global variables,
- or an object whose keys are used as global names, with a boolean value
- that determines if they are assignable.
-
- If it checks out, JSHINT returns true. Otherwise, it returns false.
-
- If false, you can inspect JSHINT.errors to find out the problems.
- JSHINT.errors is an array of objects containing these members:
-
- {
- line : The line (relative to 0) at which the lint was found
- character : The character (relative to 0) at which the lint was found
- reason : The problem
- evidence : The text line in which the problem occurred
- raw : The raw message before the details were inserted
- a : The first detail
- b : The second detail
- c : The third detail
- d : The fourth detail
- }
-
- If a fatal error was found, a null will be the last element of the
- JSHINT.errors array.
-
- You can request a Function Report, which shows all of the functions
- and the parameters and vars that they use. This can be used to find
- implied global variables and other problems. The report is in HTML and
- can be inserted in an HTML <body>.
-
- var myReport = JSHINT.report(limited);
-
- If limited is true, then the report will be limited to only errors.
-
- You can request a data structure which contains JSHint's results.
-
- var myData = JSHINT.data();
-
- It returns a structure with this form:
-
- {
- errors: [
- {
- line: NUMBER,
- character: NUMBER,
- reason: STRING,
- evidence: STRING
- }
- ],
- functions: [
- name: STRING,
- line: NUMBER,
- last: NUMBER,
- param: [
- STRING
- ],
- closure: [
- STRING
- ],
- var: [
- STRING
- ],
- exception: [
- STRING
- ],
- outer: [
- STRING
- ],
- unused: [
- STRING
- ],
- global: [
- STRING
- ],
- label: [
- STRING
- ]
- ],
- globals: [
- STRING
- ],
- member: {
- STRING: NUMBER
- },
- unuseds: [
- {
- name: STRING,
- line: NUMBER
- }
- ],
- implieds: [
- {
- name: STRING,
- line: NUMBER
- }
- ],
- urls: [
- STRING
- ],
- json: BOOLEAN
- }
-
- Empty arrays will not be included.
-
-*/
-
-/*jshint
- evil: true, nomen: false, onevar: false, regexp: false, strict: true, boss: true,
- undef: true, maxlen: 100
-*/
-
-/*members "\b", "\t", "\n", "\f", "\r", "!=", "!==", "\"", "%", "(begin)",
- "(breakage)", "(context)", "(error)", "(global)", "(identifier)", "(last)",
- "(line)", "(loopage)", "(name)", "(onevar)", "(params)", "(scope)",
- "(statement)", "(verb)", "*", "+", "++", "-", "--", "\/", "<", "<=", "==",
- "===", ">", ">=", $, $$, $A, $F, $H, $R, $break, $continue, $w, Abstract, Ajax,
- __filename, __dirname, ActiveXObject, Array, ArrayBuffer, ArrayBufferView,
- Autocompleter, Assets, Boolean, Builder, Buffer, Browser, COM, CScript, Canvas,
- CustomAnimation, Class, Control, Chain, Color, Cookie, Core, DataView, Date,
- Debug, Draggable, Draggables, Droppables, Document, DomReady, DOMReady, Drag,
- E, Enumerator, Enumerable, Element, Elements, Error, Effect, EvalError, Event,
- Events, FadeAnimation, Field, Flash, Float32Array, Float64Array, Form,
- FormField, Frame, Function, Fx, GetObject, Group, Hash, HotKey, HTMLElement,
- HtmlTable, Iframe, IframeShim, Image, Int16Array, Int32Array, Int8Array,
- Insertion, InputValidator, JSON, Keyboard, Locale, LN10, LN2, LOG10E, LOG2E,
- MAX_VALUE, MIN_VALUE, Mask, Math, MenuItem, MoveAnimation, MooTools, Native,
- NEGATIVE_INFINITY, Number, Object, ObjectRange, Option, Options, OverText, PI,
- POSITIVE_INFINITY, PeriodicalExecuter, Point, Position, Prototype, RangeError,
- Rectangle, ReferenceError, RegExp, ResizeAnimation, Request, RotateAnimation,
- SQRT1_2, SQRT2, ScrollBar, ScriptEngine, ScriptEngineBuildVersion,
- ScriptEngineMajorVersion, ScriptEngineMinorVersion, Scriptaculous, Scroller,
- Slick, Slider, Selector, String, Style, SyntaxError, Sortable, Sortables,
- SortableObserver, Sound, Spinner, System, Swiff, Text, TextArea, Template,
- Timer, Tips, Type, TypeError, Toggle, Try, URI, URIError, URL, VBArray, WSH,
- WScript, Web, Window, XMLDOM, XMLHttpRequest, XPathEvaluator, XPathException,
- XPathExpression, XPathNamespace, XPathNSResolver, XPathResult, "\\", a,
- addEventListener, address, alert, apply, applicationCache, arguments, arity,
- asi, b, bitwise, block, blur, boolOptions, boss, browser, c, call, callee,
- caller, cases, charAt, charCodeAt, character, clearInterval, clearTimeout,
- close, closed, closure, comment, condition, confirm, console, constructor,
- content, couch, create, css, curly, d, data, datalist, dd, debug, decodeURI,
- decodeURIComponent, defaultStatus, defineClass, deserialize, devel, document,
- dojo, dijit, dojox, define, edition, else, emit, encodeURI, encodeURIComponent,
- entityify, eqeqeq, eqnull, errors, es5, escape, eval, event, evidence, evil,
- ex, exception, exec, exps, expr, exports, FileReader, first, floor, focus,
- forin, fragment, frames, from, fromCharCode, fud, funct, function, functions,
- g, gc, getComputedStyle, getRow, GLOBAL, global, globals, globalstrict,
- hasOwnProperty, help, history, i, id, identifier, immed, implieds, include,
- indent, indexOf, init, ins, instanceOf, isAlpha, isApplicationRunning, isArray,
- isDigit, isFinite, isNaN, iterator, join, jshint,
- JSHINT, json, jquery, jQuery, keys, label, labelled, last, lastsemic, laxbreak,
- latedef, lbp, led, left, length, line, load, loadClass, localStorage, location,
- log, loopfunc, m, match, maxerr, maxlen, member,message, meta, module, moveBy,
- moveTo, mootools, name, navigator, new, newcap, noarg, node, noempty, nomen,
- nonew, nud, onbeforeunload, onblur, onerror, onevar, onfocus, onload, onresize,
- onunload, open, openDatabase, openURL, opener, opera, outer, param, parent,
- parseFloat, parseInt, passfail, plusplus, predef, print, process, prompt,
- proto, prototype, prototypejs, push, quit, range, raw, reach, reason, regexp,
- readFile, readUrl, regexdash, removeEventListener, replace, report, require,
- reserved, resizeBy, resizeTo, resolvePath, resumeUpdates, respond, rhino, right,
- runCommand, scroll, screen, scripturl, scrollBy, scrollTo, scrollbar, search, seal, send,
- serialize, setInterval, setTimeout, shift, slice, sort,spawn, split, stack,
- status, start, strict, sub, substr, supernew, shadow, supplant, sum, sync,
- test, toLowerCase, toString, toUpperCase, toint32, token, top, trailing, type,
- typeOf, Uint16Array, Uint32Array, Uint8Array, undef, unused, urls, value, valueOf,
- var, version, WebSocket, white, window, Worker, wsh*/
-
-/*global exports: false */
-
-// We build the application inside a function so that we produce only a single
-// global variable. That function will be invoked immediately, and its return
-// value is the JSHINT function itself.
-
-var JSHINT = (function () {
- "use strict";
-
- var anonname, // The guessed name for anonymous functions.
-
-// These are operators that should not be used with the ! operator.
-
- bang = {
- '<' : true,
- '<=' : true,
- '==' : true,
- '===': true,
- '!==': true,
- '!=' : true,
- '>' : true,
- '>=' : true,
- '+' : true,
- '-' : true,
- '*' : true,
- '/' : true,
- '%' : true
- },
-
-// These are the JSHint boolean options.
-
- boolOptions = {
- asi : true, // if automatic semicolon insertion should be tolerated
- bitwise : true, // if bitwise operators should not be allowed
- boss : true, // if advanced usage of assignments should be allowed
- browser : true, // if the standard browser globals should be predefined
- couch : true, // if CouchDB globals should be predefined
- curly : true, // if curly braces around all blocks should be required
- debug : true, // if debugger statements should be allowed
- devel : true, // if logging globals should be predefined (console, alert, etc.)
- dojo : true, // if Dojo Toolkit globals should be predefined
- eqeqeq : true, // if === should be required
- eqnull : true, // if == null comparisons should be tolerated
- es5 : true, // if ES5 syntax should be allowed
- evil : true, // if eval should be allowed
- expr : true, // if ExpressionStatement should be allowed as Programs
- forin : true, // if for in statements must filter
- globalstrict: true, // if global "use strict"; should be allowed (also enables 'strict')
- immed : true, // if immediate invocations must be wrapped in parens
- iterator : true, // if the `__iterator__` property should be disallowed
- jquery : true, // if jQuery globals should be predefined
- latedef : true, // if the use before definition should not be tolerated
- laxbreak : true, // if line breaks should not be checked
- loopfunc : true, // if functions should be allowed to be defined within loops
- mootools : true, // if MooTools globals should be predefined
- newcap : true, // if constructor names must be capitalized
- noarg : true, // if arguments.caller and arguments.callee should be disallowed
- node : true, // if the Node.js environment globals should be predefined
- noempty : true, // if empty blocks should be disallowed
- nonew : true, // if using `new` for side-effects should be disallowed
- nomen : true, // if names should be checked
- onevar : true, // if only one var statement per function should be allowed
- passfail : true, // if the scan should stop on first error
- plusplus : true, // if increment/decrement should not be allowed
- proto : true, // if the `__proto__` property should be disallowed
- prototypejs : true, // if Prototype and Scriptaculous globals should be predefined
- regexdash : true, // if unescaped last dash (-) inside brackets should be tolerated
- regexp : true, // if the . should not be allowed in regexp literals
- rhino : true, // if the Rhino environment globals should be predefined
- undef : true, // if variables should be declared before used
- scripturl : true, // if script-targeted URLs should be tolerated
- shadow : true, // if variable shadowing should be tolerated
- strict : true, // require the "use strict"; pragma
- sub : true, // if all forms of subscript notation are tolerated
- supernew : true, // if `new function () { ... };` and `new Object;`
- // should be tolerated
- trailing : true, // if trailing whitespace rules apply
- white : true, // if strict whitespace rules apply
- wsh : true // if the Windows Scripting Host environment globals should
- // be predefined
- },
-
-// browser contains a set of global names which are commonly provided by a
-// web browser environment.
-
- browser = {
- ArrayBuffer : false,
- ArrayBufferView : false,
- addEventListener: false,
- applicationCache: false,
- blur : false,
- clearInterval : false,
- clearTimeout : false,
- close : false,
- closed : false,
- DataView : false,
- defaultStatus : false,
- document : false,
- event : false,
- FileReader : false,
- Float32Array : false,
- Float64Array : false,
- focus : false,
- frames : false,
- getComputedStyle: false,
- HTMLElement : false,
- history : false,
- Int16Array : false,
- Int32Array : false,
- Int8Array : false,
- Image : false,
- length : false,
- localStorage : false,
- location : false,
- moveBy : false,
- moveTo : false,
- name : false,
- navigator : false,
- onbeforeunload : true,
- onblur : true,
- onerror : true,
- onfocus : true,
- onload : true,
- onresize : true,
- onunload : true,
- open : false,
- openDatabase : false,
- opener : false,
- Option : false,
- parent : false,
- print : false,
- removeEventListener: false,
- resizeBy : false,
- resizeTo : false,
- screen : false,
- scroll : false,
- scrollBy : false,
- scrollTo : false,
- setInterval : false,
- setTimeout : false,
- status : false,
- top : false,
- Uint16Array : false,
- Uint32Array : false,
- Uint8Array : false,
- WebSocket : false,
- window : false,
- Worker : false,
- XMLHttpRequest : false,
- XPathEvaluator : false,
- XPathException : false,
- XPathExpression : false,
- XPathNamespace : false,
- XPathNSResolver : false,
- XPathResult : false
- },
-
- couch = {
- "require" : false,
- respond : false,
- getRow : false,
- emit : false,
- send : false,
- start : false,
- sum : false,
- log : false,
- exports : false,
- module : false
- },
-
- devel = {
- alert : false,
- confirm : false,
- console : false,
- Debug : false,
- opera : false,
- prompt : false
- },
-
- dojo = {
- dojo : false,
- dijit : false,
- dojox : false,
- define : false,
- "require" : false
- },
-
- escapes = {
- '\b': '\\b',
- '\t': '\\t',
- '\n': '\\n',
- '\f': '\\f',
- '\r': '\\r',
- '"' : '\\"',
- '/' : '\\/',
- '\\': '\\\\'
- },
-
- funct, // The current function
-
- functionicity = [
- 'closure', 'exception', 'global', 'label',
- 'outer', 'unused', 'var'
- ],
-
- functions, // All of the functions
-
- global, // The global scope
- implied, // Implied globals
- inblock,
- indent,
- jsonmode,
-
- jquery = {
- '$' : false,
- jQuery : false
- },
-
- lines,
- lookahead,
- member,
- membersOnly,
-
- mootools = {
- '$' : false,
- '$$' : false,
- Assets : false,
- Browser : false,
- Chain : false,
- Class : false,
- Color : false,
- Cookie : false,
- Core : false,
- Document : false,
- DomReady : false,
- DOMReady : false,
- Drag : false,
- Element : false,
- Elements : false,
- Event : false,
- Events : false,
- Fx : false,
- Group : false,
- Hash : false,
- HtmlTable : false,
- Iframe : false,
- IframeShim : false,
- InputValidator : false,
- instanceOf : false,
- Keyboard : false,
- Locale : false,
- Mask : false,
- MooTools : false,
- Native : false,
- Options : false,
- OverText : false,
- Request : false,
- Scroller : false,
- Slick : false,
- Slider : false,
- Sortables : false,
- Spinner : false,
- Swiff : false,
- Tips : false,
- Type : false,
- typeOf : false,
- URI : false,
- Window : false
- },
-
- nexttoken,
-
- node = {
- __filename : false,
- __dirname : false,
- exports : false,
- Buffer : false,
- GLOBAL : false,
- global : false,
- module : false,
- process : false,
- require : false
- },
-
- noreach,
- option,
- predefined, // Global variables defined by option
- prereg,
- prevtoken,
-
- prototypejs = {
- '$' : false,
- '$$' : false,
- '$A' : false,
- '$F' : false,
- '$H' : false,
- '$R' : false,
- '$break' : false,
- '$continue' : false,
- '$w' : false,
- Abstract : false,
- Ajax : false,
- Class : false,
- Enumerable : false,
- Element : false,
- Event : false,
- Field : false,
- Form : false,
- Hash : false,
- Insertion : false,
- ObjectRange : false,
- PeriodicalExecuter: false,
- Position : false,
- Prototype : false,
- Selector : false,
- Template : false,
- Toggle : false,
- Try : false,
- Autocompleter : false,
- Builder : false,
- Control : false,
- Draggable : false,
- Draggables : false,
- Droppables : false,
- Effect : false,
- Sortable : false,
- SortableObserver : false,
- Sound : false,
- Scriptaculous : false
- },
-
- rhino = {
- defineClass : false,
- deserialize : false,
- gc : false,
- help : false,
- load : false,
- loadClass : false,
- print : false,
- quit : false,
- readFile : false,
- readUrl : false,
- runCommand : false,
- seal : false,
- serialize : false,
- spawn : false,
- sync : false,
- toint32 : false,
- version : false
- },
-
- scope, // The current scope
- src,
- stack,
-
-// standard contains the global names that are provided by the
-// ECMAScript standard.
-
- standard = {
- Array : false,
- Boolean : false,
- Date : false,
- decodeURI : false,
- decodeURIComponent : false,
- encodeURI : false,
- encodeURIComponent : false,
- Error : false,
- 'eval' : false,
- EvalError : false,
- Function : false,
- hasOwnProperty : false,
- isFinite : false,
- isNaN : false,
- JSON : false,
- Math : false,
- Number : false,
- Object : false,
- parseInt : false,
- parseFloat : false,
- RangeError : false,
- ReferenceError : false,
- RegExp : false,
- String : false,
- SyntaxError : false,
- TypeError : false,
- URIError : false
- },
-
- standard_member = {
- E : true,
- LN2 : true,
- LN10 : true,
- LOG2E : true,
- LOG10E : true,
- MAX_VALUE : true,
- MIN_VALUE : true,
- NEGATIVE_INFINITY : true,
- PI : true,
- POSITIVE_INFINITY : true,
- SQRT1_2 : true,
- SQRT2 : true
- },
-
- strict_mode,
- syntax = {},
- tab,
- token,
- urls,
- warnings,
-
- wsh = {
- ActiveXObject : true,
- Enumerator : true,
- GetObject : true,
- ScriptEngine : true,
- ScriptEngineBuildVersion : true,
- ScriptEngineMajorVersion : true,
- ScriptEngineMinorVersion : true,
- VBArray : true,
- WSH : true,
- WScript : true
- };
-
- // Regular expressions. Some of these are stupidly long.
- var ax, cx, tx, nx, nxg, lx, ix, jx, ft;
- (function () {
- /*jshint maxlen:300 */
-
- // unsafe comment or string
- ax = /@cc|<\/?|script|\]\s*\]|<\s*!|&lt/i;
-
- // unsafe characters that are silently deleted by one or more browsers
- cx = /[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/;
-
- // token
- tx = /^\s*([(){}\[.,:;'"~\?\]#@]|==?=?|\/(\*(jshint|jslint|members?|global)?|=|\/)?|\*[\/=]?|\+(?:=|\++)?|-(?:=|-+)?|%=?|&[&=]?|\|[|=]?|>>?>?=?|<([\/=!]|\!(\[|--)?|<=?)?|\^=?|\!=?=?|[a-zA-Z_$][a-zA-Z0-9_$]*|[0-9]+([xX][0-9a-fA-F]+|\.[0-9]*)?([eE][+\-]?[0-9]+)?)/;
-
- // characters in strings that need escapement
- nx = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/;
- nxg = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
-
- // star slash
- lx = /\*\/|\/\*/;
-
- // identifier
- ix = /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/;
-
- // javascript url
- jx = /^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i;
-
- // catches /* falls through */ comments
- ft = /^\s*\/\*\s*falls\sthrough\s*\*\/\s*$/;
- }());
-
- function F() {} // Used by Object.create
-
- function is_own(object, name) {
-
-// The object.hasOwnProperty method fails when the property under consideration
-// is named 'hasOwnProperty'. So we have to use this more convoluted form.
-
- return Object.prototype.hasOwnProperty.call(object, name);
- }
-
-// Provide critical ES5 functions to ES3.
-
- if (typeof Array.isArray !== 'function') {
- Array.isArray = function (o) {
- return Object.prototype.toString.apply(o) === '[object Array]';
- };
- }
-
- if (typeof Object.create !== 'function') {
- Object.create = function (o) {
- F.prototype = o;
- return new F();
- };
- }
-
- if (typeof Object.keys !== 'function') {
- Object.keys = function (o) {
- var a = [], k;
- for (k in o) {
- if (is_own(o, k)) {
- a.push(k);
- }
- }
- return a;
- };
- }
-
-// Non standard methods
-
- if (typeof String.prototype.entityify !== 'function') {
- String.prototype.entityify = function () {
- return this
- .replace(/&/g, '&amp;')
- .replace(/</g, '&lt;')
- .replace(/>/g, '&gt;');
- };
- }
-
- if (typeof String.prototype.isAlpha !== 'function') {
- String.prototype.isAlpha = function () {
- return (this >= 'a' && this <= 'z\uffff') ||
- (this >= 'A' && this <= 'Z\uffff');
- };
- }
-
- if (typeof String.prototype.isDigit !== 'function') {
- String.prototype.isDigit = function () {
- return (this >= '0' && this <= '9');
- };
- }
-
- if (typeof String.prototype.supplant !== 'function') {
- String.prototype.supplant = function (o) {
- return this.replace(/\{([^{}]*)\}/g, function (a, b) {
- var r = o[b];
- return typeof r === 'string' || typeof r === 'number' ? r : a;
- });
- };
- }
-
- if (typeof String.prototype.name !== 'function') {
- String.prototype.name = function () {
-
-// If the string looks like an identifier, then we can return it as is.
-// If the string contains no control characters, no quote characters, and no
-// backslash characters, then we can simply slap some quotes around it.
-// Otherwise we must also replace the offending characters with safe
-// sequences.
-
- if (ix.test(this)) {
- return this;
- }
- if (nx.test(this)) {
- return '"' + this.replace(nxg, function (a) {
- var c = escapes[a];
- if (c) {
- return c;
- }
- return '\\u' + ('0000' + a.charCodeAt().toString(16)).slice(-4);
- }) + '"';
- }
- return '"' + this + '"';
- };
- }
-
-
- function combine(t, o) {
- var n;
- for (n in o) {
- if (is_own(o, n)) {
- t[n] = o[n];
- }
- }
- }
-
- function assume() {
- if (option.couch)
- combine(predefined, couch);
-
- if (option.rhino)
- combine(predefined, rhino);
-
- if (option.prototypejs)
- combine(predefined, prototypejs);
-
- if (option.node)
- combine(predefined, node);
-
- if (option.devel)
- combine(predefined, devel);
-
- if (option.dojo)
- combine(predefined, dojo);
-
- if (option.browser)
- combine(predefined, browser);
-
- if (option.jquery)
- combine(predefined, jquery);
-
- if (option.mootools)
- combine(predefined, mootools);
-
- if (option.wsh)
- combine(predefined, wsh);
-
- if (option.globalstrict && option.strict !== false)
- option.strict = true;
- }
-
-
-// Produce an error warning.
-
- function quit(message, line, chr) {
- var percentage = Math.floor((line / lines.length) * 100);
-
- throw {
- name: 'JSHintError',
- line: line,
- character: chr,
- message: message + " (" + percentage + "% scanned)."
- };
- }
-
- function warning(m, t, a, b, c, d) {
- var ch, l, w;
- t = t || nexttoken;
- if (t.id === '(end)') { // `~
- t = token;
- }
- l = t.line || 0;
- ch = t.from || 0;
- w = {
- id: '(error)',
- raw: m,
- evidence: lines[l - 1] || '',
- line: l,
- character: ch,
- a: a,
- b: b,
- c: c,
- d: d
- };
- w.reason = m.supplant(w);
- JSHINT.errors.push(w);
- if (option.passfail) {
- quit('Stopping. ', l, ch);
- }
- warnings += 1;
- if (warnings >= option.maxerr) {
- quit("Too many errors.", l, ch);
- }
- return w;
- }
-
- function warningAt(m, l, ch, a, b, c, d) {
- return warning(m, {
- line: l,
- from: ch
- }, a, b, c, d);
- }
-
- function error(m, t, a, b, c, d) {
- var w = warning(m, t, a, b, c, d);
- quit("Stopping, unable to continue.", w.line, w.character);
- }
- function errorAt(m, l, ch, a, b, c, d) {
- return error(m, {
- line: l,
- from: ch
- }, a, b, c, d);
- }
-
-
-
-// lexical analysis and token construction
-
- var lex = (function lex() {
- var character, from, line, s;
-
-// Private lex methods
-
- function nextLine() {
- var at,
- tw; // trailing whitespace check
-
- if (line >= lines.length)
- return false;
-
- character = 1;
- s = lines[line];
- line += 1;
- at = s.search(/ \t/);
-
- if (at >= 0)
- warningAt("Mixed spaces and tabs.", line, at + 1);
-
- s = s.replace(/\t/g, tab);
- at = s.search(cx);
-
- if (at >= 0)
- warningAt("Unsafe character.", line, at);
-
- if (option.maxlen && option.maxlen < s.length)
- warningAt("Line too long.", line, s.length);
-
- // Check for trailing whitespaces
- tw = s.search(/\s+$/);
- if (option.trailing && ~tw && !~s.search(/^\s+$/))
- warningAt("Trailing whitespace.", line, tw);
-
- return true;
- }
-
-// Produce a token object. The token inherits from a syntax symbol.
-
- function it(type, value) {
- var i, t;
- if (type === '(color)' || type === '(range)') {
- t = {type: type};
- } else if (type === '(punctuator)' ||
- (type === '(identifier)' && is_own(syntax, value))) {
- t = syntax[value] || syntax['(error)'];
- } else {
- t = syntax[type];
- }
- t = Object.create(t);
- if (type === '(string)' || type === '(range)') {
- if (!option.scripturl && jx.test(value)) {
- warningAt("Script URL.", line, from);
- }
- }
- if (type === '(identifier)') {
- t.identifier = true;
- if (value === '__proto__' && !option.proto) {
- warningAt("The '{a}' property is deprecated.",
- line, from, value);
- } else if (value === '__iterator__' && !option.iterator) {
- warningAt("'{a}' is only available in JavaScript 1.7.",
- line, from, value);
- } else if (option.nomen && (value.charAt(0) === '_' ||
- value.charAt(value.length - 1) === '_')) {
- warningAt("Unexpected {a} in '{b}'.", line, from,
- "dangling '_'", value);
- }
- }
- t.value = value;
- t.line = line;
- t.character = character;
- t.from = from;
- i = t.id;
- if (i !== '(endline)') {
- prereg = i &&
- (('(,=:[!&|?{};'.indexOf(i.charAt(i.length - 1)) >= 0) ||
- i === 'return');
- }
- return t;
- }
-
-// Public lex methods
-
- return {
- init: function (source) {
- if (typeof source === 'string') {
- lines = source
- .replace(/\r\n/g, '\n')
- .replace(/\r/g, '\n')
- .split('\n');
- } else {
- lines = source;
- }
-
- // If the first line is a shebang (#!), make it a blank and move on.
- // Shebangs are used by Node scripts.
- if (lines[0] && lines[0].substr(0, 2) == '#!')
- lines[0] = '';
-
- line = 0;
- nextLine();
- from = 1;
- },
-
- range: function (begin, end) {
- var c, value = '';
- from = character;
- if (s.charAt(0) !== begin) {
- errorAt("Expected '{a}' and instead saw '{b}'.",
- line, character, begin, s.charAt(0));
- }
- for (;;) {
- s = s.slice(1);
- character += 1;
- c = s.charAt(0);
- switch (c) {
- case '':
- errorAt("Missing '{a}'.", line, character, c);
- break;
- case end:
- s = s.slice(1);
- character += 1;
- return it('(range)', value);
- case '\\':
- warningAt("Unexpected '{a}'.", line, character, c);
- }
- value += c;
- }
-
- },
+exports.delayedCall = function(fcn, defaultTimeout) {
+ var timer = null;
+ var callback = function() {
+ timer = null;
+ fcn();
+ };
-// token -- this is called by advance to get the next token.
+ var _self = function(timeout) {
+ timer && clearTimeout(timer);
+ timer = setTimeout(callback, timeout || defaultTimeout);
+ };
- token: function () {
- var b, c, captures, d, depth, high, i, l, low, q, t;
+ _self.delay = _self;
+ _self.schedule = function(timeout) {
+ if (timer == null)
+ timer = setTimeout(callback, timeout || 0);
+ };
- function match(x) {
- var r = x.exec(s), r1;
- if (r) {
- l = r[0].length;
- r1 = r[1];
- c = r1.charAt(0);
- s = s.substr(l);
- from = character + l - r1.length;
- character += l;
- return r1;
- }
- }
+ _self.call = function() {
+ this.cancel();
+ fcn();
+ };
- function string(x) {
- var c, j, r = '';
+ _self.cancel = function() {
+ timer && clearTimeout(timer);
+ timer = null;
+ };
- if (jsonmode && x !== '"') {
- warningAt("Strings must use doublequote.",
- line, character);
- }
+ _self.isPending = function() {
+ return timer;
+ };
- function esc(n) {
- var i = parseInt(s.substr(j + 1, n), 16);
- j += n;
- if (i >= 32 && i <= 126 &&
- i !== 34 && i !== 92 && i !== 39) {
- warningAt("Unnecessary escapement.", line, character);
- }
- character += n;
- c = String.fromCharCode(i);
- }
- j = 0;
- for (;;) {
- while (j >= s.length) {
- j = 0;
- if (!nextLine()) {
- errorAt("Unclosed string.", line, from);
- }
- }
- c = s.charAt(j);
- if (c === x) {
- character += 1;
- s = s.substr(j + 1);
- return it('(string)', r, x);
- }
- if (c < ' ') {
- if (c === '\n' || c === '\r') {
- break;
- }
- warningAt("Control character in string: {a}.",
- line, character + j, s.slice(0, j));
- } else if (c === '\\') {
- j += 1;
- character += 1;
- c = s.charAt(j);
- switch (c) {
- case '\\':
- case '"':
- case '/':
- break;
- case '\'':
- if (jsonmode) {
- warningAt("Avoid \\'.", line, character);
- }
- break;
- case 'b':
- c = '\b';
- break;
- case 'f':
- c = '\f';
- break;
- case 'n':
- c = '\n';
- break;
- case 'r':
- c = '\r';
- break;
- case 't':
- c = '\t';
- break;
- case 'u':
- esc(4);
- break;
- case 'v':
- if (jsonmode) {
- warningAt("Avoid \\v.", line, character);
- }
- c = '\v';
- break;
- case 'x':
- if (jsonmode) {
- warningAt("Avoid \\x-.", line, character);
- }
- esc(2);
- break;
- default:
- warningAt("Bad escapement.", line, character);
- }
- }
- r += c;
- character += 1;
- j += 1;
- }
- }
+ return _self;
+};
+});
+define('ace/mode/javascript/jshint', ['require', 'exports', 'module' ], function(require, exports, module) {
- for (;;) {
- if (!s) {
- return it(nextLine() ? '(endline)' : '(end)', '');
- }
- t = match(tx);
- if (!t) {
- t = '';
- c = '';
- while (s && s < '!') {
- s = s.substr(1);
- }
- if (s) {
- errorAt("Unexpected '{a}'.", line, character, s.substr(0, 1));
- }
- } else {
-
- // identifier
-
- if (c.isAlpha() || c === '_' || c === '$') {
- return it('(identifier)', t);
- }
-
- // number
-
- if (c.isDigit()) {
- if (!isFinite(Number(t))) {
- warningAt("Bad number '{a}'.",
- line, character, t);
- }
- if (s.substr(0, 1).isAlpha()) {
- warningAt("Missing space after '{a}'.",
- line, character, t);
- }
- if (c === '0') {
- d = t.substr(1, 1);
- if (d.isDigit()) {
- if (token.id !== '.') {
- warningAt("Don't use extra leading zeros '{a}'.",
- line, character, t);
- }
- } else if (jsonmode && (d === 'x' || d === 'X')) {
- warningAt("Avoid 0x-. '{a}'.",
- line, character, t);
- }
- }
- if (t.substr(t.length - 1) === '.') {
- warningAt(
+var JSHINT = (function () {
+
+
+ var anonname, // The guessed name for anonymous functions.
+
+ bang = {
+ "<" : true,
+ "<=" : true,
+ "==" : true,
+ "===": true,
+ "!==": true,
+ "!=" : true,
+ ">" : true,
+ ">=" : true,
+ "+" : true,
+ "-" : true,
+ "*" : true,
+ "/" : true,
+ "%" : true
+ },
+ boolOptions = {
+ asi : true, // if automatic semicolon insertion should be tolerated
+ bitwise : true, // if bitwise operators should not be allowed
+ boss : true, // if advanced usage of assignments should be allowed
+ browser : true, // if the standard browser globals should be predefined
+ camelcase : true, // if identifiers should be required in camel case
+ couch : true, // if CouchDB globals should be predefined
+ curly : true, // if curly braces around all blocks should be required
+ debug : true, // if debugger statements should be allowed
+ devel : true, // if logging globals should be predefined (console,
+ dojo : true, // if Dojo Toolkit globals should be predefined
+ eqeqeq : true, // if === should be required
+ eqnull : true, // if == null comparisons should be tolerated
+ es5 : true, // if ES5 syntax should be allowed
+ esnext : true, // if es.next specific syntax should be allowed
+ evil : true, // if eval should be allowed
+ expr : true, // if ExpressionStatement should be allowed as Programs
+ forin : true, // if for in statements must filter
+ funcscope : true, // if only function scope should be used for scope tests
+ globalstrict: true, // if global should be allowed (also
+ immed : true, // if immediate invocations must be wrapped in parens
+ iterator : true, // if the `__iterator__` property should be allowed
+ jquery : true, // if jQuery globals should be predefined
+ lastsemic : true, // if semicolons may be ommitted for the trailing
+ latedef : true, // if the use before definition should not be tolerated
+ laxbreak : true, // if line breaks should not be checked
+ laxcomma : true, // if line breaks should not be checked around commas
+ loopfunc : true, // if functions should be allowed to be defined within
+ mootools : true, // if MooTools globals should be predefined
+ multistr : true, // allow multiline strings
+ newcap : true, // if constructor names must be capitalized
+ noarg : true, // if arguments.caller and arguments.callee should be
+ node : true, // if the Node.js environment globals should be
+ noempty : true, // if empty blocks should be disallowed
+ nonew : true, // if using `new` for side-effects should be disallowed
+ nonstandard : true, // if non-standard (but widely adopted) globals should
+ nomen : true, // if names should be checked
+ onevar : true, // if only one var statement per function should be
+ onecase : true, // if one case switch statements should be allowed
+ passfail : true, // if the scan should stop on first error
+ plusplus : true, // if increment/decrement should not be allowed
+ proto : true, // if the `__proto__` property should be allowed
+ prototypejs : true, // if Prototype and Scriptaculous globals should be
+ regexdash : true, // if unescaped first/last dash (-) inside brackets
+ regexp : true, // if the . should not be allowed in regexp literals
+ rhino : true, // if the Rhino environment globals should be predefined
+ undef : true, // if variables should be declared before used
+ unused : true, // if variables should be always used
+ scripturl : true, // if script-targeted URLs should be tolerated
+ shadow : true, // if variable shadowing should be tolerated
+ smarttabs : true, // if smarttabs should be tolerated
+ strict : true, // require the pragma
+ sub : true, // if all forms of subscript notation are tolerated
+ supernew : true, // if `new function () { ... };` and `new Object;`
+ trailing : true, // if trailing whitespace rules apply
+ validthis : true, // if 'this' inside a non-constructor function is valid.
+ withstmt : true, // if with statements should be allowed
+ white : true, // if strict whitespace rules apply
+ worker : true, // if Web Worker script symbols should be allowed
+ wsh : true, // if the Windows Scripting Host environment globals
+ yui : true // YUI variables should be predefined
+ },
+ valOptions = {
+ maxlen : false,
+ indent : false,
+ maxerr : false,
+ predef : false,
+ quotmark : false, //'single'|'double'|true
+ scope : false,
+ maxstatements: false, // {int} max statements per function
+ maxdepth : false, // {int} max nested block depth per function
+ maxparams : false, // {int} max params per function
+ maxcomplexity: false // {int} max cyclomatic complexity per function
+ },
+ invertedOptions = {
+ bitwise : true,
+ forin : true,
+ newcap : true,
+ nomen : true,
+ plusplus : true,
+ regexp : true,
+ undef : true,
+ white : true,
+ eqeqeq : true,
+ onevar : true
+ },
+ renamedOptions = {
+ eqeq : "eqeqeq",
+ vars : "onevar",
+ windows : "wsh"
+ },
+ browser = {
+ ArrayBuffer : false,
+ ArrayBufferView : false,
+ Audio : false,
+ Blob : false,
+ addEventListener : false,
+ applicationCache : false,
+ atob : false,
+ blur : false,
+ btoa : false,
+ clearInterval : false,
+ clearTimeout : false,
+ close : false,
+ closed : false,
+ DataView : false,
+ DOMParser : false,
+ defaultStatus : false,
+ document : false,
+ event : false,
+ FileReader : false,
+ Float32Array : false,
+ Float64Array : false,
+ FormData : false,
+ focus : false,
+ frames : false,
+ getComputedStyle : false,
+ HTMLElement : false,
+ HTMLAnchorElement : false,
+ HTMLBaseElement : false,
+ HTMLBlockquoteElement : false,
+ HTMLBodyElement : false,
+ HTMLBRElement : false,
+ HTMLButtonElement : false,
+ HTMLCanvasElement : false,
+ HTMLDirectoryElement : false,
+ HTMLDivElement : false,
+ HTMLDListElement : false,
+ HTMLFieldSetElement : false,
+ HTMLFontElement : false,
+ HTMLFormElement : false,
+ HTMLFrameElement : false,
+ HTMLFrameSetElement : false,
+ HTMLHeadElement : false,
+ HTMLHeadingElement : false,
+ HTMLHRElement : false,
+ HTMLHtmlElement : false,
+ HTMLIFrameElement : false,
+ HTMLImageElement : false,
+ HTMLInputElement : false,
+ HTMLIsIndexElement : false,
+ HTMLLabelElement : false,
+ HTMLLayerElement : false,
+ HTMLLegendElement : false,
+ HTMLLIElement : false,
+ HTMLLinkElement : false,
+ HTMLMapElement : false,
+ HTMLMenuElement : false,
+ HTMLMetaElement : false,
+ HTMLModElement : false,
+ HTMLObjectElement : false,
+ HTMLOListElement : false,
+ HTMLOptGroupElement : false,
+ HTMLOptionElement : false,
+ HTMLParagraphElement : false,
+ HTMLParamElement : false,
+ HTMLPreElement : false,
+ HTMLQuoteElement : false,
+ HTMLScriptElement : false,
+ HTMLSelectElement : false,
+ HTMLStyleElement : false,
+ HTMLTableCaptionElement : false,
+ HTMLTableCellElement : false,
+ HTMLTableColElement : false,
+ HTMLTableElement : false,
+ HTMLTableRowElement : false,
+ HTMLTableSectionElement : false,
+ HTMLTextAreaElement : false,
+ HTMLTitleElement : false,
+ HTMLUListElement : false,
+ HTMLVideoElement : false,
+ history : false,
+ Int16Array : false,
+ Int32Array : false,
+ Int8Array : false,
+ Image : false,
+ length : false,
+ localStorage : false,
+ location : false,
+ MessageChannel : false,
+ MessageEvent : false,
+ MessagePort : false,
+ moveBy : false,
+ moveTo : false,
+ MutationObserver : false,
+ name : false,
+ Node : false,
+ NodeFilter : false,
+ navigator : false,
+ onbeforeunload : true,
+ onblur : true,
+ onerror : true,
+ onfocus : true,
+ onload : true,
+ onresize : true,
+ onunload : true,
+ open : false,
+ openDatabase : false,
+ opener : false,
+ Option : false,
+ parent : false,
+ print : false,
+ removeEventListener : false,
+ resizeBy : false,
+ resizeTo : false,
+ screen : false,
+ scroll : false,
+ scrollBy : false,
+ scrollTo : false,
+ sessionStorage : false,
+ setInterval : false,
+ setTimeout : false,
+ SharedWorker : false,
+ status : false,
+ top : false,
+ Uint16Array : false,
+ Uint32Array : false,
+ Uint8Array : false,
+ WebSocket : false,
+ window : false,
+ Worker : false,
+ XMLHttpRequest : false,
+ XMLSerializer : false,
+ XPathEvaluator : false,
+ XPathException : false,
+ XPathExpression : false,
+ XPathNamespace : false,
+ XPathNSResolver : false,
+ XPathResult : false
+ },
+
+ couch = {
+ "require" : false,
+ respond : false,
+ getRow : false,
+ emit : false,
+ send : false,
+ start : false,
+ sum : false,
+ log : false,
+ exports : false,
+ module : false,
+ provides : false
+ },
+
+ declared, // Globals that were declared using /*global ... */ syntax.
+
+ devel = {
+ alert : false,
+ confirm : false,
+ console : false,
+ Debug : false,
+ opera : false,
+ prompt : false
+ },
+
+ dojo = {
+ dojo : false,
+ dijit : false,
+ dojox : false,
+ define : false,
+ "require" : false
+ },
+
+ funct, // The current function
+
+ functionicity = [
+ "closure", "exception", "global", "label",
+ "outer", "unused", "var"
+ ],
+
+ functions, // All of the functions
+
+ global, // The global scope
+ implied, // Implied globals
+ inblock,
+ indent,
+ jsonmode,
+
+ jquery = {
+ "$" : false,
+ jQuery : false
+ },
+
+ lines,
+ lookahead,
+ member,
+ membersOnly,
+
+ mootools = {
+ "$" : false,
+ "$$" : false,
+ Asset : false,
+ Browser : false,
+ Chain : false,
+ Class : false,
+ Color : false,
+ Cookie : false,
+ Core : false,
+ Document : false,
+ DomReady : false,
+ DOMEvent : false,
+ DOMReady : false,
+ Drag : false,
+ Element : false,
+ Elements : false,
+ Event : false,
+ Events : false,
+ Fx : false,
+ Group : false,
+ Hash : false,
+ HtmlTable : false,
+ Iframe : false,
+ IframeShim : false,
+ InputValidator : false,
+ instanceOf : false,
+ Keyboard : false,
+ Locale : false,
+ Mask : false,
+ MooTools : false,
+ Native : false,
+ Options : false,
+ OverText : false,
+ Request : false,
+ Scroller : false,
+ Slick : false,
+ Slider : false,
+ Sortables : false,
+ Spinner : false,
+ Swiff : false,
+ Tips : false,
+ Type : false,
+ typeOf : false,
+ URI : false,
+ Window : false
+ },
+
+ nexttoken,
+
+ node = {
+ __filename : false,
+ __dirname : false,
+ Buffer : false,
+ console : false,
+ exports : true, // In Node it is ok to exports = module.exports = foo();
+ GLOBAL : false,
+ global : false,
+ module : false,
+ process : false,
+ require : false,
+ setTimeout : false,
+ clearTimeout : false,
+ setInterval : false,
+ clearInterval : false
+ },
+
+ noreach,
+ option,
+ predefined, // Global variables defined by option
+ prereg,
+ prevtoken,
+
+ prototypejs = {
+ "$" : false,
+ "$$" : false,
+ "$A" : false,
+ "$F" : false,
+ "$H" : false,
+ "$R" : false,
+ "$break" : false,
+ "$continue" : false,
+ "$w" : false,
+ Abstract : false,
+ Ajax : false,
+ Class : false,
+ Enumerable : false,
+ Element : false,
+ Event : false,
+ Field : false,
+ Form : false,
+ Hash : false,
+ Insertion : false,
+ ObjectRange : false,
+ PeriodicalExecuter: false,
+ Position : false,
+ Prototype : false,
+ Selector : false,
+ Template : false,
+ Toggle : false,
+ Try : false,
+ Autocompleter : false,
+ Builder : false,
+ Control : false,
+ Draggable : false,
+ Draggables : false,
+ Droppables : false,
+ Effect : false,
+ Sortable : false,
+ SortableObserver : false,
+ Sound : false,
+ Scriptaculous : false
+ },
+
+ quotmark,
+
+ rhino = {
+ defineClass : false,
+ deserialize : false,
+ gc : false,
+ help : false,
+ importPackage: false,
+ "java" : false,
+ load : false,
+ loadClass : false,
+ print : false,
+ quit : false,
+ readFile : false,
+ readUrl : false,
+ runCommand : false,
+ seal : false,
+ serialize : false,
+ spawn : false,
+ sync : false,
+ toint32 : false,
+ version : false
+ },
+
+ scope, // The current scope
+ stack,
+ standard = {
+ Array : false,
+ Boolean : false,
+ Date : false,
+ decodeURI : false,
+ decodeURIComponent : false,
+ encodeURI : false,
+ encodeURIComponent : false,
+ Error : false,
+ "eval" : false,
+ EvalError : false,
+ Function : false,
+ hasOwnProperty : false,
+ isFinite : false,
+ isNaN : false,
+ JSON : false,
+ Map : false,
+ Math : false,
+ NaN : false,
+ Number : false,
+ Object : false,
+ parseInt : false,
+ parseFloat : false,
+ RangeError : false,
+ ReferenceError : false,
+ RegExp : false,
+ Set : false,
+ String : false,
+ SyntaxError : false,
+ TypeError : false,
+ URIError : false,
+ WeakMap : false
+ },
+ nonstandard = {
+ escape : false,
+ unescape : false
+ },
+
+ directive,
+ syntax = {},
+ tab,
+ token,
+ unuseds,
+ urls,
+ useESNextSyntax,
+ warnings,
+
+ worker = {
+ importScripts : true,
+ postMessage : true,
+ self : true
+ },
+
+ wsh = {
+ ActiveXObject : true,
+ Enumerator : true,
+ GetObject : true,
+ ScriptEngine : true,
+ ScriptEngineBuildVersion : true,
+ ScriptEngineMajorVersion : true,
+ ScriptEngineMinorVersion : true,
+ VBArray : true,
+ WSH : true,
+ WScript : true,
+ XDomainRequest : true
+ },
+
+ yui = {
+ YUI : false,
+ Y : false,
+ YUI_config : false
+ };
+ var ax, cx, tx, nx, nxg, lx, ix, jx, ft;
+ (function () {
+ ax = /@cc|<\/?|script|\]\s*\]|<\s*!|&lt/i;
+ cx = /[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/;
+ tx = /^\s*([(){}\[.,:;'"~\?\]#@]|==?=?|\/=(?!(\S*\/[gim]?))|\/(\*(jshint|jslint|members?|global)?|\/)?|\*[\/=]?|\+(?:=|\++)?|-(?:=|-+)?|%=?|&[&=]?|\|[|=]?|>>?>?=?|<([\/=!]|\!(\[|--)?|<=?)?|\^=?|\!=?=?|[a-zA-Z_$][a-zA-Z0-9_$]*|[0-9]+([xX][0-9a-fA-F]+|\.[0-9]*)?([eE][+\-]?[0-9]+)?)/;
+ nx = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/;
+ nxg = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
+ lx = /\*\//;
+ ix = /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/;
+ jx = /^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i;
+ ft = /^\s*\/\*\s*falls\sthrough\s*\*\/\s*$/;
+ }());
+
+ function F() {} // Used by Object.create
+
+ function is_own(object, name) {
+ return Object.prototype.hasOwnProperty.call(object, name);
+ }
+
+ function checkOption(name, t) {
+ if (valOptions[name] === undefined && boolOptions[name] === undefined) {
+ warning("Bad option: '" + name + "'.", t);
+ }
+ }
+
+ function isString(obj) {
+ return Object.prototype.toString.call(obj) === "[object String]";
+ }
+
+ if (typeof Array.isArray !== "function") {
+ Array.isArray = function (o) {
+ return Object.prototype.toString.apply(o) === "[object Array]";
+ };
+ }
+
+ if (!Array.prototype.forEach) {
+ Array.prototype.forEach = function (fn, scope) {
+ var len = this.length;
+
+ for (var i = 0; i < len; i++) {
+ fn.call(scope || this, this[i], i, this);
+ }
+ };
+ }
+
+ if (!Array.prototype.indexOf) {
+ Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
+ if (this === null || this === undefined) {
+ throw new TypeError();
+ }
+
+ var t = new Object(this);
+ var len = t.length >>> 0;
+
+ if (len === 0) {
+ return -1;
+ }
+
+ var n = 0;
+ if (arguments.length > 0) {
+ n = Number(arguments[1]);
+ if (n != n) { // shortcut for verifying if it's NaN
+ n = 0;
+ } else if (n !== 0 && n != Infinity && n != -Infinity) {
+ n = (n > 0 || -1) * Math.floor(Math.abs(n));
+ }
+ }
+
+ if (n >= len) {
+ return -1;
+ }
+
+ var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
+ for (; k < len; k++) {
+ if (k in t && t[k] === searchElement) {
+ return k;
+ }
+ }
+
+ return -1;
+ };
+ }
+
+ if (typeof Object.create !== "function") {
+ Object.create = function (o) {
+ F.prototype = o;
+ return new F();
+ };
+ }
+
+ if (typeof Object.keys !== "function") {
+ Object.keys = function (o) {
+ var a = [], k;
+ for (k in o) {
+ if (is_own(o, k)) {
+ a.push(k);
+ }
+ }
+ return a;
+ };
+ }
+
+ function isAlpha(str) {
+ return (str >= "a" && str <= "z\uffff") ||
+ (str >= "A" && str <= "Z\uffff");
+ }
+
+ function isDigit(str) {
+ return (str >= "0" && str <= "9");
+ }
+
+ function isIdentifier(token, value) {
+ if (!token)
+ return false;
+
+ if (!token.identifier || token.value !== value)
+ return false;
+
+ return true;
+ }
+
+ function supplant(str, data) {
+ return str.replace(/\{([^{}]*)\}/g, function (a, b) {
+ var r = data[b];
+ return typeof r === "string" || typeof r === "number" ? r : a;
+ });
+ }
+
+ function combine(t, o) {
+ var n;
+ for (n in o) {
+ if (is_own(o, n) && !is_own(JSHINT.blacklist, n)) {
+ t[n] = o[n];
+ }
+ }
+ }
+
+ function updatePredefined() {
+ Object.keys(JSHINT.blacklist).forEach(function (key) {
+ delete predefined[key];
+ });
+ }
+
+ function assume() {
+ if (option.couch) {
+ combine(predefined, couch);
+ }
+
+ if (option.rhino) {
+ combine(predefined, rhino);
+ }
+
+ if (option.prototypejs) {
+ combine(predefined, prototypejs);
+ }
+
+ if (option.node) {
+ combine(predefined, node);
+ option.globalstrict = true;
+ }
+
+ if (option.devel) {
+ combine(predefined, devel);
+ }
+
+ if (option.dojo) {
+ combine(predefined, dojo);
+ }
+
+ if (option.browser) {
+ combine(predefined, browser);
+ }
+
+ if (option.nonstandard) {
+ combine(predefined, nonstandard);
+ }
+
+ if (option.jquery) {
+ combine(predefined, jquery);
+ }
+
+ if (option.mootools) {
+ combine(predefined, mootools);
+ }
+
+ if (option.worker) {
+ combine(predefined, worker);
+ }
+
+ if (option.wsh) {
+ combine(predefined, wsh);
+ }
+
+ if (option.esnext) {
+ useESNextSyntax();
+ }
+
+ if (option.globalstrict && option.strict !== false) {
+ option.strict = true;
+ }
+
+ if (option.yui) {
+ combine(predefined, yui);
+ }
+ }
+ function quit(message, line, chr) {
+ var percentage = Math.floor((line / lines.length) * 100);
+
+ throw {
+ name: "JSHintError",
+ line: line,
+ character: chr,
+ message: message + " (" + percentage + "% scanned).",
+ raw: message
+ };
+ }
+
+ function isundef(scope, m, t, a) {
+ return JSHINT.undefs.push([scope, m, t, a]);
+ }
+
+ function warning(m, t, a, b, c, d) {
+ var ch, l, w;
+ t = t || nexttoken;
+ if (t.id === "(end)") { // `~
+ t = token;
+ }
+ l = t.line || 0;
+ ch = t.from || 0;
+ w = {
+ id: "(error)",
+ raw: m,
+ evidence: lines[l - 1] || "",
+ line: l,
+ character: ch,
+ scope: JSHINT.scope,
+ a: a,
+ b: b,
+ c: c,
+ d: d
+ };
+ w.reason = supplant(m, w);
+ JSHINT.errors.push(w);
+ if (option.passfail) {
+ quit("Stopping. ", l, ch);
+ }
+ warnings += 1;
+ if (warnings >= option.maxerr) {
+ quit("Too many errors.", l, ch);
+ }
+ return w;
+ }
+
+ function warningAt(m, l, ch, a, b, c, d) {
+ return warning(m, {
+ line: l,
+ from: ch
+ }, a, b, c, d);
+ }
+
+ function error(m, t, a, b, c, d) {
+ warning(m, t, a, b, c, d);
+ }
+
+ function errorAt(m, l, ch, a, b, c, d) {
+ return error(m, {
+ line: l,
+ from: ch
+ }, a, b, c, d);
+ }
+ function addInternalSrc(elem, src) {
+ var i;
+ i = {
+ id: "(internal)",
+ elem: elem,
+ value: src
+ };
+ JSHINT.internals.push(i);
+ return i;
+ }
+
+ var lex = (function lex() {
+ var character, from, line, s;
+
+ function nextLine() {
+ var at,
+ match,
+ tw; // trailing whitespace check
+
+ if (line >= lines.length)
+ return false;
+
+ character = 1;
+ s = lines[line];
+ line += 1;
+ if (option.smarttabs) {
+ match = s.match(/(\/\/)? \t/);
+ at = match && !match[1] ? 0 : -1;
+ } else {
+ at = s.search(/ \t|\t [^\*]/);
+ }
+
+ if (at >= 0)
+ warningAt("Mixed spaces and tabs.", line, at + 1);
+
+ s = s.replace(/\t/g, tab);
+ at = s.search(cx);
+
+ if (at >= 0)
+ warningAt("Unsafe character.", line, at);
+
+ if (option.maxlen && option.maxlen < s.length)
+ warningAt("Line too long.", line, s.length);
+ tw = option.trailing && s.match(/^(.*?)\s+$/);
+ if (tw && !/^\s+$/.test(s)) {
+ warningAt("Trailing whitespace.", line, tw[1].length + 1);
+ }
+ return true;
+ }
+
+ function it(type, value) {
+ var i, t;
+
+ function checkName(name) {
+ if (!option.proto && name === "__proto__") {
+ warningAt("The '{a}' property is deprecated.", line, from, name);
+ return;
+ }
+
+ if (!option.iterator && name === "__iterator__") {
+ warningAt("'{a}' is only available in JavaScript 1.7.", line, from, name);
+ return;
+ }
+
+ var hasDangling = /^(_+.*|.*_+)$/.test(name);
+
+ if (option.nomen && hasDangling && name !== "_") {
+ if (option.node && token.id !== "." && /^(__dirname|__filename)$/.test(name))
+ return;
+
+ warningAt("Unexpected {a} in '{b}'.", line, from, "dangling '_'", name);
+ return;
+ }
+
+ if (option.camelcase) {
+ if (name.replace(/^_+/, "").indexOf("_") > -1 && !name.match(/^[A-Z0-9_]*$/)) {
+ warningAt("Identifier '{a}' is not in camel case.", line, from, value);
+ }
+ }
+ }
+
+ if (type === "(color)" || type === "(range)") {
+ t = {type: type};
+ } else if (type === "(punctuator)" ||
+ (type === "(identifier)" && is_own(syntax, value))) {
+ t = syntax[value] || syntax["(error)"];
+ } else {
+ t = syntax[type];
+ }
+
+ t = Object.create(t);
+
+ if (type === "(string)" || type === "(range)") {
+ if (!option.scripturl && jx.test(value)) {
+ warningAt("Script URL.", line, from);
+ }
+ }
+
+ if (type === "(identifier)") {
+ t.identifier = true;
+ checkName(value);
+ }
+
+ t.value = value;
+ t.line = line;
+ t.character = character;
+ t.from = from;
+ i = t.id;
+ if (i !== "(endline)") {
+ prereg = i &&
+ (("(,=:[!&|?{};".indexOf(i.charAt(i.length - 1)) >= 0) ||
+ i === "return" ||
+ i === "case");
+ }
+ return t;
+ }
+ return {
+ init: function (source) {
+ if (typeof source === "string") {
+ lines = source
+ .replace(/\r\n/g, "\n")
+ .replace(/\r/g, "\n")
+ .split("\n");
+ } else {
+ lines = source;
+ }
+ if (lines[0] && lines[0].substr(0, 2) === "#!")
+ lines[0] = "";
+
+ line = 0;
+ nextLine();
+ from = 1;
+ },
+
+ range: function (begin, end) {
+ var c, value = "";
+ from = character;
+ if (s.charAt(0) !== begin) {
+ errorAt("Expected '{a}' and instead saw '{b}'.",
+ line, character, begin, s.charAt(0));
+ }
+ for (;;) {
+ s = s.slice(1);
+ character += 1;
+ c = s.charAt(0);
+ switch (c) {
+ case "":
+ errorAt("Missing '{a}'.", line, character, c);
+ break;
+ case end:
+ s = s.slice(1);
+ character += 1;
+ return it("(range)", value);
+ case "\\":
+ warningAt("Unexpected '{a}'.", line, character, c);
+ }
+ value += c;
+ }
+
+ },
+ token: function () {
+ var b, c, captures, d, depth, high, i, l, low, q, t, isLiteral, isInRange, n;
+
+ function match(x) {
+ var r = x.exec(s), r1;
+
+ if (r) {
+ l = r[0].length;
+ r1 = r[1];
+ c = r1.charAt(0);
+ s = s.substr(l);
+ from = character + l - r1.length;
+ character += l;
+ return r1;
+ }
+ }
+
+ function string(x) {
+ var c, j, r = "", allowNewLine = false;
+
+ if (jsonmode && x !== "\"") {
+ warningAt("Strings must use doublequote.",
+ line, character);
+ }
+
+ if (option.quotmark) {
+ if (option.quotmark === "single" && x !== "'") {
+ warningAt("Strings must use singlequote.",
+ line, character);
+ } else if (option.quotmark === "double" && x !== "\"") {
+ warningAt("Strings must use doublequote.",
+ line, character);
+ } else if (option.quotmark === true) {
+ quotmark = quotmark || x;
+ if (quotmark !== x) {
+ warningAt("Mixed double and single quotes.",
+ line, character);
+ }
+ }
+ }
+
+ function esc(n) {
+ var i = parseInt(s.substr(j + 1, n), 16);
+ j += n;
+ if (i >= 32 && i <= 126 &&
+ i !== 34 && i !== 92 && i !== 39) {
+ warningAt("Unnecessary escapement.", line, character);
+ }
+ character += n;
+ c = String.fromCharCode(i);
+ }
+
+ j = 0;
+
+unclosedString:
+ for (;;) {
+ while (j >= s.length) {
+ j = 0;
+
+ var cl = line, cf = from;
+ if (!nextLine()) {
+ errorAt("Unclosed string.", cl, cf);
+ break unclosedString;
+ }
+
+ if (allowNewLine) {
+ allowNewLine = false;
+ } else {
+ warningAt("Unclosed string.", cl, cf);
+ }
+ }
+
+ c = s.charAt(j);
+ if (c === x) {
+ character += 1;
+ s = s.substr(j + 1);
+ return it("(string)", r, x);
+ }
+
+ if (c < " ") {
+ if (c === "\n" || c === "\r") {
+ break;
+ }
+ warningAt("Control character in string: {a}.",
+ line, character + j, s.slice(0, j));
+ } else if (c === "\\") {
+ j += 1;
+ character += 1;
+ c = s.charAt(j);
+ n = s.charAt(j + 1);
+ switch (c) {
+ case "\\":
+ case "\"":
+ case "/":
+ break;
+ case "\'":
+ if (jsonmode) {
+ warningAt("Avoid \\'.", line, character);
+ }
+ break;
+ case "b":
+ c = "\b";
+ break;
+ case "f":
+ c = "\f";
+ break;
+ case "n":
+ c = "\n";
+ break;
+ case "r":
+ c = "\r";
+ break;
+ case "t":
+ c = "\t";
+ break;
+ case "0":
+ c = "\0";
+ if (n >= 0 && n <= 7 && directive["use strict"]) {
+ warningAt(
+ "Octal literals are not allowed in strict mode.",
+ line, character);
+ }
+ break;
+ case "u":
+ esc(4);
+ break;
+ case "v":
+ if (jsonmode) {
+ warningAt("Avoid \\v.", line, character);
+ }
+ c = "\v";
+ break;
+ case "x":
+ if (jsonmode) {
+ warningAt("Avoid \\x-.", line, character);
+ }
+ esc(2);
+ break;
+ case "":
+ allowNewLine = true;
+ if (option.multistr) {
+ if (jsonmode) {
+ warningAt("Avoid EOL escapement.", line, character);
+ }
+ c = "";
+ character -= 1;
+ break;
+ }
+ warningAt("Bad escapement of EOL. Use option multistr if needed.",
+ line, character);
+ break;
+ case "!":
+ if (s.charAt(j - 2) === "<")
+ break;
+ default:
+ warningAt("Bad escapement.", line, character);
+ }
+ }
+ r += c;
+ character += 1;
+ j += 1;
+ }
+ }
+
+ for (;;) {
+ if (!s) {
+ return it(nextLine() ? "(endline)" : "(end)", "");
+ }
+
+ t = match(tx);
+
+ if (!t) {
+ t = "";
+ c = "";
+ while (s && s < "!") {
+ s = s.substr(1);
+ }
+ if (s) {
+ errorAt("Unexpected '{a}'.", line, character, s.substr(0, 1));
+ s = "";
+ }
+ } else {
+
+ if (isAlpha(c) || c === "_" || c === "$") {
+ return it("(identifier)", t);
+ }
+
+ if (isDigit(c)) {
+ if (!isFinite(Number(t))) {
+ warningAt("Bad number '{a}'.",
+ line, character, t);
+ }
+ if (isAlpha(s.substr(0, 1))) {
+ warningAt("Missing space after '{a}'.",
+ line, character, t);
+ }
+ if (c === "0") {
+ d = t.substr(1, 1);
+ if (isDigit(d)) {
+ if (token.id !== ".") {
+ warningAt("Don't use extra leading zeros '{a}'.",
+ line, character, t);
+ }
+ } else if (jsonmode && (d === "x" || d === "X")) {
+ warningAt("Avoid 0x-. '{a}'.",
+ line, character, t);
+ }
+ }
+ if (t.substr(t.length - 1) === ".") {
+ warningAt(
"A trailing decimal point can be confused with a dot '{a}'.", line, character, t);
- }
- return it('(number)', t);
- }
- switch (t) {
-
- // string
-
- case '"':
- case "'":
- return string(t);
-
- // // comment
-
- case '//':
- if (src) {
- warningAt("Unexpected comment.", line, character);
- }
- s = '';
- token.comment = true;
- break;
-
- // /* comment
-
- case '/*':
- if (src) {
- warningAt("Unexpected comment.", line, character);
- }
- for (;;) {
- i = s.search(lx);
- if (i >= 0) {
- break;
- }
- if (!nextLine()) {
- errorAt("Unclosed comment.", line, character);
- }
- }
- character += i + 2;
- if (s.substr(i, 1) === '/') {
- errorAt("Nested comment.", line, character);
- }
- s = s.substr(i + 2);
- token.comment = true;
- break;
-
- // /*members /*jshint /*global
-
- case '/*members':
- case '/*member':
- case '/*jshint':
- case '/*jslint':
- case '/*global':
- case '*/':
- return {
- value: t,
- type: 'special',
- line: line,
- character: character,
- from: from
- };
-
- case '':
- break;
- // /
- case '/':
- if (token.id === '/=') {
- errorAt(
-"A regular expression literal can be confused with '/='.", line, from);
- }
- if (prereg) {
- depth = 0;
- captures = 0;
- l = 0;
- for (;;) {
- b = true;
- c = s.charAt(l);
- l += 1;
- switch (c) {
- case '':
- errorAt("Unclosed regular expression.",
- line, from);
- return;
- case '/':
- if (depth > 0) {
- warningAt("Unescaped '{a}'.",
- line, from + l, '/');
- }
- c = s.substr(0, l - 1);
- q = {
- g: true,
- i: true,
- m: true
- };
- while (q[s.charAt(l)] === true) {
- q[s.charAt(l)] = false;
- l += 1;
- }
- character += l;
- s = s.substr(l);
- q = s.charAt(0);
- if (q === '/' || q === '*') {
- errorAt("Confusing regular expression.",
- line, from);
- }
- return it('(regexp)', c);
- case '\\':
- c = s.charAt(l);
- if (c < ' ') {
- warningAt(
+ }
+ return it("(number)", t);
+ }
+ switch (t) {
+
+ case "\"":
+ case "'":
+ return string(t);
+
+ case "//":
+ s = "";
+ token.comment = true;
+ break;
+
+ case "/*":
+ for (;;) {
+ i = s.search(lx);
+ if (i >= 0) {
+ break;
+ }
+ if (!nextLine()) {
+ errorAt("Unclosed comment.", line, character);
+ }
+ }
+ s = s.substr(i + 2);
+ token.comment = true;
+ break;
+
+ case "/*members":
+ case "/*member":
+ case "/*jshint":
+ case "/*jslint":
+ case "/*global":
+ case "*/":
+ return {
+ value: t,
+ type: "special",
+ line: line,
+ character: character,
+ from: from
+ };
+
+ case "":
+ break;
+ case "/":
+ if (s.charAt(0) === "=") {
+ errorAt("A regular expression literal can be confused with '/='.",
+ line, from);
+ }
+
+ if (prereg) {
+ depth = 0;
+ captures = 0;
+ l = 0;
+ for (;;) {
+ b = true;
+ c = s.charAt(l);
+ l += 1;
+ switch (c) {
+ case "":
+ errorAt("Unclosed regular expression.", line, from);
+ return quit("Stopping.", line, from);
+ case "/":
+ if (depth > 0) {
+ warningAt("{a} unterminated regular expression " +
+ "group(s).", line, from + l, depth);
+ }
+ c = s.substr(0, l - 1);
+ q = {
+ g: true,
+ i: true,
+ m: true
+ };
+ while (q[s.charAt(l)] === true) {
+ q[s.charAt(l)] = false;
+ l += 1;
+ }
+ character += l;
+ s = s.substr(l);
+ q = s.charAt(0);
+ if (q === "/" || q === "*") {
+ errorAt("Confusing regular expression.",
+ line, from);
+ }
+ return it("(regexp)", c);
+ case "\\":
+ c = s.charAt(l);
+ if (c < " ") {
+ warningAt(
"Unexpected control character in regular expression.", line, from + l);
- } else if (c === '<') {
- warningAt(
+ } else if (c === "<") {
+ warningAt(
"Unexpected escaped character '{a}' in regular expression.", line, from + l, c);
- }
- l += 1;
- break;
- case '(':
- depth += 1;
- b = false;
- if (s.charAt(l) === '?') {
- l += 1;
- switch (s.charAt(l)) {
- case ':':
- case '=':
- case '!':
- l += 1;
- break;
- default:
- warningAt(
-"Expected '{a}' and instead saw '{b}'.", line, from + l, ':', s.charAt(l));
- }
- } else {
- captures += 1;
- }
- break;
- case '|':
- b = false;
- break;
- case ')':
- if (depth === 0) {
- warningAt("Unescaped '{a}'.",
- line, from + l, ')');
- } else {
- depth -= 1;
- }
- break;
- case ' ':
- q = 1;
- while (s.charAt(l) === ' ') {
- l += 1;
- q += 1;
- }
- if (q > 1) {
- warningAt(
+ }
+ l += 1;
+ break;
+ case "(":
+ depth += 1;
+ b = false;
+ if (s.charAt(l) === "?") {
+ l += 1;
+ switch (s.charAt(l)) {
+ case ":":
+ case "=":
+ case "!":
+ l += 1;
+ break;
+ default:
+ warningAt(
+"Expected '{a}' and instead saw '{b}'.", line, from + l, ":", s.charAt(l));
+ }
+ } else {
+ captures += 1;
+ }
+ break;
+ case "|":
+ b = false;
+ break;
+ case ")":
+ if (depth === 0) {
+ warningAt("Unescaped '{a}'.",
+ line, from + l, ")");
+ } else {
+ depth -= 1;
+ }
+ break;
+ case " ":
+ q = 1;
+ while (s.charAt(l) === " ") {
+ l += 1;
+ q += 1;
+ }
+ if (q > 1) {
+ warningAt(
"Spaces are hard to count. Use {{a}}.", line, from + l, q);
- }
- break;
- case '[':
- c = s.charAt(l);
- if (c === '^') {
- l += 1;
- if (option.regexp) {
- warningAt("Insecure '{a}'.",
- line, from + l, c);
- } else if (s.charAt(l) === ']') {
- errorAt("Unescaped '{a}'.",
- line, from + l, '^');
- }
- }
- q = false;
- if (c === ']') {
- warningAt("Empty class.", line,
- from + l - 1);
- q = true;
- }
-klass: do {
- c = s.charAt(l);
- l += 1;
- switch (c) {
- case '[':
- case '^':
- warningAt("Unescaped '{a}'.",
- line, from + l, c);
- q = true;
- break;
- case '-':
- if (q) {
- q = false;
- } else {
- warningAt("Unescaped '{a}'.",
- line, from + l, '-');
- q = true;
- }
- break;
- case ']':
- if (!q && !option.regexdash) {
- warningAt("Unescaped '{a}'.",
- line, from + l - 1, '-');
- }
- break klass;
- case '\\':
- c = s.charAt(l);
- if (c < ' ') {
- warningAt(
+ }
+ break;
+ case "[":
+ c = s.charAt(l);
+ if (c === "^") {
+ l += 1;
+ if (s.charAt(l) === "]") {
+ errorAt("Unescaped '{a}'.",
+ line, from + l, "^");
+ }
+ }
+ if (c === "]") {
+ warningAt("Empty class.", line,
+ from + l - 1);
+ }
+ isLiteral = false;
+ isInRange = false;
+klass:
+ do {
+ c = s.charAt(l);
+ l += 1;
+ switch (c) {
+ case "[":
+ case "^":
+ warningAt("Unescaped '{a}'.",
+ line, from + l, c);
+ if (isInRange) {
+ isInRange = false;
+ } else {
+ isLiteral = true;
+ }
+ break;
+ case "-":
+ if (isLiteral && !isInRange) {
+ isLiteral = false;
+ isInRange = true;
+ } else if (isInRange) {
+ isInRange = false;
+ } else if (s.charAt(l) === "]") {
+ isInRange = true;
+ } else {
+ if (option.regexdash !== (l === 2 || (l === 3 &&
+ s.charAt(1) === "^"))) {
+ warningAt("Unescaped '{a}'.",
+ line, from + l - 1, "-");
+ }
+ isLiteral = true;
+ }
+ break;
+ case "]":
+ if (isInRange && !option.regexdash) {
+ warningAt("Unescaped '{a}'.",
+ line, from + l - 1, "-");
+ }
+ break klass;
+ case "\\":
+ c = s.charAt(l);
+ if (c < " ") {
+ warningAt(
"Unexpected control character in regular expression.", line, from + l);
- } else if (c === '<') {
- warningAt(
+ } else if (c === "<") {
+ warningAt(
"Unexpected escaped character '{a}' in regular expression.", line, from + l, c);
- }
- l += 1;
- q = true;
- break;
- case '/':
- warningAt("Unescaped '{a}'.",
- line, from + l - 1, '/');
- q = true;
- break;
- case '<':
- q = true;
- break;
- default:
- q = true;
- }
- } while (c);
- break;
- case '.':
- if (option.regexp) {
- warningAt("Insecure '{a}'.", line,
- from + l, c);
- }
- break;
- case ']':
- case '?':
- case '{':
- case '}':
- case '+':
- case '*':
- warningAt("Unescaped '{a}'.", line,
- from + l, c);
- }
- if (b) {
- switch (s.charAt(l)) {
- case '?':
- case '+':
- case '*':
- l += 1;
- if (s.charAt(l) === '?') {
- l += 1;
- }
- break;
- case '{':
- l += 1;
- c = s.charAt(l);
- if (c < '0' || c > '9') {
- warningAt(
+ }
+ l += 1;
+ if (/[wsd]/i.test(c)) {
+ if (isInRange) {
+ warningAt("Unescaped '{a}'.",
+ line, from + l, "-");
+ isInRange = false;
+ }
+ isLiteral = false;
+ } else if (isInRange) {
+ isInRange = false;
+ } else {
+ isLiteral = true;
+ }
+ break;
+ case "/":
+ warningAt("Unescaped '{a}'.",
+ line, from + l - 1, "/");
+
+ if (isInRange) {
+ isInRange = false;
+ } else {
+ isLiteral = true;
+ }
+ break;
+ case "<":
+ if (isInRange) {
+ isInRange = false;
+ } else {
+ isLiteral = true;
+ }
+ break;
+ default:
+ if (isInRange) {
+ isInRange = false;
+ } else {
+ isLiteral = true;
+ }
+ }
+ } while (c);
+ break;
+ case ".":
+ if (option.regexp) {
+ warningAt("Insecure '{a}'.", line,
+ from + l, c);
+ }
+ break;
+ case "]":
+ case "?":
+ case "{":
+ case "}":
+ case "+":
+ case "*":
+ warningAt("Unescaped '{a}'.", line,
+ from + l, c);
+ }
+ if (b) {
+ switch (s.charAt(l)) {
+ case "?":
+ case "+":
+ case "*":
+ l += 1;
+ if (s.charAt(l) === "?") {
+ l += 1;
+ }
+ break;
+ case "{":
+ l += 1;
+ c = s.charAt(l);
+ if (c < "0" || c > "9") {
+ warningAt(
"Expected a number and instead saw '{a}'.", line, from + l, c);
- }
- l += 1;
- low = +c;
- for (;;) {
- c = s.charAt(l);
- if (c < '0' || c > '9') {
- break;
- }
- l += 1;
- low = +c + (low * 10);
- }
- high = low;
- if (c === ',') {
- l += 1;
- high = Infinity;
- c = s.charAt(l);
- if (c >= '0' && c <= '9') {
- l += 1;
- high = +c;
- for (;;) {
- c = s.charAt(l);
- if (c < '0' || c > '9') {
- break;
- }
- l += 1;
- high = +c + (high * 10);
- }
- }
- }
- if (s.charAt(l) !== '}') {
- warningAt(
-"Expected '{a}' and instead saw '{b}'.", line, from + l, '}', c);
- } else {
- l += 1;
- }
- if (s.charAt(l) === '?') {
- l += 1;
- }
- if (low > high) {
- warningAt(
+ break; // No reason to continue checking numbers.
+ }
+ l += 1;
+ low = +c;
+ for (;;) {
+ c = s.charAt(l);
+ if (c < "0" || c > "9") {
+ break;
+ }
+ l += 1;
+ low = +c + (low * 10);
+ }
+ high = low;
+ if (c === ",") {
+ l += 1;
+ high = Infinity;
+ c = s.charAt(l);
+ if (c >= "0" && c <= "9") {
+ l += 1;
+ high = +c;
+ for (;;) {
+ c = s.charAt(l);
+ if (c < "0" || c > "9") {
+ break;
+ }
+ l += 1;
+ high = +c + (high * 10);
+ }
+ }
+ }
+ if (s.charAt(l) !== "}") {
+ warningAt(
+"Expected '{a}' and instead saw '{b}'.", line, from + l, "}", c);
+ } else {
+ l += 1;
+ }
+ if (s.charAt(l) === "?") {
+ l += 1;
+ }
+ if (low > high) {
+ warningAt(
"'{a}' should not be greater than '{b}'.", line, from + l, low, high);
- }
- }
- }
- }
- c = s.substr(0, l - 1);
- character += l;
- s = s.substr(l);
- return it('(regexp)', c);
- }
- return it('(punctuator)', t);
-
- // punctuator
-
- case '#':
- return it('(punctuator)', t);
- default:
- return it('(punctuator)', t);
- }
- }
- }
- }
- };
- }());
-
-
- function addlabel(t, type) {
-
- if (t === 'hasOwnProperty') {
- warning("'hasOwnProperty' is a really bad name.");
- }
-
-// Define t in the current function in the current scope.
-
- if (is_own(funct, t) && !funct['(global)']) {
- if (funct[t] === true) {
- if (option.latedef)
- warning("'{a}' was used before it was defined.", nexttoken, t);
- } else {
- if (!option.shadow)
- warning("'{a}' is already defined.", nexttoken, t);
- }
- }
-
- funct[t] = type;
- if (funct['(global)']) {
- global[t] = funct;
- if (is_own(implied, t)) {
- if (option.latedef)
- warning("'{a}' was used before it was defined.", nexttoken, t);
- delete implied[t];
- }
- } else {
- scope[t] = funct;
- }
- }
-
-
- function doOption() {
- var b, obj, filter, o = nexttoken.value, t, v;
- switch (o) {
- case '*/':
- error("Unbegun comment.");
- break;
- case '/*members':
- case '/*member':
- o = '/*members';
- if (!membersOnly) {
- membersOnly = {};
- }
- obj = membersOnly;
- break;
- case '/*jshint':
- case '/*jslint':
- obj = option;
- filter = boolOptions;
- break;
- case '/*global':
- obj = predefined;
- break;
- default:
- error("What?");
- }
- t = lex.token();
-loop: for (;;) {
- for (;;) {
- if (t.type === 'special' && t.value === '*/') {
- break loop;
- }
- if (t.id !== '(endline)' && t.id !== ',') {
- break;
- }
- t = lex.token();
- }
- if (t.type !== '(string)' && t.type !== '(identifier)' &&
- o !== '/*members') {
- error("Bad option.", t);
- }
- v = lex.token();
- if (v.id === ':') {
- v = lex.token();
- if (obj === membersOnly) {
- error("Expected '{a}' and instead saw '{b}'.",
- t, '*/', ':');
- }
- if (t.value === 'indent' && (o === '/*jshint' || o === '/*jslint')) {
- b = +v.value;
- if (typeof b !== 'number' || !isFinite(b) || b <= 0 ||
- Math.floor(b) !== b) {
- error("Expected a small integer and instead saw '{a}'.",
- v, v.value);
- }
- obj.white = true;
- obj.indent = b;
- } else if (t.value === 'maxerr' && (o === '/*jshint' || o === '/*jslint')) {
- b = +v.value;
- if (typeof b !== 'number' || !isFinite(b) || b <= 0 ||
- Math.floor(b) !== b) {
- error("Expected a small integer and instead saw '{a}'.",
- v, v.value);
- }
- obj.maxerr = b;
- } else if (t.value === 'maxlen' && (o === '/*jshint' || o === '/*jslint')) {
- b = +v.value;
- if (typeof b !== 'number' || !isFinite(b) || b <= 0 ||
- Math.floor(b) !== b) {
- error("Expected a small integer and instead saw '{a}'.",
- v, v.value);
- }
- obj.maxlen = b;
- } else if (v.value === 'true') {
- obj[t.value] = true;
- } else if (v.value === 'false') {
- obj[t.value] = false;
- } else {
- error("Bad option value.", v);
- }
- t = lex.token();
- } else {
- if (o === '/*jshint' || o === '/*jslint') {
- error("Missing option value.", t);
- }
- obj[t.value] = false;
- t = v;
- }
- }
- if (filter) {
- assume();
- }
- }
-
-
-// We need a peek function. If it has an argument, it peeks that much farther
-// ahead. It is used to distinguish
-// for ( var i in ...
-// from
-// for ( var i = ...
-
- function peek(p) {
- var i = p || 0, j = 0, t;
-
- while (j <= i) {
- t = lookahead[j];
- if (!t) {
- t = lookahead[j] = lex.token();
- }
- j += 1;
- }
- return t;
- }
-
-
-
-// Produce the next token. It looks for programming errors.
-
- function advance(id, t) {
- switch (token.id) {
- case '(number)':
- if (nexttoken.id === '.') {
- warning("A dot following a number can be confused with a decimal point.", token);
- }
- break;
- case '-':
- if (nexttoken.id === '-' || nexttoken.id === '--') {
- warning("Confusing minusses.");
- }
- break;
- case '+':
- if (nexttoken.id === '+' || nexttoken.id === '++') {
- warning("Confusing plusses.");
- }
- break;
- }
- if (token.type === '(string)' || token.identifier) {
- anonname = token.value;
- }
-
- if (id && nexttoken.id !== id) {
- if (t) {
- if (nexttoken.id === '(end)') {
- warning("Unmatched '{a}'.", t, t.id);
- } else {
- warning("Expected '{a}' to match '{b}' from line {c} and instead saw '{d}'.",
- nexttoken, id, t.id, t.line, nexttoken.value);
- }
- } else if (nexttoken.type !== '(identifier)' ||
- nexttoken.value !== id) {
- warning("Expected '{a}' and instead saw '{b}'.",
- nexttoken, id, nexttoken.value);
- }
- }
- prevtoken = token;
- token = nexttoken;
- for (;;) {
- nexttoken = lookahead.shift() || lex.token();
- if (nexttoken.id === '(end)' || nexttoken.id === '(error)') {
- return;
- }
- if (nexttoken.type === 'special') {
- doOption();
- } else {
- if (nexttoken.id !== '(endline)') {
- break;
- }
- }
- }
- }
-
-
-// This is the heart of JSHINT, the Pratt parser. In addition to parsing, it
-// is looking for ad hoc lint patterns. We add .fud to Pratt's model, which is
-// like .nud except that it is only used on the first token of a statement.
-// Having .fud makes it much easier to define statement-oriented languages like
-// JavaScript. I retained Pratt's nomenclature.
-
-// .nud Null denotation
-// .fud First null denotation
-// .led Left denotation
-// lbp Left binding power
-// rbp Right binding power
-
-// They are elements of the parsing method called Top Down Operator Precedence.
-
- function expression(rbp, initial) {
- var left, isArray = false;
-
- if (nexttoken.id === '(end)')
- error("Unexpected early end of program.", token);
-
- advance();
- if (initial) {
- anonname = 'anonymous';
- funct['(verb)'] = token.value;
- }
- if (initial === true && token.fud) {
- left = token.fud();
- } else {
- if (token.nud) {
- left = token.nud();
- } else {
- if (nexttoken.type === '(number)' && token.id === '.') {
- warning("A leading decimal point can be confused with a dot: '.{a}'.",
- token, nexttoken.value);
- advance();
- return token;
- } else {
- error("Expected an identifier and instead saw '{a}'.",
- token, token.id);
- }
- }
- while (rbp < nexttoken.lbp) {
- isArray = token.value == 'Array';
- advance();
- if (isArray && token.id == '(' && nexttoken.id == ')')
- warning("Use the array literal notation [].", token);
- if (token.led) {
- left = token.led(left);
- } else {
- error("Expected an operator and instead saw '{a}'.",
- token, token.id);
- }
- }
- }
- return left;
- }
-
-
-// Functions for conformance of style.
-
- function adjacent(left, right) {
- left = left || token;
- right = right || nexttoken;
- if (option.white) {
- if (left.character !== right.from && left.line === right.line) {
- warning("Unexpected space after '{a}'.", right, left.value);
- }
- }
- }
-
- function nobreak(left, right) {
- left = left || token;
- right = right || nexttoken;
- if (option.white && (left.character !== right.from || left.line !== right.line)) {
- warning("Unexpected space before '{a}'.", right, right.value);
- }
- }
-
- function nospace(left, right) {
- left = left || token;
- right = right || nexttoken;
- if (option.white && !left.comment) {
- if (left.line === right.line) {
- adjacent(left, right);
- }
- }
- }
-
- function nonadjacent(left, right) {
- if (option.white) {
- left = left || token;
- right = right || nexttoken;
- if (left.line === right.line && left.character === right.from) {
- warning("Missing space after '{a}'.",
- nexttoken, left.value);
- }
- }
- }
-
- function nobreaknonadjacent(left, right) {
- left = left || token;
- right = right || nexttoken;
- if (!option.laxbreak && left.line !== right.line) {
- warning("Bad line breaking before '{a}'.", right, right.id);
- } else if (option.white) {
- left = left || token;
- right = right || nexttoken;
- if (left.character === right.from) {
- warning("Missing space after '{a}'.",
- nexttoken, left.value);
- }
- }
- }
-
- function indentation(bias) {
- var i;
- if (option.white && nexttoken.id !== '(end)') {
- i = indent + (bias || 0);
- if (nexttoken.from !== i) {
- warning(
+ }
+ }
+ }
+ }
+ c = s.substr(0, l - 1);
+ character += l;
+ s = s.substr(l);
+ return it("(regexp)", c);
+ }
+ return it("(punctuator)", t);
+
+ case "#":
+ return it("(punctuator)", t);
+ default:
+ return it("(punctuator)", t);
+ }
+ }
+ }
+ }
+ };
+ }());
+
+
+ function addlabel(t, type, token) {
+ if (t === "hasOwnProperty") {
+ warning("'hasOwnProperty' is a really bad name.");
+ }
+ if (type === "exception") {
+ if (is_own(funct["(context)"], t)) {
+ if (funct[t] !== true && !option.node) {
+ warning("Value of '{a}' may be overwritten in IE.", nexttoken, t);
+ }
+ }
+ }
+
+ if (is_own(funct, t) && !funct["(global)"]) {
+ if (funct[t] === true) {
+ if (option.latedef)
+ warning("'{a}' was used before it was defined.", nexttoken, t);
+ } else {
+ if (!option.shadow && type !== "exception") {
+ warning("'{a}' is already defined.", nexttoken, t);
+ }
+ }
+ }
+
+ funct[t] = type;
+
+ if (token) {
+ funct["(tokens)"][t] = token;
+ }
+
+ if (funct["(global)"]) {
+ global[t] = funct;
+ if (is_own(implied, t)) {
+ if (option.latedef)
+ warning("'{a}' was used before it was defined.", nexttoken, t);
+ delete implied[t];
+ }
+ } else {
+ scope[t] = funct;
+ }
+ }
+
+
+ function doOption() {
+ var nt = nexttoken;
+ var o = nt.value;
+ var quotmarkValue = option.quotmark;
+ var predef = {};
+ var b, obj, filter, t, tn, v, minus;
+
+ switch (o) {
+ case "*/":
+ error("Unbegun comment.");
+ break;
+ case "/*members":
+ case "/*member":
+ o = "/*members";
+ if (!membersOnly) {
+ membersOnly = {};
+ }
+ obj = membersOnly;
+ option.quotmark = false;
+ break;
+ case "/*jshint":
+ case "/*jslint":
+ obj = option;
+ filter = boolOptions;
+ break;
+ case "/*global":
+ obj = predef;
+ break;
+ default:
+ error("What?");
+ }
+
+ t = lex.token();
+
+loop:
+ for (;;) {
+ minus = false;
+ for (;;) {
+ if (t.type === "special" && t.value === "*/") {
+ break loop;
+ }
+ if (t.id !== "(endline)" && t.id !== ",") {
+ break;
+ }
+ t = lex.token();
+ }
+
+ if (o === "/*global" && t.value === "-") {
+ minus = true;
+ t = lex.token();
+ }
+
+ if (t.type !== "(string)" && t.type !== "(identifier)" && o !== "/*members") {
+ error("Bad option.", t);
+ }
+
+ v = lex.token();
+ if (v.id === ":") {
+ v = lex.token();
+
+ if (obj === membersOnly) {
+ error("Expected '{a}' and instead saw '{b}'.", t, "*/", ":");
+ }
+
+ if (o === "/*jshint") {
+ checkOption(t.value, t);
+ }
+
+ var numericVals = [
+ "maxstatements",
+ "maxparams",
+ "maxdepth",
+ "maxcomplexity",
+ "maxerr",
+ "maxlen",
+ "indent"
+ ];
+
+ if (numericVals.indexOf(t.value) > -1 && (o === "/*jshint" || o === "/*jslint")) {
+ b = +v.value;
+
+ if (typeof b !== "number" || !isFinite(b) || b <= 0 || Math.floor(b) !== b) {
+ error("Expected a small integer and instead saw '{a}'.", v, v.value);
+ }
+
+ if (t.value === "indent")
+ obj.white = true;
+
+ obj[t.value] = b;
+ } else if (t.value === "validthis") {
+ if (funct["(global)"]) {
+ error("Option 'validthis' can't be used in a global scope.");
+ } else {
+ if (v.value === "true" || v.value === "false")
+ obj[t.value] = v.value === "true";
+ else
+ error("Bad option value.", v);
+ }
+ } else if (t.value === "quotmark" && (o === "/*jshint")) {
+ switch (v.value) {
+ case "true":
+ obj.quotmark = true;
+ break;
+ case "false":
+ obj.quotmark = false;
+ break;
+ case "double":
+ case "single":
+ obj.quotmark = v.value;
+ break;
+ default:
+ error("Bad option value.", v);
+ }
+ } else if (v.value === "true" || v.value === "false") {
+ if (o === "/*jslint") {
+ tn = renamedOptions[t.value] || t.value;
+ obj[tn] = v.value === "true";
+ if (invertedOptions[tn] !== undefined) {
+ obj[tn] = !obj[tn];
+ }
+ } else {
+ obj[t.value] = v.value === "true";
+ }
+
+ if (t.value === "newcap")
+ obj["(explicitNewcap)"] = true;
+ } else {
+ error("Bad option value.", v);
+ }
+ t = lex.token();
+ } else {
+ if (o === "/*jshint" || o === "/*jslint") {
+ error("Missing option value.", t);
+ }
+
+ obj[t.value] = false;
+
+ if (o === "/*global" && minus === true) {
+ JSHINT.blacklist[t.value] = t.value;
+ updatePredefined();
+ }
+
+ t = v;
+ }
+ }
+
+ if (o === "/*members") {
+ option.quotmark = quotmarkValue;
+ }
+
+ combine(predefined, predef);
+
+ for (var key in predef) {
+ if (is_own(predef, key)) {
+ declared[key] = nt;
+ }
+ }
+
+ if (filter) {
+ assume();
+ }
+ }
+
+ function peek(p) {
+ var i = p || 0, j = 0, t;
+
+ while (j <= i) {
+ t = lookahead[j];
+ if (!t) {
+ t = lookahead[j] = lex.token();
+ }
+ j += 1;
+ }
+ return t;
+ }
+
+ function advance(id, t) {
+ switch (token.id) {
+ case "(number)":
+ if (nexttoken.id === ".") {
+ warning("A dot following a number can be confused with a decimal point.", token);
+ }
+ break;
+ case "-":
+ if (nexttoken.id === "-" || nexttoken.id === "--") {
+ warning("Confusing minusses.");
+ }
+ break;
+ case "+":
+ if (nexttoken.id === "+" || nexttoken.id === "++") {
+ warning("Confusing plusses.");
+ }
+ break;
+ }
+
+ if (token.type === "(string)" || token.identifier) {
+ anonname = token.value;
+ }
+
+ if (id && nexttoken.id !== id) {
+ if (t) {
+ if (nexttoken.id === "(end)") {
+ warning("Unmatched '{a}'.", t, t.id);
+ } else {
+ warning("Expected '{a}' to match '{b}' from line {c} and instead saw '{d}'.",
+ nexttoken, id, t.id, t.line, nexttoken.value);
+ }
+ } else if (nexttoken.type !== "(identifier)" ||
+ nexttoken.value !== id) {
+ warning("Expected '{a}' and instead saw '{b}'.",
+ nexttoken, id, nexttoken.value);
+ }
+ }
+
+ prevtoken = token;
+ token = nexttoken;
+ for (;;) {
+ nexttoken = lookahead.shift() || lex.token();
+ if (nexttoken.id === "(end)" || nexttoken.id === "(error)") {
+ return;
+ }
+ if (nexttoken.type === "special") {
+ doOption();
+ } else {
+ if (nexttoken.id !== "(endline)") {
+ break;
+ }
+ }
+ }
+ }
+
+ function expression(rbp, initial) {
+ var left, isArray = false, isObject = false;
+
+ if (nexttoken.id === "(end)")
+ error("Unexpected early end of program.", token);
+
+ advance();
+ if (initial) {
+ anonname = "anonymous";
+ funct["(verb)"] = token.value;
+ }
+ if (initial === true && token.fud) {
+ left = token.fud();
+ } else {
+ if (token.nud) {
+ left = token.nud();
+ } else {
+ if (nexttoken.type === "(number)" && token.id === ".") {
+ warning("A leading decimal point can be confused with a dot: '.{a}'.",
+ token, nexttoken.value);
+ advance();
+ return token;
+ } else {
+ error("Expected an identifier and instead saw '{a}'.",
+ token, token.id);
+ }
+ }
+ while (rbp < nexttoken.lbp) {
+ isArray = token.value === "Array";
+ isObject = token.value === "Object";
+ if (left && (left.value || (left.first && left.first.value))) {
+ if (left.value !== "new" ||
+ (left.first && left.first.value && left.first.value === ".")) {
+ isArray = false;
+ if (left.value !== token.value) {
+ isObject = false;
+ }
+ }
+ }
+
+ advance();
+ if (isArray && token.id === "(" && nexttoken.id === ")")
+ warning("Use the array literal notation [].", token);
+ if (isObject && token.id === "(" && nexttoken.id === ")")
+ warning("Use the object literal notation {}.", token);
+ if (token.led) {
+ left = token.led(left);
+ } else {
+ error("Expected an operator and instead saw '{a}'.",
+ token, token.id);
+ }
+ }
+ }
+ return left;
+ }
+
+ function adjacent(left, right) {
+ left = left || token;
+ right = right || nexttoken;
+ if (option.white) {
+ if (left.character !== right.from && left.line === right.line) {
+ left.from += (left.character - left.from);
+ warning("Unexpected space after '{a}'.", left, left.value);
+ }
+ }
+ }
+
+ function nobreak(left, right) {
+ left = left || token;
+ right = right || nexttoken;
+ if (option.white && (left.character !== right.from || left.line !== right.line)) {
+ warning("Unexpected space before '{a}'.", right, right.value);
+ }
+ }
+
+ function nospace(left, right) {
+ left = left || token;
+ right = right || nexttoken;
+ if (option.white && !left.comment) {
+ if (left.line === right.line) {
+ adjacent(left, right);
+ }
+ }
+ }
+
+ function nonadjacent(left, right) {
+ if (option.white) {
+ left = left || token;
+ right = right || nexttoken;
+ if (left.value === ";" && right.value === ";") {
+ return;
+ }
+ if (left.line === right.line && left.character === right.from) {
+ left.from += (left.character - left.from);
+ warning("Missing space after '{a}'.",
+ left, left.value);
+ }
+ }
+ }
+
+ function nobreaknonadjacent(left, right) {
+ left = left || token;
+ right = right || nexttoken;
+ if (!option.laxbreak && left.line !== right.line) {
+ warning("Bad line breaking before '{a}'.", right, right.id);
+ } else if (option.white) {
+ left = left || token;
+ right = right || nexttoken;
+ if (left.character === right.from) {
+ left.from += (left.character - left.from);
+ warning("Missing space after '{a}'.",
+ left, left.value);
+ }
+ }
+ }
+
+ function indentation(bias) {
+ var i;
+ if (option.white && nexttoken.id !== "(end)") {
+ i = indent + (bias || 0);
+ if (nexttoken.from !== i) {
+ warning(
"Expected '{a}' to have an indentation at {b} instead at {c}.",
- nexttoken, nexttoken.value, i, nexttoken.from);
- }
- }
- }
-
- function nolinebreak(t) {
- t = t || token;
- if (t.line !== nexttoken.line) {
- warning("Line breaking error '{a}'.", t, t.value);
- }
- }
-
-
- function comma() {
- if (token.line !== nexttoken.line) {
- if (!option.laxbreak) {
- warning("Bad line breaking before '{a}'.", token, nexttoken.id);
- }
- } else if (token.character !== nexttoken.from && option.white) {
- warning("Unexpected space after '{a}'.", nexttoken, token.value);
- }
- advance(',');
- nonadjacent(token, nexttoken);
- }
-
-
-// Functional constructors for making the symbols that will be inherited by
-// tokens.
-
- function symbol(s, p) {
- var x = syntax[s];
- if (!x || typeof x !== 'object') {
- syntax[s] = x = {
- id: s,
- lbp: p,
- value: s
- };
- }
- return x;
- }
-
-
- function delim(s) {
- return symbol(s, 0);
- }
-
-
- function stmt(s, f) {
- var x = delim(s);
- x.identifier = x.reserved = true;
- x.fud = f;
- return x;
- }
-
-
- function blockstmt(s, f) {
- var x = stmt(s, f);
- x.block = true;
- return x;
- }
-
-
- function reserveName(x) {
- var c = x.id.charAt(0);
- if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
- x.identifier = x.reserved = true;
- }
- return x;
- }
-
-
- function prefix(s, f) {
- var x = symbol(s, 150);
- reserveName(x);
- x.nud = (typeof f === 'function') ? f : function () {
- this.right = expression(150);
- this.arity = 'unary';
- if (this.id === '++' || this.id === '--') {
- if (option.plusplus) {
- warning("Unexpected use of '{a}'.", this, this.id);
- } else if ((!this.right.identifier || this.right.reserved) &&
- this.right.id !== '.' && this.right.id !== '[') {
- warning("Bad operand.", this);
- }
- }
- return this;
- };
- return x;
- }
-
-
- function type(s, f) {
- var x = delim(s);
- x.type = s;
- x.nud = f;
- return x;
- }
-
-
- function reserve(s, f) {
- var x = type(s, f);
- x.identifier = x.reserved = true;
- return x;
- }
-
-
- function reservevar(s, v) {
- return reserve(s, function () {
- if (typeof v === 'function') {
- v(this);
- }
- return this;
- });
- }
-
-
- function infix(s, f, p, w) {
- var x = symbol(s, p);
- reserveName(x);
- x.led = function (left) {
- if (!w) {
- nobreaknonadjacent(prevtoken, token);
- nonadjacent(token, nexttoken);
- }
- if (typeof f === 'function') {
- return f(left, this);
- } else {
- this.left = left;
- this.right = expression(p);
- return this;
- }
- };
- return x;
- }
-
-
- function relation(s, f) {
- var x = symbol(s, 100);
- x.led = function (left) {
- nobreaknonadjacent(prevtoken, token);
- nonadjacent(token, nexttoken);
- var right = expression(100);
- if ((left && left.id === 'NaN') || (right && right.id === 'NaN')) {
- warning("Use the isNaN function to compare with NaN.", this);
- } else if (f) {
- f.apply(this, [left, right]);
- }
- if (left.id === '!') {
- warning("Confusing use of '{a}'.", left, '!');
- }
- if (right.id === '!') {
- warning("Confusing use of '{a}'.", left, '!');
- }
- this.left = left;
- this.right = right;
- return this;
- };
- return x;
- }
-
-
- function isPoorRelation(node) {
- return node &&
- ((node.type === '(number)' && +node.value === 0) ||
- (node.type === '(string)' && node.value === '') ||
- (node.type === 'null' && !option.eqnull) ||
- node.type === 'true' ||
- node.type === 'false' ||
- node.type === 'undefined');
- }
-
-
- function assignop(s, f) {
- symbol(s, 20).exps = true;
- return infix(s, function (left, that) {
- var l;
- that.left = left;
- if (predefined[left.value] === false &&
- scope[left.value]['(global)'] === true) {
- warning("Read only.", left);
- } else if (left['function']) {
- warning("'{a}' is a function.", left, left.value);
- }
- if (left) {
- if (left.id === '.' || left.id === '[') {
- if (!left.left || left.left.value === 'arguments') {
- warning('Bad assignment.', that);
- }
- that.right = expression(19);
- return that;
- } else if (left.identifier && !left.reserved) {
- if (funct[left.value] === 'exception') {
- warning("Do not assign to the exception parameter.", left);
- }
- that.right = expression(19);
- return that;
- }
- if (left === syntax['function']) {
- warning(
+ nexttoken, nexttoken.value, i, nexttoken.from);
+ }
+ }
+ }
+
+ function nolinebreak(t) {
+ t = t || token;
+ if (t.line !== nexttoken.line) {
+ warning("Line breaking error '{a}'.", t, t.value);
+ }
+ }
+
+
+ function comma() {
+ if (token.line !== nexttoken.line) {
+ if (!option.laxcomma) {
+ if (comma.first) {
+ warning("Comma warnings can be turned off with 'laxcomma'");
+ comma.first = false;
+ }
+ warning("Bad line breaking before '{a}'.", token, nexttoken.id);
+ }
+ } else if (!token.comment && token.character !== nexttoken.from && option.white) {
+ token.from += (token.character - token.from);
+ warning("Unexpected space after '{a}'.", token, token.value);
+ }
+ advance(",");
+ nonadjacent(token, nexttoken);
+ }
+
+ function symbol(s, p) {
+ var x = syntax[s];
+ if (!x || typeof x !== "object") {
+ syntax[s] = x = {
+ id: s,
+ lbp: p,
+ value: s
+ };
+ }
+ return x;
+ }
+
+
+ function delim(s) {
+ return symbol(s, 0);
+ }
+
+
+ function stmt(s, f) {
+ var x = delim(s);
+ x.identifier = x.reserved = true;
+ x.fud = f;
+ return x;
+ }
+
+
+ function blockstmt(s, f) {
+ var x = stmt(s, f);
+ x.block = true;
+ return x;
+ }
+
+
+ function reserveName(x) {
+ var c = x.id.charAt(0);
+ if ((c >= "a" && c <= "z") || (c >= "A" && c <= "Z")) {
+ x.identifier = x.reserved = true;
+ }
+ return x;
+ }
+
+
+ function prefix(s, f) {
+ var x = symbol(s, 150);
+ reserveName(x);
+ x.nud = (typeof f === "function") ? f : function () {
+ this.right = expression(150);
+ this.arity = "unary";
+ if (this.id === "++" || this.id === "--") {
+ if (option.plusplus) {
+ warning("Unexpected use of '{a}'.", this, this.id);
+ } else if ((!this.right.identifier || this.right.reserved) &&
+ this.right.id !== "." && this.right.id !== "[") {
+ warning("Bad operand.", this);
+ }
+ }
+ return this;
+ };
+ return x;
+ }
+
+
+ function type(s, f) {
+ var x = delim(s);
+ x.type = s;
+ x.nud = f;
+ return x;
+ }
+
+
+ function reserve(s, f) {
+ var x = type(s, f);
+ x.identifier = x.reserved = true;
+ return x;
+ }
+
+
+ function reservevar(s, v) {
+ return reserve(s, function () {
+ if (typeof v === "function") {
+ v(this);
+ }
+ return this;
+ });
+ }
+
+
+ function infix(s, f, p, w) {
+ var x = symbol(s, p);
+ reserveName(x);
+ x.led = function (left) {
+ if (!w) {
+ nobreaknonadjacent(prevtoken, token);
+ nonadjacent(token, nexttoken);
+ }
+ if (s === "in" && left.id === "!") {
+ warning("Confusing use of '{a}'.", left, "!");
+ }
+ if (typeof f === "function") {
+ return f(left, this);
+ } else {
+ this.left = left;
+ this.right = expression(p);
+ return this;
+ }
+ };
+ return x;
+ }
+
+
+ function relation(s, f) {
+ var x = symbol(s, 100);
+ x.led = function (left) {
+ nobreaknonadjacent(prevtoken, token);
+ nonadjacent(token, nexttoken);
+ var right = expression(100);
+
+ if (isIdentifier(left, "NaN") || isIdentifier(right, "NaN")) {
+ warning("Use the isNaN function to compare with NaN.", this);
+ } else if (f) {
+ f.apply(this, [left, right]);
+ }
+ if (left.id === "!") {
+ warning("Confusing use of '{a}'.", left, "!");
+ }
+ if (right.id === "!") {
+ warning("Confusing use of '{a}'.", right, "!");
+ }
+ this.left = left;
+ this.right = right;
+ return this;
+ };
+ return x;
+ }
+
+
+ function isPoorRelation(node) {
+ return node &&
+ ((node.type === "(number)" && +node.value === 0) ||
+ (node.type === "(string)" && node.value === "") ||
+ (node.type === "null" && !option.eqnull) ||
+ node.type === "true" ||
+ node.type === "false" ||
+ node.type === "undefined");
+ }
+
+
+ function assignop(s) {
+ symbol(s, 20).exps = true;
+
+ return infix(s, function (left, that) {
+ that.left = left;
+
+ if (predefined[left.value] === false &&
+ scope[left.value]["(global)"] === true) {
+ warning("Read only.", left);
+ } else if (left["function"]) {
+ warning("'{a}' is a function.", left, left.value);
+ }
+
+ if (left) {
+ if (option.esnext && funct[left.value] === "const") {
+ warning("Attempting to override '{a}' which is a constant", left, left.value);
+ }
+
+ if (left.id === "." || left.id === "[") {
+ if (!left.left || left.left.value === "arguments") {
+ warning("Bad assignment.", that);
+ }
+ that.right = expression(19);
+ return that;
+ } else if (left.identifier && !left.reserved) {
+ if (funct[left.value] === "exception") {
+ warning("Do not assign to the exception parameter.", left);
+ }
+ that.right = expression(19);
+ return that;
+ }
+
+ if (left === syntax["function"]) {
+ warning(
"Expected an identifier in an assignment and instead saw a function invocation.",
- token);
- }
- }
- error("Bad assignment.", that);
- }, 20);
- }
-
-
- function bitwise(s, f, p) {
- var x = symbol(s, p);
- reserveName(x);
- x.led = (typeof f === 'function') ? f : function (left) {
- if (option.bitwise) {
- warning("Unexpected use of '{a}'.", this, this.id);
- }
- this.left = left;
- this.right = expression(p);
- return this;
- };
- return x;
- }
-
-
- function bitwiseassignop(s) {
- symbol(s, 20).exps = true;
- return infix(s, function (left, that) {
- if (option.bitwise) {
- warning("Unexpected use of '{a}'.", that, that.id);
- }
- nonadjacent(prevtoken, token);
- nonadjacent(token, nexttoken);
- if (left) {
- if (left.id === '.' || left.id === '[' ||
- (left.identifier && !left.reserved)) {
- expression(19);
- return that;
- }
- if (left === syntax['function']) {
- warning(
+ token);
+ }
+ }
+
+ error("Bad assignment.", that);
+ }, 20);
+ }
+
+
+ function bitwise(s, f, p) {
+ var x = symbol(s, p);
+ reserveName(x);
+ x.led = (typeof f === "function") ? f : function (left) {
+ if (option.bitwise) {
+ warning("Unexpected use of '{a}'.", this, this.id);
+ }
+ this.left = left;
+ this.right = expression(p);
+ return this;
+ };
+ return x;
+ }
+
+
+ function bitwiseassignop(s) {
+ symbol(s, 20).exps = true;
+ return infix(s, function (left, that) {
+ if (option.bitwise) {
+ warning("Unexpected use of '{a}'.", that, that.id);
+ }
+ nonadjacent(prevtoken, token);
+ nonadjacent(token, nexttoken);
+ if (left) {
+ if (left.id === "." || left.id === "[" ||
+ (left.identifier && !left.reserved)) {
+ expression(19);
+ return that;
+ }
+ if (left === syntax["function"]) {
+ warning(
"Expected an identifier in an assignment, and instead saw a function invocation.",
- token);
- }
- return that;
- }
- error("Bad assignment.", that);
- }, 20);
- }
-
-
- function suffix(s, f) {
- var x = symbol(s, 150);
- x.led = function (left) {
- if (option.plusplus) {
- warning("Unexpected use of '{a}'.", this, this.id);
- } else if ((!left.identifier || left.reserved) &&
- left.id !== '.' && left.id !== '[') {
- warning("Bad operand.", this);
- }
- this.left = left;
- return this;
- };
- return x;
- }
-
-
- // fnparam means that this identifier is being defined as a function
- // argument (see identifier())
- function optionalidentifier(fnparam) {
- if (nexttoken.identifier) {
- advance();
- if (token.reserved && !option.es5) {
- // `undefined` as a function param is a common pattern to protect
- // against the case when somebody does `undefined = true` and
- // help with minification. More info: https://gist.github.com/315916
- if (!fnparam || token.value != 'undefined') {
- warning("Expected an identifier and instead saw '{a}' (a reserved word).",
- token, token.id);
- }
- }
- return token.value;
- }
- }
-
- // fnparam means that this identifier is being defined as a function
- // argument
- function identifier(fnparam) {
- var i = optionalidentifier(fnparam);
- if (i) {
- return i;
- }
- if (token.id === 'function' && nexttoken.id === '(') {
- warning("Missing name in function declaration.");
- } else {
- error("Expected an identifier and instead saw '{a}'.",
- nexttoken, nexttoken.value);
- }
- }
-
-
- function reachable(s) {
- var i = 0, t;
- if (nexttoken.id !== ';' || noreach) {
- return;
- }
- for (;;) {
- t = peek(i);
- if (t.reach) {
- return;
- }
- if (t.id !== '(endline)') {
- if (t.id === 'function') {
- warning(
+ token);
+ }
+ return that;
+ }
+ error("Bad assignment.", that);
+ }, 20);
+ }
+
+
+ function suffix(s) {
+ var x = symbol(s, 150);
+ x.led = function (left) {
+ if (option.plusplus) {
+ warning("Unexpected use of '{a}'.", this, this.id);
+ } else if ((!left.identifier || left.reserved) &&
+ left.id !== "." && left.id !== "[") {
+ warning("Bad operand.", this);
+ }
+ this.left = left;
+ return this;
+ };
+ return x;
+ }
+ function optionalidentifier(fnparam) {
+ if (nexttoken.identifier) {
+ advance();
+ if (token.reserved && !option.es5) {
+ if (!fnparam || token.value !== "undefined") {
+ warning("Expected an identifier and instead saw '{a}' (a reserved word).",
+ token, token.id);
+ }
+ }
+ return token.value;
+ }
+ }
+ function identifier(fnparam) {
+ var i = optionalidentifier(fnparam);
+ if (i) {
+ return i;
+ }
+ if (token.id === "function" && nexttoken.id === "(") {
+ warning("Missing name in function declaration.");
+ } else {
+ error("Expected an identifier and instead saw '{a}'.",
+ nexttoken, nexttoken.value);
+ }
+ }
+
+
+ function reachable(s) {
+ var i = 0, t;
+ if (nexttoken.id !== ";" || noreach) {
+ return;
+ }
+ for (;;) {
+ t = peek(i);
+ if (t.reach) {
+ return;
+ }
+ if (t.id !== "(endline)") {
+ if (t.id === "function") {
+ if (!option.latedef) {
+ break;
+ }
+ warning(
"Inner functions should be listed at the top of the outer function.", t);
- break;
- }
- warning("Unreachable '{a}' after '{b}'.", t, t.value, s);
- break;
- }
- i += 1;
- }
- }
-
-
- function statement(noindent) {
- var i = indent, r, s = scope, t = nexttoken;
-
-// We don't like the empty statement.
-
- if (t.id === ';') {
- warning("Unnecessary semicolon.", t);
- advance(';');
- return;
- }
-
-// Is this a labelled statement?
-
- if (t.identifier && !t.reserved && peek().id === ':') {
- advance();
- advance(':');
- scope = Object.create(s);
- addlabel(t.value, 'label');
- if (!nexttoken.labelled) {
- warning("Label '{a}' on {b} statement.",
- nexttoken, t.value, nexttoken.value);
- }
- if (jx.test(t.value + ':')) {
- warning("Label '{a}' looks like a javascript url.",
- t, t.value);
- }
- nexttoken.label = t.value;
- t = nexttoken;
- }
-
-// Parse the statement.
-
- if (!noindent) {
- indentation();
- }
- r = expression(0, true);
-
-// Look for the final semicolon.
-
- if (!t.block) {
- if (!option.expr && (!r || !r.exps)) {
- warning("Expected an assignment or function call and instead saw an expression.",
- token);
- } else if (option.nonew && r.id === '(' && r.left.id === 'new') {
- warning("Do not use 'new' for side effects.");
- }
- if (nexttoken.id !== ';') {
- if (!option.asi && !(option.lastsemic && nexttoken.id == '}' &&
- nexttoken.line == token.line)) {
- warningAt("Missing semicolon.", token.line, token.from + token.value.length);
- }
- } else {
- adjacent(token, nexttoken);
- advance(';');
- nonadjacent(token, nexttoken);
- }
- }
-
-// Restore the indentation.
-
- indent = i;
- scope = s;
- return r;
- }
-
-
- function use_strict() {
- if (nexttoken.value === 'use strict') {
- if (strict_mode) {
- warning("Unnecessary \"use strict\".");
- }
- advance();
- advance(';');
- strict_mode = true;
- option.newcap = true;
- option.undef = true;
- return true;
- } else {
- return false;
- }
- }
-
-
- function statements(begin) {
- var a = [], f, p;
-
- while (!nexttoken.reach && nexttoken.id !== '(end)') {
- if (nexttoken.id === ';') {
- warning("Unnecessary semicolon.");
- advance(';');
- } else {
- a.push(statement());
- }
- }
- return a;
- }
-
-
- /*
- * Parses a single block. A block is a sequence of statements wrapped in
- * braces.
- *
- * ordinary - true for everything but function bodies and try blocks.
- * stmt - true if block can be a single statement (e.g. in if/for/while).
- */
- function block(ordinary, stmt) {
- var a,
- b = inblock,
- old_indent = indent,
- m = strict_mode,
- s = scope,
- t;
-
- inblock = ordinary;
- scope = Object.create(scope);
- nonadjacent(token, nexttoken);
- t = nexttoken;
-
- if (nexttoken.id === '{') {
- advance('{');
- if (nexttoken.id !== '}' || token.line !== nexttoken.line) {
- indent += option.indent;
- while (!ordinary && nexttoken.from > indent) {
- indent += option.indent;
- }
- if (!ordinary && !use_strict() && !m && option.strict &&
- funct['(context)']['(global)']) {
- warning("Missing \"use strict\" statement.");
- }
- a = statements();
- strict_mode = m;
- indent -= option.indent;
- indentation();
- }
- advance('}', t);
- indent = old_indent;
- } else if (!ordinary) {
- error("Expected '{a}' and instead saw '{b}'.",
- nexttoken, '{', nexttoken.value);
- } else {
- if (!stmt || option.curly)
- warning("Expected '{a}' and instead saw '{b}'.",
- nexttoken, '{', nexttoken.value);
-
- noreach = true;
- a = [statement()];
- noreach = false;
- }
- funct['(verb)'] = null;
- scope = s;
- inblock = b;
- if (ordinary && option.noempty && (!a || a.length === 0)) {
- warning("Empty block.");
- }
- return a;
- }
-
-
- function countMember(m) {
- if (membersOnly && typeof membersOnly[m] !== 'boolean') {
- warning("Unexpected /*member '{a}'.", token, m);
- }
- if (typeof member[m] === 'number') {
- member[m] += 1;
- } else {
- member[m] = 1;
- }
- }
-
-
- function note_implied(token) {
- var name = token.value, line = token.line, a = implied[name];
- if (typeof a === 'function') {
- a = false;
- }
- if (!a) {
- a = [line];
- implied[name] = a;
- } else if (a[a.length - 1] !== line) {
- a.push(line);
- }
- }
-
-// Build the syntax table by declaring the syntactic elements of the language.
-
- type('(number)', function () {
- return this;
- });
- type('(string)', function () {
- return this;
- });
-
- syntax['(identifier)'] = {
- type: '(identifier)',
- lbp: 0,
- identifier: true,
- nud: function () {
- var v = this.value,
- s = scope[v],
- f;
- if (typeof s === 'function') {
-
-// Protection against accidental inheritance.
-
- s = undefined;
- } else if (typeof s === 'boolean') {
- f = funct;
- funct = functions[0];
- addlabel(v, 'var');
- s = funct;
- funct = f;
- }
-
-// The name is in scope and defined in the current function.
-
- if (funct === s) {
-
-// Change 'unused' to 'var', and reject labels.
-
- switch (funct[v]) {
- case 'unused':
- funct[v] = 'var';
- break;
- case 'unction':
- funct[v] = 'function';
- this['function'] = true;
- break;
- case 'function':
- this['function'] = true;
- break;
- case 'label':
- warning("'{a}' is a statement label.", token, v);
- break;
- }
-
-// The name is not defined in the function. If we are in the global scope,
-// then we have an undefined variable.
-//
-// Operators typeof and delete do not raise runtime errors even if the base
-// object of a reference is null so no need to display warning if we're
-// inside of typeof or delete.
-
- } else if (funct['(global)']) {
- if (anonname != 'typeof' && anonname != 'delete' &&
- option.undef && typeof predefined[v] !== 'boolean') {
- warning("'{a}' is not defined.", token, v);
- }
- note_implied(token);
-
-// If the name is already defined in the current
-// function, but not as outer, then there is a scope error.
-
- } else {
- switch (funct[v]) {
- case 'closure':
- case 'function':
- case 'var':
- case 'unused':
- warning("'{a}' used out of scope.", token, v);
- break;
- case 'label':
- warning("'{a}' is a statement label.", token, v);
- break;
- case 'outer':
- case 'global':
- break;
- default:
-
-// If the name is defined in an outer function, make an outer entry, and if
-// it was unused, make it var.
-
- if (s === true) {
- funct[v] = true;
- } else if (s === null) {
- warning("'{a}' is not allowed.", token, v);
- note_implied(token);
- } else if (typeof s !== 'object') {
-
-// Operators typeof and delete do not raise runtime errors even if the base object of
-// a reference is null so no need to display warning if we're inside of typeof or delete.
-
- if (anonname != 'typeof' && anonname != 'delete' && option.undef) {
- warning("'{a}' is not defined.", token, v);
- } else {
- funct[v] = true;
- }
- note_implied(token);
- } else {
- switch (s[v]) {
- case 'function':
- case 'unction':
- this['function'] = true;
- s[v] = 'closure';
- funct[v] = s['(global)'] ? 'global' : 'outer';
- break;
- case 'var':
- case 'unused':
- s[v] = 'closure';
- funct[v] = s['(global)'] ? 'global' : 'outer';
- break;
- case 'closure':
- case 'parameter':
- funct[v] = s['(global)'] ? 'global' : 'outer';
- break;
- case 'label':
- warning("'{a}' is a statement label.", token, v);
- }
- }
- }
- }
- return this;
- },
- led: function () {
- error("Expected an operator and instead saw '{a}'.",
- nexttoken, nexttoken.value);
- }
- };
-
- type('(regexp)', function () {
- return this;
- });
-
-
-// ECMAScript parser
-
- delim('(endline)');
- delim('(begin)');
- delim('(end)').reach = true;
- delim('</').reach = true;
- delim('<!');
- delim('<!--');
- delim('-->');
- delim('(error)').reach = true;
- delim('}').reach = true;
- delim(')');
- delim(']');
- delim('"').reach = true;
- delim("'").reach = true;
- delim(';');
- delim(':').reach = true;
- delim(',');
- delim('#');
- delim('@');
- reserve('else');
- reserve('case').reach = true;
- reserve('catch');
- reserve('default').reach = true;
- reserve('finally');
- reservevar('arguments', function (x) {
- if (strict_mode && funct['(global)']) {
- warning("Strict violation.", x);
- }
- });
- reservevar('eval');
- reservevar('false');
- reservevar('Infinity');
- reservevar('NaN');
- reservevar('null');
- reservevar('this', function (x) {
- if (strict_mode && ((funct['(statement)'] &&
- funct['(name)'].charAt(0) > 'Z') || funct['(global)'])) {
- warning("Strict violation.", x);
- }
- });
- reservevar('true');
- reservevar('undefined');
- assignop('=', 'assign', 20);
- assignop('+=', 'assignadd', 20);
- assignop('-=', 'assignsub', 20);
- assignop('*=', 'assignmult', 20);
- assignop('/=', 'assigndiv', 20).nud = function () {
- error("A regular expression literal can be confused with '/='.");
- };
- assignop('%=', 'assignmod', 20);
- bitwiseassignop('&=', 'assignbitand', 20);
- bitwiseassignop('|=', 'assignbitor', 20);
- bitwiseassignop('^=', 'assignbitxor', 20);
- bitwiseassignop('<<=', 'assignshiftleft', 20);
- bitwiseassignop('>>=', 'assignshiftright', 20);
- bitwiseassignop('>>>=', 'assignshiftrightunsigned', 20);
- infix('?', function (left, that) {
- that.left = left;
- that.right = expression(10);
- advance(':');
- that['else'] = expression(10);
- return that;
- }, 30);
-
- infix('||', 'or', 40);
- infix('&&', 'and', 50);
- bitwise('|', 'bitor', 70);
- bitwise('^', 'bitxor', 80);
- bitwise('&', 'bitand', 90);
- relation('==', function (left, right) {
- var eqnull = option.eqnull &&
- (left.value == 'null' || right.value == 'null');
-
- if (!eqnull && option.eqeqeq) {
- warning("Expected '{a}' and instead saw '{b}'.",
- this, '===', '==');
- } else if (isPoorRelation(left)) {
- warning("Use '{a}' to compare with '{b}'.",
- this, '===', left.value);
- } else if (isPoorRelation(right)) {
- warning("Use '{a}' to compare with '{b}'.",
- this, '===', right.value);
- }
- return this;
- });
- relation('===');
- relation('!=', function (left, right) {
- var eqnull = option.eqnull &&
- (left.value == 'null' || right.value == 'null');
-
- if (!eqnull && option.eqeqeq) {
- warning("Expected '{a}' and instead saw '{b}'.",
- this, '!==', '!=');
- } else if (isPoorRelation(left)) {
- warning("Use '{a}' to compare with '{b}'.",
- this, '!==', left.value);
- } else if (isPoorRelation(right)) {
- warning("Use '{a}' to compare with '{b}'.",
- this, '!==', right.value);
- }
- return this;
- });
- relation('!==');
- relation('<');
- relation('>');
- relation('<=');
- relation('>=');
- bitwise('<<', 'shiftleft', 120);
- bitwise('>>', 'shiftright', 120);
- bitwise('>>>', 'shiftrightunsigned', 120);
- infix('in', 'in', 120);
- infix('instanceof', 'instanceof', 120);
- infix('+', function (left, that) {
- var right = expression(130);
- if (left && right && left.id === '(string)' && right.id === '(string)') {
- left.value += right.value;
- left.character = right.character;
- if (!option.scripturl && jx.test(left.value)) {
- warning("JavaScript URL.", left);
- }
- return left;
- }
- that.left = left;
- that.right = right;
- return that;
- }, 130);
- prefix('+', 'num');
- prefix('+++', function () {
- warning("Confusing pluses.");
- this.right = expression(150);
- this.arity = 'unary';
- return this;
- });
- infix('+++', function (left) {
- warning("Confusing pluses.");
- this.left = left;
- this.right = expression(130);
- return this;
- }, 130);
- infix('-', 'sub', 130);
- prefix('-', 'neg');
- prefix('---', function () {
- warning("Confusing minuses.");
- this.right = expression(150);
- this.arity = 'unary';
- return this;
- });
- infix('---', function (left) {
- warning("Confusing minuses.");
- this.left = left;
- this.right = expression(130);
- return this;
- }, 130);
- infix('*', 'mult', 140);
- infix('/', 'div', 140);
- infix('%', 'mod', 140);
-
- suffix('++', 'postinc');
- prefix('++', 'preinc');
- syntax['++'].exps = true;
-
- suffix('--', 'postdec');
- prefix('--', 'predec');
- syntax['--'].exps = true;
- prefix('delete', function () {
- var p = expression(0);
- if (!p || (p.id !== '.' && p.id !== '[')) {
- warning("Variables should not be deleted.");
- }
- this.first = p;
- return this;
- }).exps = true;
-
- prefix('~', function () {
- if (option.bitwise) {
- warning("Unexpected '{a}'.", this, '~');
- }
- expression(150);
- return this;
- });
-
- prefix('!', function () {
- this.right = expression(150);
- this.arity = 'unary';
- if (bang[this.right.id] === true) {
- warning("Confusing use of '{a}'.", this, '!');
- }
- return this;
- });
- prefix('typeof', 'typeof');
- prefix('new', function () {
- var c = expression(155), i;
- if (c && c.id !== 'function') {
- if (c.identifier) {
- c['new'] = true;
- switch (c.value) {
- case 'Object':
- warning("Use the object literal notation {}.", token);
- break;
- case 'Number':
- case 'String':
- case 'Boolean':
- case 'Math':
- case 'JSON':
- warning("Do not use {a} as a constructor.", token, c.value);
- break;
- case 'Function':
- if (!option.evil) {
- warning("The Function constructor is eval.");
- }
- break;
- case 'Date':
- case 'RegExp':
- break;
- default:
- if (c.id !== 'function') {
- i = c.value.substr(0, 1);
- if (option.newcap && (i < 'A' || i > 'Z')) {
- warning("A constructor name should start with "+
- "an uppercase letter.", token);
- }
- }
- }
- } else {
- if (c.id !== '.' && c.id !== '[' && c.id !== '(') {
- warning("Bad constructor.", token);
- }
- }
- } else {
- if (!option.supernew)
- warning("Weird construction. Delete 'new'.", this);
- }
- adjacent(token, nexttoken);
- if (nexttoken.id !== '(' && !option.supernew) {
- warning("Missing '()' invoking a constructor.");
- }
- this.first = c;
- return this;
- });
- syntax['new'].exps = true;
-
- prefix('void').exps = true;
-
- infix('.', function (left, that) {
- adjacent(prevtoken, token);
- nobreak();
- var m = identifier();
- if (typeof m === 'string') {
- countMember(m);
- }
- that.left = left;
- that.right = m;
- if (option.noarg && left && left.value === 'arguments' &&
- (m === 'callee' || m === 'caller')) {
- warning("Avoid arguments.{a}.", left, m);
- } else if (!option.evil && left && left.value === 'document' &&
- (m === 'write' || m === 'writeln')) {
- warning("document.write can be a form of eval.", left);
- }
- if (!option.evil && (m === 'eval' || m === 'execScript')) {
- warning('eval is evil.');
- }
- return that;
- }, 160, true);
-
- infix('(', function (left, that) {
- if (prevtoken.id !== '}' && prevtoken.id !== ')') {
- nobreak(prevtoken, token);
- }
- nospace();
- if (option.immed && !left.immed && left.id === 'function') {
- warning("Wrap an immediate function invocation in parentheses " +
- "to assist the reader in understanding that the expression " +
- "is the result of a function, and not the function itself.");
- }
- var n = 0,
- p = [];
- if (left) {
- if (left.type === '(identifier)') {
- if (left.value.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)) {
- if (left.value !== 'Number' && left.value !== 'String' &&
- left.value !== 'Boolean' &&
- left.value !== 'Date') {
- if (left.value === 'Math') {
- warning("Math is not a function.", left);
- } else if (option.newcap) {
- warning(
-"Missing 'new' prefix when invoking a constructor.", left);
- }
- }
- }
- }
- }
- if (nexttoken.id !== ')') {
- for (;;) {
- p[p.length] = expression(10);
- n += 1;
- if (nexttoken.id !== ',') {
- break;
- }
- comma();
- }
- }
- advance(')');
- nospace(prevtoken, token);
- if (typeof left === 'object') {
- if (left.value === 'parseInt' && n === 1) {
- warning("Missing radix parameter.", left);
- }
- if (!option.evil) {
- if (left.value === 'eval' || left.value === 'Function' ||
- left.value === 'execScript') {
- warning("eval is evil.", left);
- } else if (p[0] && p[0].id === '(string)' &&
- (left.value === 'setTimeout' ||
- left.value === 'setInterval')) {
- warning(
- "Implied eval is evil. Pass a function instead of a string.", left);
- }
- }
- if (!left.identifier && left.id !== '.' && left.id !== '[' &&
- left.id !== '(' && left.id !== '&&' && left.id !== '||' &&
- left.id !== '?') {
- warning("Bad invocation.", left);
- }
- }
- that.left = left;
- return that;
- }, 155, true).exps = true;
-
- prefix('(', function () {
- nospace();
- if (nexttoken.id === 'function') {
- nexttoken.immed = true;
- }
- var v = expression(0);
- advance(')', this);
- nospace(prevtoken, token);
- if (option.immed && v.id === 'function') {
- if (nexttoken.id === '(') {
- warning(
-"Move the invocation into the parens that contain the function.", nexttoken);
- } else {
- warning(
+ break;
+ }
+ warning("Unreachable '{a}' after '{b}'.", t, t.value, s);
+ break;
+ }
+ i += 1;
+ }
+ }
+
+
+ function statement(noindent) {
+ var i = indent, r, s = scope, t = nexttoken;
+
+ if (t.id === ";") {
+ advance(";");
+ return;
+ }
+
+ if (t.identifier && !t.reserved && peek().id === ":") {
+ advance();
+ advance(":");
+ scope = Object.create(s);
+ addlabel(t.value, "label");
+
+ if (!nexttoken.labelled && nexttoken.value !== "{") {
+ warning("Label '{a}' on {b} statement.", nexttoken, t.value, nexttoken.value);
+ }
+
+ if (jx.test(t.value + ":")) {
+ warning("Label '{a}' looks like a javascript url.", t, t.value);
+ }
+
+ nexttoken.label = t.value;
+ t = nexttoken;
+ }
+
+ if (t.id === "{") {
+ block(true, true);
+ return;
+ }
+
+ if (!noindent) {
+ indentation();
+ }
+ r = expression(0, true);
+
+ if (!t.block) {
+ if (!option.expr && (!r || !r.exps)) {
+ warning("Expected an assignment or function call and instead saw an expression.",
+ token);
+ } else if (option.nonew && r.id === "(" && r.left.id === "new") {
+ warning("Do not use 'new' for side effects.", t);
+ }
+
+ if (nexttoken.id === ",") {
+ return comma();
+ }
+
+ if (nexttoken.id !== ";") {
+ if (!option.asi) {
+ if (!option.lastsemic || nexttoken.id !== "}" ||
+ nexttoken.line !== token.line) {
+ warningAt("Missing semicolon.", token.line, token.character);
+ }
+ }
+ } else {
+ adjacent(token, nexttoken);
+ advance(";");
+ nonadjacent(token, nexttoken);
+ }
+ }
+
+ indent = i;
+ scope = s;
+ return r;
+ }
+
+
+ function statements(startLine) {
+ var a = [], p;
+
+ while (!nexttoken.reach && nexttoken.id !== "(end)") {
+ if (nexttoken.id === ";") {
+ p = peek();
+ if (!p || p.id !== "(") {
+ warning("Unnecessary semicolon.");
+ }
+ advance(";");
+ } else {
+ a.push(statement(startLine === nexttoken.line));
+ }
+ }
+ return a;
+ }
+ function directives() {
+ var i, p, pn;
+
+ for (;;) {
+ if (nexttoken.id === "(string)") {
+ p = peek(0);
+ if (p.id === "(endline)") {
+ i = 1;
+ do {
+ pn = peek(i);
+ i = i + 1;
+ } while (pn.id === "(endline)");
+
+ if (pn.id !== ";") {
+ if (pn.id !== "(string)" && pn.id !== "(number)" &&
+ pn.id !== "(regexp)" && pn.identifier !== true &&
+ pn.id !== "}") {
+ break;
+ }
+ warning("Missing semicolon.", nexttoken);
+ } else {
+ p = pn;
+ }
+ } else if (p.id === "}") {
+ warning("Missing semicolon.", p);
+ } else if (p.id !== ";") {
+ break;
+ }
+
+ indentation();
+ advance();
+ if (directive[token.value]) {
+ warning("Unnecessary directive \"{a}\".", token, token.value);
+ }
+
+ if (token.value === "use strict") {
+ if (!option["(explicitNewcap)"])
+ option.newcap = true;
+ option.undef = true;
+ }
+ directive[token.value] = true;
+
+ if (p.id === ";") {
+ advance(";");
+ }
+ continue;
+ }
+ break;
+ }
+ }
+ function block(ordinary, stmt, isfunc) {
+ var a,
+ b = inblock,
+ old_indent = indent,
+ m,
+ s = scope,
+ t,
+ line,
+ d;
+
+ inblock = ordinary;
+
+ if (!ordinary || !option.funcscope)
+ scope = Object.create(scope);
+
+ nonadjacent(token, nexttoken);
+ t = nexttoken;
+
+ var metrics = funct["(metrics)"];
+ metrics.nestedBlockDepth += 1;
+ metrics.verifyMaxNestedBlockDepthPerFunction();
+
+ if (nexttoken.id === "{") {
+ advance("{");
+ line = token.line;
+ if (nexttoken.id !== "}") {
+ indent += option.indent;
+ while (!ordinary && nexttoken.from > indent) {
+ indent += option.indent;
+ }
+
+ if (isfunc) {
+ m = {};
+ for (d in directive) {
+ if (is_own(directive, d)) {
+ m[d] = directive[d];
+ }
+ }
+ directives();
+
+ if (option.strict && funct["(context)"]["(global)"]) {
+ if (!m["use strict"] && !directive["use strict"]) {
+ warning("Missing \"use strict\" statement.");
+ }
+ }
+ }
+
+ a = statements(line);
+
+ metrics.statementCount += a.length;
+
+ if (isfunc) {
+ directive = m;
+ }
+
+ indent -= option.indent;
+ if (line !== nexttoken.line) {
+ indentation();
+ }
+ } else if (line !== nexttoken.line) {
+ indentation();
+ }
+ advance("}", t);
+ indent = old_indent;
+ } else if (!ordinary) {
+ error("Expected '{a}' and instead saw '{b}'.",
+ nexttoken, "{", nexttoken.value);
+ } else {
+ if (!stmt || option.curly)
+ warning("Expected '{a}' and instead saw '{b}'.",
+ nexttoken, "{", nexttoken.value);
+
+ noreach = true;
+ indent += option.indent;
+ a = [statement(nexttoken.line === token.line)];
+ indent -= option.indent;
+ noreach = false;
+ }
+ funct["(verb)"] = null;
+ if (!ordinary || !option.funcscope) scope = s;
+ inblock = b;
+ if (ordinary && option.noempty && (!a || a.length === 0)) {
+ warning("Empty block.");
+ }
+ metrics.nestedBlockDepth -= 1;
+ return a;
+ }
+
+
+ function countMember(m) {
+ if (membersOnly && typeof membersOnly[m] !== "boolean") {
+ warning("Unexpected /*member '{a}'.", token, m);
+ }
+ if (typeof member[m] === "number") {
+ member[m] += 1;
+ } else {
+ member[m] = 1;
+ }
+ }
+
+
+ function note_implied(token) {
+ var name = token.value, line = token.line, a = implied[name];
+ if (typeof a === "function") {
+ a = false;
+ }
+
+ if (!a) {
+ a = [line];
+ implied[name] = a;
+ } else if (a[a.length - 1] !== line) {
+ a.push(line);
+ }
+ }
+
+ type("(number)", function () {
+ return this;
+ });
+
+ type("(string)", function () {
+ return this;
+ });
+
+ syntax["(identifier)"] = {
+ type: "(identifier)",
+ lbp: 0,
+ identifier: true,
+ nud: function () {
+ var v = this.value,
+ s = scope[v],
+ f;
+
+ if (typeof s === "function") {
+ s = undefined;
+ } else if (typeof s === "boolean") {
+ f = funct;
+ funct = functions[0];
+ addlabel(v, "var");
+ s = funct;
+ funct = f;
+ }
+ if (funct === s) {
+ switch (funct[v]) {
+ case "unused":
+ funct[v] = "var";
+ break;
+ case "unction":
+ funct[v] = "function";
+ this["function"] = true;
+ break;
+ case "function":
+ this["function"] = true;
+ break;
+ case "label":
+ warning("'{a}' is a statement label.", token, v);
+ break;
+ }
+ } else if (funct["(global)"]) {
+
+ if (option.undef && typeof predefined[v] !== "boolean") {
+ if (!(anonname === "typeof" || anonname === "delete") ||
+ (nexttoken && (nexttoken.value === "." || nexttoken.value === "["))) {
+
+ isundef(funct, "'{a}' is not defined.", token, v);
+ }
+ }
+
+ note_implied(token);
+ } else {
+
+ switch (funct[v]) {
+ case "closure":
+ case "function":
+ case "var":
+ case "unused":
+ warning("'{a}' used out of scope.", token, v);
+ break;
+ case "label":
+ warning("'{a}' is a statement label.", token, v);
+ break;
+ case "outer":
+ case "global":
+ break;
+ default:
+ if (s === true) {
+ funct[v] = true;
+ } else if (s === null) {
+ warning("'{a}' is not allowed.", token, v);
+ note_implied(token);
+ } else if (typeof s !== "object") {
+ if (option.undef) {
+ if (!(anonname === "typeof" || anonname === "delete") ||
+ (nexttoken &&
+ (nexttoken.value === "." || nexttoken.value === "["))) {
+
+ isundef(funct, "'{a}' is not defined.", token, v);
+ }
+ }
+ funct[v] = true;
+ note_implied(token);
+ } else {
+ switch (s[v]) {
+ case "function":
+ case "unction":
+ this["function"] = true;
+ s[v] = "closure";
+ funct[v] = s["(global)"] ? "global" : "outer";
+ break;
+ case "var":
+ case "unused":
+ s[v] = "closure";
+ funct[v] = s["(global)"] ? "global" : "outer";
+ break;
+ case "closure":
+ funct[v] = s["(global)"] ? "global" : "outer";
+ break;
+ case "label":
+ warning("'{a}' is a statement label.", token, v);
+ }
+ }
+ }
+ }
+ return this;
+ },
+ led: function () {
+ error("Expected an operator and instead saw '{a}'.",
+ nexttoken, nexttoken.value);
+ }
+ };
+
+ type("(regexp)", function () {
+ return this;
+ });
+
+ delim("(endline)");
+ delim("(begin)");
+ delim("(end)").reach = true;
+ delim("</").reach = true;
+ delim("<!");
+ delim("<!--");
+ delim("-->");
+ delim("(error)").reach = true;
+ delim("}").reach = true;
+ delim(")");
+ delim("]");
+ delim("\"").reach = true;
+ delim("'").reach = true;
+ delim(";");
+ delim(":").reach = true;
+ delim(",");
+ delim("#");
+ delim("@");
+ reserve("else");
+ reserve("case").reach = true;
+ reserve("catch");
+ reserve("default").reach = true;
+ reserve("finally");
+ reservevar("arguments", function (x) {
+ if (directive["use strict"] && funct["(global)"]) {
+ warning("Strict violation.", x);
+ }
+ });
+ reservevar("eval");
+ reservevar("false");
+ reservevar("Infinity");
+ reservevar("null");
+ reservevar("this", function (x) {
+ if (directive["use strict"] && !option.validthis && ((funct["(statement)"] &&
+ funct["(name)"].charAt(0) > "Z") || funct["(global)"])) {
+ warning("Possible strict violation.", x);
+ }
+ });
+ reservevar("true");
+ reservevar("undefined");
+ assignop("=", "assign", 20);
+ assignop("+=", "assignadd", 20);
+ assignop("-=", "assignsub", 20);
+ assignop("*=", "assignmult", 20);
+ assignop("/=", "assigndiv", 20).nud = function () {
+ error("A regular expression literal can be confused with '/='.");
+ };
+ assignop("%=", "assignmod", 20);
+ bitwiseassignop("&=", "assignbitand", 20);
+ bitwiseassignop("|=", "assignbitor", 20);
+ bitwiseassignop("^=", "assignbitxor", 20);
+ bitwiseassignop("<<=", "assignshiftleft", 20);
+ bitwiseassignop(">>=", "assignshiftright", 20);
+ bitwiseassignop(">>>=", "assignshiftrightunsigned", 20);
+ infix("?", function (left, that) {
+ that.left = left;
+ that.right = expression(10);
+ advance(":");
+ that["else"] = expression(10);
+ return that;
+ }, 30);
+
+ infix("||", "or", 40);
+ infix("&&", "and", 50);
+ bitwise("|", "bitor", 70);
+ bitwise("^", "bitxor", 80);
+ bitwise("&", "bitand", 90);
+ relation("==", function (left, right) {
+ var eqnull = option.eqnull && (left.value === "null" || right.value === "null");
+
+ if (!eqnull && option.eqeqeq)
+ warning("Expected '{a}' and instead saw '{b}'.", this, "===", "==");
+ else if (isPoorRelation(left))
+ warning("Use '{a}' to compare with '{b}'.", this, "===", left.value);
+ else if (isPoorRelation(right))
+ warning("Use '{a}' to compare with '{b}'.", this, "===", right.value);
+
+ return this;
+ });
+ relation("===");
+ relation("!=", function (left, right) {
+ var eqnull = option.eqnull &&
+ (left.value === "null" || right.value === "null");
+
+ if (!eqnull && option.eqeqeq) {
+ warning("Expected '{a}' and instead saw '{b}'.",
+ this, "!==", "!=");
+ } else if (isPoorRelation(left)) {
+ warning("Use '{a}' to compare with '{b}'.",
+ this, "!==", left.value);
+ } else if (isPoorRelation(right)) {
+ warning("Use '{a}' to compare with '{b}'.",
+ this, "!==", right.value);
+ }
+ return this;
+ });
+ relation("!==");
+ relation("<");
+ relation(">");
+ relation("<=");
+ relation(">=");
+ bitwise("<<", "shiftleft", 120);
+ bitwise(">>", "shiftright", 120);
+ bitwise(">>>", "shiftrightunsigned", 120);
+ infix("in", "in", 120);
+ infix("instanceof", "instanceof", 120);
+ infix("+", function (left, that) {
+ var right = expression(130);
+ if (left && right && left.id === "(string)" && right.id === "(string)") {
+ left.value += right.value;
+ left.character = right.character;
+ if (!option.scripturl && jx.test(left.value)) {
+ warning("JavaScript URL.", left);
+ }
+ return left;
+ }
+ that.left = left;
+ that.right = right;
+ return that;
+ }, 130);
+ prefix("+", "num");
+ prefix("+++", function () {
+ warning("Confusing pluses.");
+ this.right = expression(150);
+ this.arity = "unary";
+ return this;
+ });
+ infix("+++", function (left) {
+ warning("Confusing pluses.");
+ this.left = left;
+ this.right = expression(130);
+ return this;
+ }, 130);
+ infix("-", "sub", 130);
+ prefix("-", "neg");
+ prefix("---", function () {
+ warning("Confusing minuses.");
+ this.right = expression(150);
+ this.arity = "unary";
+ return this;
+ });
+ infix("---", function (left) {
+ warning("Confusing minuses.");
+ this.left = left;
+ this.right = expression(130);
+ return this;
+ }, 130);
+ infix("*", "mult", 140);
+ infix("/", "div", 140);
+ infix("%", "mod", 140);
+
+ suffix("++", "postinc");
+ prefix("++", "preinc");
+ syntax["++"].exps = true;
+
+ suffix("--", "postdec");
+ prefix("--", "predec");
+ syntax["--"].exps = true;
+ prefix("delete", function () {
+ var p = expression(0);
+ if (!p || (p.id !== "." && p.id !== "[")) {
+ warning("Variables should not be deleted.");
+ }
+ this.first = p;
+ return this;
+ }).exps = true;
+
+ prefix("~", function () {
+ if (option.bitwise) {
+ warning("Unexpected '{a}'.", this, "~");
+ }
+ expression(150);
+ return this;
+ });
+
+ prefix("!", function () {
+ this.right = expression(150);
+ this.arity = "unary";
+ if (bang[this.right.id] === true) {
+ warning("Confusing use of '{a}'.", this, "!");
+ }
+ return this;
+ });
+ prefix("typeof", "typeof");
+ prefix("new", function () {
+ var c = expression(155), i;
+ if (c && c.id !== "function") {
+ if (c.identifier) {
+ c["new"] = true;
+ switch (c.value) {
+ case "Number":
+ case "String":
+ case "Boolean":
+ case "Math":
+ case "JSON":
+ warning("Do not use {a} as a constructor.", prevtoken, c.value);
+ break;
+ case "Function":
+ if (!option.evil) {
+ warning("The Function constructor is eval.");
+ }
+ break;
+ case "Date":
+ case "RegExp":
+ break;
+ default:
+ if (c.id !== "function") {
+ i = c.value.substr(0, 1);
+ if (option.newcap && (i < "A" || i > "Z") && !is_own(global, c.value)) {
+ warning("A constructor name should start with an uppercase letter.",
+ token);
+ }
+ }
+ }
+ } else {
+ if (c.id !== "." && c.id !== "[" && c.id !== "(") {
+ warning("Bad constructor.", token);
+ }
+ }
+ } else {
+ if (!option.supernew)
+ warning("Weird construction. Delete 'new'.", this);
+ }
+ adjacent(token, nexttoken);
+ if (nexttoken.id !== "(" && !option.supernew) {
+ warning("Missing '()' invoking a constructor.",
+ token, token.value);
+ }
+ this.first = c;
+ return this;
+ });
+ syntax["new"].exps = true;
+
+ prefix("void").exps = true;
+
+ infix(".", function (left, that) {
+ adjacent(prevtoken, token);
+ nobreak();
+ var m = identifier();
+ if (typeof m === "string") {
+ countMember(m);
+ }
+ that.left = left;
+ that.right = m;
+ if (left && left.value === "arguments" && (m === "callee" || m === "caller")) {
+ if (option.noarg)
+ warning("Avoid arguments.{a}.", left, m);
+ else if (directive["use strict"])
+ error("Strict violation.");
+ } else if (!option.evil && left && left.value === "document" &&
+ (m === "write" || m === "writeln")) {
+ warning("document.write can be a form of eval.", left);
+ }
+ if (!option.evil && (m === "eval" || m === "execScript")) {
+ warning("eval is evil.");
+ }
+ return that;
+ }, 160, true);
+
+ infix("(", function (left, that) {
+ if (prevtoken.id !== "}" && prevtoken.id !== ")") {
+ nobreak(prevtoken, token);
+ }
+ nospace();
+ if (option.immed && !left.immed && left.id === "function") {
+ warning("Wrap an immediate function invocation in parentheses " +
+ "to assist the reader in understanding that the expression " +
+ "is the result of a function, and not the function itself.");
+ }
+ var n = 0,
+ p = [];
+ if (left) {
+ if (left.type === "(identifier)") {
+ if (left.value.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)) {
+ if ("Number String Boolean Date Object".indexOf(left.value) === -1) {
+ if (left.value === "Math") {
+ warning("Math is not a function.", left);
+ } else if (option.newcap) {
+ warning("Missing 'new' prefix when invoking a constructor.", left);
+ }
+ }
+ }
+ }
+ }
+ if (nexttoken.id !== ")") {
+ for (;;) {
+ p[p.length] = expression(10);
+ n += 1;
+ if (nexttoken.id !== ",") {
+ break;
+ }
+ comma();
+ }
+ }
+ advance(")");
+ nospace(prevtoken, token);
+ if (typeof left === "object") {
+ if (left.value === "parseInt" && n === 1) {
+ warning("Missing radix parameter.", token);
+ }
+ if (!option.evil) {
+ if (left.value === "eval" || left.value === "Function" ||
+ left.value === "execScript") {
+ warning("eval is evil.", left);
+
+ if (p[0] && [0].id === "(string)") {
+ addInternalSrc(left, p[0].value);
+ }
+ } else if (p[0] && p[0].id === "(string)" &&
+ (left.value === "setTimeout" ||
+ left.value === "setInterval")) {
+ warning(
+ "Implied eval is evil. Pass a function instead of a string.", left);
+ addInternalSrc(left, p[0].value);
+ } else if (p[0] && p[0].id === "(string)" &&
+ left.value === "." &&
+ left.left.value === "window" &&
+ (left.right === "setTimeout" ||
+ left.right === "setInterval")) {
+ warning(
+ "Implied eval is evil. Pass a function instead of a string.", left);
+ addInternalSrc(left, p[0].value);
+ }
+ }
+ if (!left.identifier && left.id !== "." && left.id !== "[" &&
+ left.id !== "(" && left.id !== "&&" && left.id !== "||" &&
+ left.id !== "?") {
+ warning("Bad invocation.", left);
+ }
+ }
+ that.left = left;
+ return that;
+ }, 155, true).exps = true;
+
+ prefix("(", function () {
+ nospace();
+ if (nexttoken.id === "function") {
+ nexttoken.immed = true;
+ }
+ var v = expression(0);
+ advance(")", this);
+ nospace(prevtoken, token);
+ if (option.immed && v.id === "function") {
+ if (nexttoken.id !== "(" &&
+ (nexttoken.id !== "." || (peek().value !== "call" && peek().value !== "apply"))) {
+ warning(
"Do not wrap function literals in parens unless they are to be immediately invoked.",
- this);
- }
- }
- return v;
- });
-
- infix('[', function (left, that) {
- nobreak(prevtoken, token);
- nospace();
- var e = expression(0), s;
- if (e && e.type === '(string)') {
- if (!option.evil && (e.value === 'eval' || e.value === 'execScript')) {
- warning("eval is evil.", that);
- }
- countMember(e.value);
- if (!option.sub && ix.test(e.value)) {
- s = syntax[e.value];
- if (!s || !s.reserved) {
- warning("['{a}'] is better written in dot notation.",
- e, e.value);
- }
- }
- }
- advance(']', that);
- nospace(prevtoken, token);
- that.left = left;
- that.right = e;
- return that;
- }, 160, true);
-
- prefix('[', function () {
- var b = token.line !== nexttoken.line;
- this.first = [];
- if (b) {
- indent += option.indent;
- if (nexttoken.from === indent + option.indent) {
- indent += option.indent;
- }
- }
- while (nexttoken.id !== '(end)') {
- while (nexttoken.id === ',') {
- warning("Extra comma.");
- advance(',');
- }
- if (nexttoken.id === ']') {
- break;
- }
- if (b && token.line !== nexttoken.line) {
- indentation();
- }
- this.first.push(expression(10));
- if (nexttoken.id === ',') {
- comma();
- if (nexttoken.id === ']' && !option.es5) {
- warning("Extra comma.", token);
- break;
- }
- } else {
- break;
- }
- }
- if (b) {
- indent -= option.indent;
- indentation();
- }
- advance(']', this);
- return this;
- }, 160);
-
-
- function property_name() {
- var id = optionalidentifier(true);
- if (!id) {
- if (nexttoken.id === '(string)') {
- id = nexttoken.value;
- advance();
- } else if (nexttoken.id === '(number)') {
- id = nexttoken.value.toString();
- advance();
- }
- }
- return id;
- }
-
-
- function functionparams() {
- var i, t = nexttoken, p = [];
- advance('(');
- nospace();
- if (nexttoken.id === ')') {
- advance(')');
- nospace(prevtoken, token);
- return;
- }
- for (;;) {
- i = identifier(true);
- p.push(i);
- addlabel(i, 'parameter');
- if (nexttoken.id === ',') {
- comma();
- } else {
- advance(')', t);
- nospace(prevtoken, token);
- return p;
- }
- }
- }
-
-
- function doFunction(i, statement) {
- var f,
- oldOption = option,
- oldScope = scope;
-
- option = Object.create(option);
- scope = Object.create(scope);
-
- funct = {
- '(name)' : i || '"' + anonname + '"',
- '(line)' : nexttoken.line,
- '(context)' : funct,
- '(breakage)' : 0,
- '(loopage)' : 0,
- '(scope)' : scope,
- '(statement)': statement
- };
- f = funct;
- token.funct = funct;
- functions.push(funct);
- if (i) {
- addlabel(i, 'function');
- }
- funct['(params)'] = functionparams();
-
- block(false);
- scope = oldScope;
- option = oldOption;
- funct['(last)'] = token.line;
- funct = funct['(context)'];
- return f;
- }
-
-
- (function (x) {
- x.nud = function () {
- var b, f, i, j, p, seen = {}, t;
-
- b = token.line !== nexttoken.line;
- if (b) {
- indent += option.indent;
- if (nexttoken.from === indent + option.indent) {
- indent += option.indent;
- }
- }
- for (;;) {
- if (nexttoken.id === '}') {
- break;
- }
- if (b) {
- indentation();
- }
- if (nexttoken.value === 'get' && peek().id !== ':') {
- advance('get');
- if (!option.es5) {
- error("get/set are ES5 features.");
- }
- i = property_name();
- if (!i) {
- error("Missing property name.");
- }
- t = nexttoken;
- adjacent(token, nexttoken);
- f = doFunction();
- if (!option.loopfunc && funct['(loopage)']) {
- warning("Don't make functions within a loop.", t);
- }
- p = f['(params)'];
- if (p) {
- warning("Unexpected parameter '{a}' in get {b} function.", t, p[0], i);
- }
- adjacent(token, nexttoken);
- advance(',');
- indentation();
- advance('set');
- j = property_name();
- if (i !== j) {
- error("Expected {a} and instead saw {b}.", token, i, j);
- }
- t = nexttoken;
- adjacent(token, nexttoken);
- f = doFunction();
- p = f['(params)'];
- if (!p || p.length !== 1 || p[0] !== 'value') {
- warning("Expected (value) in set {a} function.", t, i);
- }
- } else {
- i = property_name();
- if (typeof i !== 'string') {
- break;
- }
- advance(':');
- nonadjacent(token, nexttoken);
- expression(10);
- }
- if (seen[i] === true) {
- warning("Duplicate member '{a}'.", nexttoken, i);
- }
- seen[i] = true;
- countMember(i);
- if (nexttoken.id === ',') {
- comma();
- if (nexttoken.id === ',') {
- warning("Extra comma.", token);
- } else if (nexttoken.id === '}' && !option.es5) {
- warning("Extra comma.", token);
- }
- } else {
- break;
- }
- }
- if (b) {
- indent -= option.indent;
- indentation();
- }
- advance('}', this);
- return this;
- };
- x.fud = function () {
- error("Expected to see a statement and instead saw a block.", token);
- };
- }(delim('{')));
-
- var varstatement = stmt('var', function (prefix) {
- // JavaScript does not have block scope. It only has function scope. So,
- // declaring a variable in a block can have unexpected consequences.
- var id, name, value;
-
- if (funct['(onevar)'] && option.onevar) {
- warning("Too many var statements.");
- } else if (!funct['(global)']) {
- funct['(onevar)'] = true;
- }
- this.first = [];
- for (;;) {
- nonadjacent(token, nexttoken);
- id = identifier();
- if (funct['(global)'] && predefined[id] === false) {
- warning("Redefinition of '{a}'.", token, id);
- }
- addlabel(id, 'unused');
- if (prefix) {
- break;
- }
- name = token;
- this.first.push(token);
- if (nexttoken.id === '=') {
- nonadjacent(token, nexttoken);
- advance('=');
- nonadjacent(token, nexttoken);
- if (nexttoken.id === 'undefined') {
- warning("It is not necessary to initialize '{a}' to 'undefined'.", token, id);
- }
- if (peek(0).id === '=' && nexttoken.identifier) {
- error("Variable {a} was not declared correctly.",
- nexttoken, nexttoken.value);
- }
- value = expression(0);
- name.first = value;
- }
- if (nexttoken.id !== ',') {
- break;
- }
- comma();
- }
- return this;
- });
- varstatement.exps = true;
-
- blockstmt('function', function () {
- if (inblock) {
- warning("Function declarations should not be placed in blocks. " +
- "Use a function expression or move the statement to the top of " +
- "the outer function.", token);
-
- }
- var i = identifier();
- adjacent(token, nexttoken);
- addlabel(i, 'unction');
- doFunction(i, true);
- if (nexttoken.id === '(' && nexttoken.line === token.line) {
- error(
+ this);
+ }
+ }
+
+ return v;
+ });
+
+ infix("[", function (left, that) {
+ nobreak(prevtoken, token);
+ nospace();
+ var e = expression(0), s;
+ if (e && e.type === "(string)") {
+ if (!option.evil && (e.value === "eval" || e.value === "execScript")) {
+ warning("eval is evil.", that);
+ }
+ countMember(e.value);
+ if (!option.sub && ix.test(e.value)) {
+ s = syntax[e.value];
+ if (!s || !s.reserved) {
+ warning("['{a}'] is better written in dot notation.",
+ prevtoken, e.value);
+ }
+ }
+ }
+ advance("]", that);
+ nospace(prevtoken, token);
+ that.left = left;
+ that.right = e;
+ return that;
+ }, 160, true);
+
+ prefix("[", function () {
+ var b = token.line !== nexttoken.line;
+ this.first = [];
+ if (b) {
+ indent += option.indent;
+ if (nexttoken.from === indent + option.indent) {
+ indent += option.indent;
+ }
+ }
+ while (nexttoken.id !== "(end)") {
+ while (nexttoken.id === ",") {
+ if (!option.es5)
+ warning("Extra comma.");
+ advance(",");
+ }
+ if (nexttoken.id === "]") {
+ break;
+ }
+ if (b && token.line !== nexttoken.line) {
+ indentation();
+ }
+ this.first.push(expression(10));
+ if (nexttoken.id === ",") {
+ comma();
+ if (nexttoken.id === "]" && !option.es5) {
+ warning("Extra comma.", token);
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ if (b) {
+ indent -= option.indent;
+ indentation();
+ }
+ advance("]", this);
+ return this;
+ }, 160);
+
+
+ function property_name() {
+ var id = optionalidentifier(true);
+ if (!id) {
+ if (nexttoken.id === "(string)") {
+ id = nexttoken.value;
+ advance();
+ } else if (nexttoken.id === "(number)") {
+ id = nexttoken.value.toString();
+ advance();
+ }
+ }
+ return id;
+ }
+
+
+ function functionparams() {
+ var next = nexttoken;
+ var params = [];
+ var ident;
+
+ advance("(");
+ nospace();
+
+ if (nexttoken.id === ")") {
+ advance(")");
+ return;
+ }
+
+ for (;;) {
+ ident = identifier(true);
+ params.push(ident);
+ addlabel(ident, "unused", token);
+ if (nexttoken.id === ",") {
+ comma();
+ } else {
+ advance(")", next);
+ nospace(prevtoken, token);
+ return params;
+ }
+ }
+ }
+
+
+ function doFunction(name, statement) {
+ var f;
+ var oldOption = option;
+ var oldScope = scope;
+
+ option = Object.create(option);
+ scope = Object.create(scope);
+
+ funct = {
+ "(name)" : name || "\"" + anonname + "\"",
+ "(line)" : nexttoken.line,
+ "(character)": nexttoken.character,
+ "(context)" : funct,
+ "(breakage)" : 0,
+ "(loopage)" : 0,
+ "(metrics)" : createMetrics(nexttoken),
+ "(scope)" : scope,
+ "(statement)": statement,
+ "(tokens)" : {}
+ };
+
+ f = funct;
+ token.funct = funct;
+
+ functions.push(funct);
+
+ if (name) {
+ addlabel(name, "function");
+ }
+
+ funct["(params)"] = functionparams();
+ funct["(metrics)"].verifyMaxParametersPerFunction(funct["(params)"]);
+
+ block(false, false, true);
+
+ funct["(metrics)"].verifyMaxStatementsPerFunction();
+ funct["(metrics)"].verifyMaxComplexityPerFunction();
+
+ scope = oldScope;
+ option = oldOption;
+ funct["(last)"] = token.line;
+ funct["(lastcharacter)"] = token.character;
+ funct = funct["(context)"];
+
+ return f;
+ }
+
+ function createMetrics(functionStartToken) {
+ return {
+ statementCount: 0,
+ nestedBlockDepth: -1,
+ ComplexityCount: 1,
+ verifyMaxStatementsPerFunction: function () {
+ if (option.maxstatements &&
+ this.statementCount > option.maxstatements) {
+ var message = "Too many statements per function (" + this.statementCount + ").";
+ warning(message, functionStartToken);
+ }
+ },
+
+ verifyMaxParametersPerFunction: function (params) {
+ params = params || [];
+
+ if (option.maxparams && params.length > option.maxparams) {
+ var message = "Too many parameters per function (" + params.length + ").";
+ warning(message, functionStartToken);
+ }
+ },
+
+ verifyMaxNestedBlockDepthPerFunction: function () {
+ if (option.maxdepth &&
+ this.nestedBlockDepth > 0 &&
+ this.nestedBlockDepth === option.maxdepth + 1) {
+ var message = "Blocks are nested too deeply (" + this.nestedBlockDepth + ").";
+ warning(message);
+ }
+ },
+
+ verifyMaxComplexityPerFunction: function () {
+ var max = option.maxcomplexity;
+ var cc = this.ComplexityCount;
+ if (max && cc > max) {
+ var message = "Cyclomatic complexity is too high per function (" + cc + ").";
+ warning(message, functionStartToken);
+ }
+ }
+ };
+ }
+
+ function increaseComplexityCount() {
+ funct["(metrics)"].ComplexityCount += 1;
+ }
+
+
+ (function (x) {
+ x.nud = function () {
+ var b, f, i, p, t;
+ var props = {}; // All properties, including accessors
+
+ function saveProperty(name, token) {
+ if (props[name] && is_own(props, name))
+ warning("Duplicate member '{a}'.", nexttoken, i);
+ else
+ props[name] = {};
+
+ props[name].basic = true;
+ props[name].basicToken = token;
+ }
+
+ function saveSetter(name, token) {
+ if (props[name] && is_own(props, name)) {
+ if (props[name].basic || props[name].setter)
+ warning("Duplicate member '{a}'.", nexttoken, i);
+ } else {
+ props[name] = {};
+ }
+
+ props[name].setter = true;
+ props[name].setterToken = token;
+ }
+
+ function saveGetter(name) {
+ if (props[name] && is_own(props, name)) {
+ if (props[name].basic || props[name].getter)
+ warning("Duplicate member '{a}'.", nexttoken, i);
+ } else {
+ props[name] = {};
+ }
+
+ props[name].getter = true;
+ props[name].getterToken = token;
+ }
+
+ b = token.line !== nexttoken.line;
+ if (b) {
+ indent += option.indent;
+ if (nexttoken.from === indent + option.indent) {
+ indent += option.indent;
+ }
+ }
+ for (;;) {
+ if (nexttoken.id === "}") {
+ break;
+ }
+ if (b) {
+ indentation();
+ }
+ if (nexttoken.value === "get" && peek().id !== ":") {
+ advance("get");
+ if (!option.es5) {
+ error("get/set are ES5 features.");
+ }
+ i = property_name();
+ if (!i) {
+ error("Missing property name.");
+ }
+ saveGetter(i);
+ t = nexttoken;
+ adjacent(token, nexttoken);
+ f = doFunction();
+ p = f["(params)"];
+ if (p) {
+ warning("Unexpected parameter '{a}' in get {b} function.", t, p[0], i);
+ }
+ adjacent(token, nexttoken);
+ } else if (nexttoken.value === "set" && peek().id !== ":") {
+ advance("set");
+ if (!option.es5) {
+ error("get/set are ES5 features.");
+ }
+ i = property_name();
+ if (!i) {
+ error("Missing property name.");
+ }
+ saveSetter(i, nexttoken);
+ t = nexttoken;
+ adjacent(token, nexttoken);
+ f = doFunction();
+ p = f["(params)"];
+ if (!p || p.length !== 1) {
+ warning("Expected a single parameter in set {a} function.", t, i);
+ }
+ } else {
+ i = property_name();
+ saveProperty(i, nexttoken);
+ if (typeof i !== "string") {
+ break;
+ }
+ advance(":");
+ nonadjacent(token, nexttoken);
+ expression(10);
+ }
+
+ countMember(i);
+ if (nexttoken.id === ",") {
+ comma();
+ if (nexttoken.id === ",") {
+ warning("Extra comma.", token);
+ } else if (nexttoken.id === "}" && !option.es5) {
+ warning("Extra comma.", token);
+ }
+ } else {
+ break;
+ }
+ }
+ if (b) {
+ indent -= option.indent;
+ indentation();
+ }
+ advance("}", this);
+ if (option.es5) {
+ for (var name in props) {
+ if (is_own(props, name) && props[name].setter && !props[name].getter) {
+ warning("Setter is defined without getter.", props[name].setterToken);
+ }
+ }
+ }
+ return this;
+ };
+ x.fud = function () {
+ error("Expected to see a statement and instead saw a block.", token);
+ };
+ }(delim("{")));
+
+ useESNextSyntax = function () {
+ var conststatement = stmt("const", function (prefix) {
+ var id, name, value;
+
+ this.first = [];
+ for (;;) {
+ nonadjacent(token, nexttoken);
+ id = identifier();
+ if (funct[id] === "const") {
+ warning("const '" + id + "' has already been declared");
+ }
+ if (funct["(global)"] && predefined[id] === false) {
+ warning("Redefinition of '{a}'.", token, id);
+ }
+ addlabel(id, "const");
+ if (prefix) {
+ break;
+ }
+ name = token;
+ this.first.push(token);
+
+ if (nexttoken.id !== "=") {
+ warning("const " +
+ "'{a}' is initialized to 'undefined'.", token, id);
+ }
+
+ if (nexttoken.id === "=") {
+ nonadjacent(token, nexttoken);
+ advance("=");
+ nonadjacent(token, nexttoken);
+ if (nexttoken.id === "undefined") {
+ warning("It is not necessary to initialize " +
+ "'{a}' to 'undefined'.", token, id);
+ }
+ if (peek(0).id === "=" && nexttoken.identifier) {
+ error("Constant {a} was not declared correctly.",
+ nexttoken, nexttoken.value);
+ }
+ value = expression(0);
+ name.first = value;
+ }
+
+ if (nexttoken.id !== ",") {
+ break;
+ }
+ comma();
+ }
+ return this;
+ });
+ conststatement.exps = true;
+ };
+
+ var varstatement = stmt("var", function (prefix) {
+ var id, name, value;
+
+ if (funct["(onevar)"] && option.onevar) {
+ warning("Too many var statements.");
+ } else if (!funct["(global)"]) {
+ funct["(onevar)"] = true;
+ }
+
+ this.first = [];
+
+ for (;;) {
+ nonadjacent(token, nexttoken);
+ id = identifier();
+
+ if (option.esnext && funct[id] === "const") {
+ warning("const '" + id + "' has already been declared");
+ }
+
+ if (funct["(global)"] && predefined[id] === false) {
+ warning("Redefinition of '{a}'.", token, id);
+ }
+
+ addlabel(id, "unused", token);
+
+ if (prefix) {
+ break;
+ }
+
+ name = token;
+ this.first.push(token);
+
+ if (nexttoken.id === "=") {
+ nonadjacent(token, nexttoken);
+ advance("=");
+ nonadjacent(token, nexttoken);
+ if (nexttoken.id === "undefined") {
+ warning("It is not necessary to initialize '{a}' to 'undefined'.", token, id);
+ }
+ if (peek(0).id === "=" && nexttoken.identifier) {
+ error("Variable {a} was not declared correctly.",
+ nexttoken, nexttoken.value);
+ }
+ value = expression(0);
+ name.first = value;
+ }
+ if (nexttoken.id !== ",") {
+ break;
+ }
+ comma();
+ }
+ return this;
+ });
+ varstatement.exps = true;
+
+ blockstmt("function", function () {
+ if (inblock) {
+ warning("Function declarations should not be placed in blocks. " +
+ "Use a function expression or move the statement to the top of " +
+ "the outer function.", token);
+
+ }
+ var i = identifier();
+ if (option.esnext && funct[i] === "const") {
+ warning("const '" + i + "' has already been declared");
+ }
+ adjacent(token, nexttoken);
+ addlabel(i, "unction", token);
+
+ doFunction(i, { statement: true });
+ if (nexttoken.id === "(" && nexttoken.line === token.line) {
+ error(
"Function declarations are not invocable. Wrap the whole function invocation in parens.");
- }
- return this;
- });
-
- prefix('function', function () {
- var i = optionalidentifier();
- if (i) {
- adjacent(token, nexttoken);
- } else {
- nonadjacent(token, nexttoken);
- }
- doFunction(i);
- if (!option.loopfunc && funct['(loopage)']) {
- warning("Don't make functions within a loop.");
- }
- return this;
- });
-
- blockstmt('if', function () {
- var t = nexttoken;
- advance('(');
- nonadjacent(this, t);
- nospace();
- expression(20);
- if (nexttoken.id === '=') {
- if (!option.boss)
- warning("Expected a conditional expression and instead saw an assignment.");
- advance('=');
- expression(20);
- }
- advance(')', t);
- nospace(prevtoken, token);
- block(true, true);
- if (nexttoken.id === 'else') {
- nonadjacent(token, nexttoken);
- advance('else');
- if (nexttoken.id === 'if' || nexttoken.id === 'switch') {
- statement(true);
- } else {
- block(true, true);
- }
- }
- return this;
- });
-
- blockstmt('try', function () {
- var b, e, s;
-
- block(false);
- if (nexttoken.id === 'catch') {
- advance('catch');
- nonadjacent(token, nexttoken);
- advance('(');
- s = scope;
- scope = Object.create(s);
- e = nexttoken.value;
- if (nexttoken.type !== '(identifier)') {
- warning("Expected an identifier and instead saw '{a}'.",
- nexttoken, e);
- } else {
- addlabel(e, 'exception');
- }
- advance();
- advance(')');
- block(false);
- b = true;
- scope = s;
- }
- if (nexttoken.id === 'finally') {
- advance('finally');
- block(false);
- return;
- } else if (!b) {
- error("Expected '{a}' and instead saw '{b}'.",
- nexttoken, 'catch', nexttoken.value);
- }
- return this;
- });
-
- blockstmt('while', function () {
- var t = nexttoken;
- funct['(breakage)'] += 1;
- funct['(loopage)'] += 1;
- advance('(');
- nonadjacent(this, t);
- nospace();
- expression(20);
- if (nexttoken.id === '=') {
- if (!option.boss)
- warning("Expected a conditional expression and instead saw an assignment.");
- advance('=');
- expression(20);
- }
- advance(')', t);
- nospace(prevtoken, token);
- block(true, true);
- funct['(breakage)'] -= 1;
- funct['(loopage)'] -= 1;
- return this;
- }).labelled = true;
-
- reserve('with');
-
- blockstmt('switch', function () {
- var t = nexttoken,
- g = false;
- funct['(breakage)'] += 1;
- advance('(');
- nonadjacent(this, t);
- nospace();
- this.condition = expression(20);
- advance(')', t);
- nospace(prevtoken, token);
- nonadjacent(token, nexttoken);
- t = nexttoken;
- advance('{');
- nonadjacent(token, nexttoken);
- indent += option.indent;
- this.cases = [];
- for (;;) {
- switch (nexttoken.id) {
- case 'case':
- switch (funct['(verb)']) {
- case 'break':
- case 'case':
- case 'continue':
- case 'return':
- case 'switch':
- case 'throw':
- break;
- default:
- // You can tell JSHint that you don't use break intentionally by
- // adding a comment /* falls through */ on a line just before
- // the next `case`.
- if (!ft.test(lines[nexttoken.line - 2])) {
- warning(
- "Expected a 'break' statement before 'case'.",
- token);
- }
- }
- indentation(-option.indent);
- advance('case');
- this.cases.push(expression(20));
- g = true;
- advance(':');
- funct['(verb)'] = 'case';
- break;
- case 'default':
- switch (funct['(verb)']) {
- case 'break':
- case 'continue':
- case 'return':
- case 'throw':
- break;
- default:
- if (!ft.test(lines[nexttoken.line - 2])) {
- warning(
- "Expected a 'break' statement before 'default'.",
- token);
- }
- }
- indentation(-option.indent);
- advance('default');
- g = true;
- advance(':');
- break;
- case '}':
- indent -= option.indent;
- indentation();
- advance('}', t);
- if (this.cases.length === 1 || this.condition.id === 'true' ||
- this.condition.id === 'false') {
- warning("This 'switch' should be an 'if'.", this);
- }
- funct['(breakage)'] -= 1;
- funct['(verb)'] = undefined;
- return;
- case '(end)':
- error("Missing '{a}'.", nexttoken, '}');
- return;
- default:
- if (g) {
- switch (token.id) {
- case ',':
- error("Each value should have its own case label.");
- return;
- case ':':
- statements();
- break;
- default:
- error("Missing ':' on a case clause.", token);
- }
- } else {
- error("Expected '{a}' and instead saw '{b}'.",
- nexttoken, 'case', nexttoken.value);
- }
- }
- }
- }).labelled = true;
-
- stmt('debugger', function () {
- if (!option.debug) {
- warning("All 'debugger' statements should be removed.");
- }
- return this;
- }).exps = true;
-
- (function () {
- var x = stmt('do', function () {
- funct['(breakage)'] += 1;
- funct['(loopage)'] += 1;
- this.first = block(true);
- advance('while');
- var t = nexttoken;
- nonadjacent(token, t);
- advance('(');
- nospace();
- expression(20);
- if (nexttoken.id === '=') {
- if (!option.boss)
- warning("Expected a conditional expression and instead saw an assignment.");
- advance('=');
- expression(20);
- }
- advance(')', t);
- nospace(prevtoken, token);
- funct['(breakage)'] -= 1;
- funct['(loopage)'] -= 1;
- return this;
- });
- x.labelled = true;
- x.exps = true;
- }());
-
- blockstmt('for', function () {
- var s, t = nexttoken;
- funct['(breakage)'] += 1;
- funct['(loopage)'] += 1;
- advance('(');
- nonadjacent(this, t);
- nospace();
- if (peek(nexttoken.id === 'var' ? 1 : 0).id === 'in') {
- if (nexttoken.id === 'var') {
- advance('var');
- varstatement.fud.call(varstatement, true);
- } else {
- switch (funct[nexttoken.value]) {
- case 'unused':
- funct[nexttoken.value] = 'var';
- break;
- case 'var':
- break;
- default:
- warning("Bad for in variable '{a}'.",
- nexttoken, nexttoken.value);
- }
- advance();
- }
- advance('in');
- expression(20);
- advance(')', t);
- s = block(true, true);
- if (option.forin && (s.length > 1 || typeof s[0] !== 'object' ||
- s[0].value !== 'if')) {
- warning("The body of a for in should be wrapped in an if statement to filter " +
- "unwanted properties from the prototype.", this);
- }
- funct['(breakage)'] -= 1;
- funct['(loopage)'] -= 1;
- return this;
- } else {
- if (nexttoken.id !== ';') {
- if (nexttoken.id === 'var') {
- advance('var');
- varstatement.fud.call(varstatement);
- } else {
- for (;;) {
- expression(0, 'for');
- if (nexttoken.id !== ',') {
- break;
- }
- comma();
- }
- }
- }
- nolinebreak(token);
- advance(';');
- if (nexttoken.id !== ';') {
- expression(20);
- if (nexttoken.id === '=') {
- if (!option.boss)
- warning("Expected a conditional expression and instead saw an assignment.");
- advance('=');
- expression(20);
- }
- }
- nolinebreak(token);
- advance(';');
- if (nexttoken.id === ';') {
- error("Expected '{a}' and instead saw '{b}'.",
- nexttoken, ')', ';');
- }
- if (nexttoken.id !== ')') {
- for (;;) {
- expression(0, 'for');
- if (nexttoken.id !== ',') {
- break;
- }
- comma();
- }
- }
- advance(')', t);
- nospace(prevtoken, token);
- block(true, true);
- funct['(breakage)'] -= 1;
- funct['(loopage)'] -= 1;
- return this;
- }
- }).labelled = true;
-
-
- stmt('break', function () {
- var v = nexttoken.value;
- if (funct['(breakage)'] === 0) {
- warning("Unexpected '{a}'.", nexttoken, this.value);
- }
- nolinebreak(this);
- if (nexttoken.id !== ';') {
- if (token.line === nexttoken.line) {
- if (funct[v] !== 'label') {
- warning("'{a}' is not a statement label.", nexttoken, v);
- } else if (scope[v] !== funct) {
- warning("'{a}' is out of scope.", nexttoken, v);
- }
- this.first = nexttoken;
- advance();
- }
- }
- reachable('break');
- return this;
- }).exps = true;
-
-
- stmt('continue', function () {
- var v = nexttoken.value;
- if (funct['(breakage)'] === 0) {
- warning("Unexpected '{a}'.", nexttoken, this.value);
- }
- nolinebreak(this);
- if (nexttoken.id !== ';') {
- if (token.line === nexttoken.line) {
- if (funct[v] !== 'label') {
- warning("'{a}' is not a statement label.", nexttoken, v);
- } else if (scope[v] !== funct) {
- warning("'{a}' is out of scope.", nexttoken, v);
- }
- this.first = nexttoken;
- advance();
- }
- } else if (!funct['(loopage)']) {
- warning("Unexpected '{a}'.", nexttoken, this.value);
- }
- reachable('continue');
- return this;
- }).exps = true;
-
-
- stmt('return', function () {
- nolinebreak(this);
- if (nexttoken.id === '(regexp)') {
- warning("Wrap the /regexp/ literal in parens to disambiguate the slash operator.");
- }
- if (nexttoken.id !== ';' && !nexttoken.reach) {
- nonadjacent(token, nexttoken);
- this.first = expression(20);
- }
- reachable('return');
- return this;
- }).exps = true;
-
-
- stmt('throw', function () {
- nolinebreak(this);
- nonadjacent(token, nexttoken);
- this.first = expression(20);
- reachable('throw');
- return this;
- }).exps = true;
-
-// Superfluous reserved words
-
- reserve('class');
- reserve('const');
- reserve('enum');
- reserve('export');
- reserve('extends');
- reserve('import');
- reserve('super');
-
- reserve('let');
- reserve('yield');
- reserve('implements');
- reserve('interface');
- reserve('package');
- reserve('private');
- reserve('protected');
- reserve('public');
- reserve('static');
-
-
-// Parse JSON
-
- function jsonValue() {
-
- function jsonObject() {
- var o = {}, t = nexttoken;
- advance('{');
- if (nexttoken.id !== '}') {
- for (;;) {
- if (nexttoken.id === '(end)') {
- error("Missing '}' to match '{' from line {a}.",
- nexttoken, t.line);
- } else if (nexttoken.id === '}') {
- warning("Unexpected comma.", token);
- break;
- } else if (nexttoken.id === ',') {
- error("Unexpected comma.", nexttoken);
- } else if (nexttoken.id !== '(string)') {
- warning("Expected a string and instead saw {a}.",
- nexttoken, nexttoken.value);
- }
- if (o[nexttoken.value] === true) {
- warning("Duplicate key '{a}'.",
- nexttoken, nexttoken.value);
- } else if ((nexttoken.value === '__proto__' &&
- !option.proto) || (nexttoken.value === '__iterator__' &&
- !option.iterator)) {
- warning("The '{a}' key may produce unexpected results.",
- nexttoken, nexttoken.value);
- } else {
- o[nexttoken.value] = true;
- }
- advance();
- advance(':');
- jsonValue();
- if (nexttoken.id !== ',') {
- break;
- }
- advance(',');
- }
- }
- advance('}');
- }
-
- function jsonArray() {
- var t = nexttoken;
- advance('[');
- if (nexttoken.id !== ']') {
- for (;;) {
- if (nexttoken.id === '(end)') {
- error("Missing ']' to match '[' from line {a}.",
- nexttoken, t.line);
- } else if (nexttoken.id === ']') {
- warning("Unexpected comma.", token);
- break;
- } else if (nexttoken.id === ',') {
- error("Unexpected comma.", nexttoken);
- }
- jsonValue();
- if (nexttoken.id !== ',') {
- break;
- }
- advance(',');
- }
- }
- advance(']');
- }
-
- switch (nexttoken.id) {
- case '{':
- jsonObject();
- break;
- case '[':
- jsonArray();
- break;
- case 'true':
- case 'false':
- case 'null':
- case '(number)':
- case '(string)':
- advance();
- break;
- case '-':
- advance('-');
- if (token.character !== nexttoken.from) {
- warning("Unexpected space after '-'.", token);
- }
- adjacent(token, nexttoken);
- advance('(number)');
- break;
- default:
- error("Expected a JSON value.", nexttoken);
- }
- }
-
-
-// The actual JSHINT function itself.
-
- var itself = function (s, o, g) {
- var a, i, k;
- JSHINT.errors = [];
- predefined = Object.create(standard);
- combine(predefined, g || {});
- if (o) {
- a = o.predef;
- if (a) {
- if (Array.isArray(a)) {
- for (i = 0; i < a.length; i += 1) {
- predefined[a[i]] = true;
- }
- } else if (typeof a === 'object') {
- k = Object.keys(a);
- for (i = 0; i < k.length; i += 1) {
- predefined[k[i]] = !!a[k[i]];
- }
- }
- }
- option = o;
- } else {
- option = {};
- }
- option.indent = option.indent || 4;
- option.maxerr = option.maxerr || 50;
-
- tab = '';
- for (i = 0; i < option.indent; i += 1) {
- tab += ' ';
- }
- indent = 1;
- global = Object.create(predefined);
- scope = global;
- funct = {
- '(global)': true,
- '(name)': '(global)',
- '(scope)': scope,
- '(breakage)': 0,
- '(loopage)': 0
- };
- functions = [funct];
- urls = [];
- src = false;
- stack = null;
- member = {};
- membersOnly = null;
- implied = {};
- inblock = false;
- lookahead = [];
- jsonmode = false;
- warnings = 0;
- lex.init(s);
- prereg = true;
- strict_mode = false;
-
- prevtoken = token = nexttoken = syntax['(begin)'];
- assume();
-
- try {
- advance();
- switch (nexttoken.id) {
- case '{':
- case '[':
- option.laxbreak = true;
- jsonmode = true;
- jsonValue();
- break;
- default:
- if (nexttoken.value === 'use strict') {
- if (!option.globalstrict)
- warning("Use the function form of \"use strict\".");
- use_strict();
- }
- statements('lib');
- }
- advance('(end)');
- } catch (e) {
- if (e) {
- JSHINT.errors.push({
- reason : e.message,
- line : e.line || nexttoken.line,
- character : e.character || nexttoken.from
- }, null);
- }
- }
- return JSHINT.errors.length === 0;
- };
-
-
-// Data summary.
-
- itself.data = function () {
-
- var data = {functions: []}, fu, globals, implieds = [], f, i, j,
- members = [], n, unused = [], v;
- if (itself.errors.length) {
- data.errors = itself.errors;
- }
-
- if (jsonmode) {
- data.json = true;
- }
-
- for (n in implied) {
- if (is_own(implied, n)) {
- implieds.push({
- name: n,
- line: implied[n]
- });
- }
- }
- if (implieds.length > 0) {
- data.implieds = implieds;
- }
-
- if (urls.length > 0) {
- data.urls = urls;
- }
-
- globals = Object.keys(scope);
- if (globals.length > 0) {
- data.globals = globals;
- }
-
- for (i = 1; i < functions.length; i += 1) {
- f = functions[i];
- fu = {};
- for (j = 0; j < functionicity.length; j += 1) {
- fu[functionicity[j]] = [];
- }
- for (n in f) {
- if (is_own(f, n) && n.charAt(0) !== '(') {
- v = f[n];
- if (v === 'unction') {
- v = 'unused';
- }
- if (Array.isArray(fu[v])) {
- fu[v].push(n);
- if (v === 'unused') {
- unused.push({
- name: n,
- line: f['(line)'],
- 'function': f['(name)']
- });
- }
- }
- }
- }
- for (j = 0; j < functionicity.length; j += 1) {
- if (fu[functionicity[j]].length === 0) {
- delete fu[functionicity[j]];
- }
- }
- fu.name = f['(name)'];
- fu.param = f['(params)'];
- fu.line = f['(line)'];
- fu.last = f['(last)'];
- data.functions.push(fu);
- }
-
- if (unused.length > 0) {
- data.unused = unused;
- }
-
- members = [];
- for (n in member) {
- if (typeof member[n] === 'number') {
- data.member = member;
- break;
- }
- }
-
- return data;
- };
-
- itself.report = function (option) {
- var data = itself.data();
-
- var a = [], c, e, err, f, i, k, l, m = '', n, o = [], s;
-
- function detail(h, array) {
- var b, i, singularity;
- if (array) {
- o.push('<div><i>' + h + '</i> ');
- array = array.sort();
- for (i = 0; i < array.length; i += 1) {
- if (array[i] !== singularity) {
- singularity = array[i];
- o.push((b ? ', ' : '') + singularity);
- b = true;
- }
- }
- o.push('</div>');
- }
- }
-
-
- if (data.errors || data.implieds || data.unused) {
- err = true;
- o.push('<div id=errors><i>Error:</i>');
- if (data.errors) {
- for (i = 0; i < data.errors.length; i += 1) {
- c = data.errors[i];
- if (c) {
- e = c.evidence || '';
- o.push('<p>Problem' + (isFinite(c.line) ? ' at line ' +
- c.line + ' character ' + c.character : '') +
- ': ' + c.reason.entityify() +
- '</p><p class=evidence>' +
- (e && (e.length > 80 ? e.slice(0, 77) + '...' :
- e).entityify()) + '</p>');
- }
- }
- }
-
- if (data.implieds) {
- s = [];
- for (i = 0; i < data.implieds.length; i += 1) {
- s[i] = '<code>' + data.implieds[i].name + '</code>&nbsp;<i>' +
- data.implieds[i].line + '</i>';
- }
- o.push('<p><i>Implied global:</i> ' + s.join(', ') + '</p>');
- }
-
- if (data.unused) {
- s = [];
- for (i = 0; i < data.unused.length; i += 1) {
- s[i] = '<code><u>' + data.unused[i].name + '</u></code>&nbsp;<i>' +
- data.unused[i].line + '</i> <code>' +
- data.unused[i]['function'] + '</code>';
- }
- o.push('<p><i>Unused variable:</i> ' + s.join(', ') + '</p>');
- }
- if (data.json) {
- o.push('<p>JSON: bad.</p>');
- }
- o.push('</div>');
- }
-
- if (!option) {
-
- o.push('<br><div id=functions>');
-
- if (data.urls) {
- detail("URLs<br>", data.urls, '<br>');
- }
-
- if (data.json && !err) {
- o.push('<p>JSON: good.</p>');
- } else if (data.globals) {
- o.push('<div><i>Global</i> ' +
- data.globals.sort().join(', ') + '</div>');
- } else {
- o.push('<div><i>No new global variables introduced.</i></div>');
- }
-
- for (i = 0; i < data.functions.length; i += 1) {
- f = data.functions[i];
-
- o.push('<br><div class=function><i>' + f.line + '-' +
- f.last + '</i> ' + (f.name || '') + '(' +
- (f.param ? f.param.join(', ') : '') + ')</div>');
- detail('<big><b>Unused</b></big>', f.unused);
- detail('Closure', f.closure);
- detail('Variable', f['var']);
- detail('Exception', f.exception);
- detail('Outer', f.outer);
- detail('Global', f.global);
- detail('Label', f.label);
- }
-
- if (data.member) {
- a = Object.keys(data.member);
- if (a.length) {
- a = a.sort();
- m = '<br><pre id=members>/*members ';
- l = 10;
- for (i = 0; i < a.length; i += 1) {
- k = a[i];
- n = k.name();
- if (l + n.length > 72) {
- o.push(m + '<br>');
- m = ' ';
- l = 1;
- }
- l += n.length + 2;
- if (data.member[k] === 1) {
- n = '<i>' + n + '</i>';
- }
- if (i < a.length - 1) {
- n += ', ';
- }
- m += n;
- }
- o.push(m + '<br>*/</pre>');
- }
- o.push('</div>');
- }
- }
- return o.join('');
- };
- itself.jshint = itself;
-
- itself.edition = '2011-04-16';
-
- return itself;
-
+ }
+ return this;
+ });
+
+ prefix("function", function () {
+ var i = optionalidentifier();
+ if (i) {
+ adjacent(token, nexttoken);
+ } else {
+ nonadjacent(token, nexttoken);
+ }
+ doFunction(i);
+ if (!option.loopfunc && funct["(loopage)"]) {
+ warning("Don't make functions within a loop.");
+ }
+ return this;
+ });
+
+ blockstmt("if", function () {
+ var t = nexttoken;
+ increaseComplexityCount();
+ advance("(");
+ nonadjacent(this, t);
+ nospace();
+ expression(20);
+ if (nexttoken.id === "=") {
+ if (!option.boss)
+ warning("Assignment in conditional expression");
+ advance("=");
+ expression(20);
+ }
+ advance(")", t);
+ nospace(prevtoken, token);
+ block(true, true);
+ if (nexttoken.id === "else") {
+ nonadjacent(token, nexttoken);
+ advance("else");
+ if (nexttoken.id === "if" || nexttoken.id === "switch") {
+ statement(true);
+ } else {
+ block(true, true);
+ }
+ }
+ return this;
+ });
+
+ blockstmt("try", function () {
+ var b;
+
+ function doCatch() {
+ var oldScope = scope;
+ var e;
+
+ advance("catch");
+ nonadjacent(token, nexttoken);
+ advance("(");
+
+ scope = Object.create(oldScope);
+
+ e = nexttoken.value;
+ if (nexttoken.type !== "(identifier)") {
+ e = null;
+ warning("Expected an identifier and instead saw '{a}'.", nexttoken, e);
+ }
+
+ advance();
+ advance(")");
+
+ funct = {
+ "(name)" : "(catch)",
+ "(line)" : nexttoken.line,
+ "(character)": nexttoken.character,
+ "(context)" : funct,
+ "(breakage)" : funct["(breakage)"],
+ "(loopage)" : funct["(loopage)"],
+ "(scope)" : scope,
+ "(statement)": false,
+ "(metrics)" : createMetrics(nexttoken),
+ "(catch)" : true,
+ "(tokens)" : {}
+ };
+
+ if (e) {
+ addlabel(e, "exception");
+ }
+
+ token.funct = funct;
+ functions.push(funct);
+
+ block(false);
+
+ scope = oldScope;
+
+ funct["(last)"] = token.line;
+ funct["(lastcharacter)"] = token.character;
+ funct = funct["(context)"];
+ }
+
+ block(false);
+
+ if (nexttoken.id === "catch") {
+ increaseComplexityCount();
+ doCatch();
+ b = true;
+ }
+
+ if (nexttoken.id === "finally") {
+ advance("finally");
+ block(false);
+ return;
+ } else if (!b) {
+ error("Expected '{a}' and instead saw '{b}'.",
+ nexttoken, "catch", nexttoken.value);
+ }
+
+ return this;
+ });
+
+ blockstmt("while", function () {
+ var t = nexttoken;
+ funct["(breakage)"] += 1;
+ funct["(loopage)"] += 1;
+ increaseComplexityCount();
+ advance("(");
+ nonadjacent(this, t);
+ nospace();
+ expression(20);
+ if (nexttoken.id === "=") {
+ if (!option.boss)
+ warning("Assignment in conditional expression");
+ advance("=");
+ expression(20);
+ }
+ advance(")", t);
+ nospace(prevtoken, token);
+ block(true, true);
+ funct["(breakage)"] -= 1;
+ funct["(loopage)"] -= 1;
+ return this;
+ }).labelled = true;
+
+ blockstmt("with", function () {
+ var t = nexttoken;
+ if (directive["use strict"]) {
+ error("'with' is not allowed in strict mode.", token);
+ } else if (!option.withstmt) {
+ warning("Don't use 'with'.", token);
+ }
+
+ advance("(");
+ nonadjacent(this, t);
+ nospace();
+ expression(0);
+ advance(")", t);
+ nospace(prevtoken, token);
+ block(true, true);
+
+ return this;
+ });
+
+ blockstmt("switch", function () {
+ var t = nexttoken,
+ g = false;
+ funct["(breakage)"] += 1;
+ advance("(");
+ nonadjacent(this, t);
+ nospace();
+ this.condition = expression(20);
+ advance(")", t);
+ nospace(prevtoken, token);
+ nonadjacent(token, nexttoken);
+ t = nexttoken;
+ advance("{");
+ nonadjacent(token, nexttoken);
+ indent += option.indent;
+ this.cases = [];
+ for (;;) {
+ switch (nexttoken.id) {
+ case "case":
+ switch (funct["(verb)"]) {
+ case "break":
+ case "case":
+ case "continue":
+ case "return":
+ case "switch":
+ case "throw":
+ break;
+ default:
+ if (!ft.test(lines[nexttoken.line - 2])) {
+ warning(
+ "Expected a 'break' statement before 'case'.",
+ token);
+ }
+ }
+ indentation(-option.indent);
+ advance("case");
+ this.cases.push(expression(20));
+ increaseComplexityCount();
+ g = true;
+ advance(":");
+ funct["(verb)"] = "case";
+ break;
+ case "default":
+ switch (funct["(verb)"]) {
+ case "break":
+ case "continue":
+ case "return":
+ case "throw":
+ break;
+ default:
+ if (!ft.test(lines[nexttoken.line - 2])) {
+ warning(
+ "Expected a 'break' statement before 'default'.",
+ token);
+ }
+ }
+ indentation(-option.indent);
+ advance("default");
+ g = true;
+ advance(":");
+ break;
+ case "}":
+ indent -= option.indent;
+ indentation();
+ advance("}", t);
+ if (this.cases.length === 1 || this.condition.id === "true" ||
+ this.condition.id === "false") {
+ if (!option.onecase)
+ warning("This 'switch' should be an 'if'.", this);
+ }
+ funct["(breakage)"] -= 1;
+ funct["(verb)"] = undefined;
+ return;
+ case "(end)":
+ error("Missing '{a}'.", nexttoken, "}");
+ return;
+ default:
+ if (g) {
+ switch (token.id) {
+ case ",":
+ error("Each value should have its own case label.");
+ return;
+ case ":":
+ g = false;
+ statements();
+ break;
+ default:
+ error("Missing ':' on a case clause.", token);
+ return;
+ }
+ } else {
+ if (token.id === ":") {
+ advance(":");
+ error("Unexpected '{a}'.", token, ":");
+ statements();
+ } else {
+ error("Expected '{a}' and instead saw '{b}'.",
+ nexttoken, "case", nexttoken.value);
+ return;
+ }
+ }
+ }
+ }
+ }).labelled = true;
+
+ stmt("debugger", function () {
+ if (!option.debug) {
+ warning("All 'debugger' statements should be removed.");
+ }
+ return this;
+ }).exps = true;
+
+ (function () {
+ var x = stmt("do", function () {
+ funct["(breakage)"] += 1;
+ funct["(loopage)"] += 1;
+ increaseComplexityCount();
+
+ this.first = block(true);
+ advance("while");
+ var t = nexttoken;
+ nonadjacent(token, t);
+ advance("(");
+ nospace();
+ expression(20);
+ if (nexttoken.id === "=") {
+ if (!option.boss)
+ warning("Assignment in conditional expression");
+ advance("=");
+ expression(20);
+ }
+ advance(")", t);
+ nospace(prevtoken, token);
+ funct["(breakage)"] -= 1;
+ funct["(loopage)"] -= 1;
+ return this;
+ });
+ x.labelled = true;
+ x.exps = true;
+ }());
+
+ blockstmt("for", function () {
+ var s, t = nexttoken;
+ funct["(breakage)"] += 1;
+ funct["(loopage)"] += 1;
+ increaseComplexityCount();
+ advance("(");
+ nonadjacent(this, t);
+ nospace();
+ if (peek(nexttoken.id === "var" ? 1 : 0).id === "in") {
+ if (nexttoken.id === "var") {
+ advance("var");
+ varstatement.fud.call(varstatement, true);
+ } else {
+ switch (funct[nexttoken.value]) {
+ case "unused":
+ funct[nexttoken.value] = "var";
+ break;
+ case "var":
+ break;
+ default:
+ warning("Bad for in variable '{a}'.",
+ nexttoken, nexttoken.value);
+ }
+ advance();
+ }
+ advance("in");
+ expression(20);
+ advance(")", t);
+ s = block(true, true);
+ if (option.forin && s && (s.length > 1 || typeof s[0] !== "object" ||
+ s[0].value !== "if")) {
+ warning("The body of a for in should be wrapped in an if statement to filter " +
+ "unwanted properties from the prototype.", this);
+ }
+ funct["(breakage)"] -= 1;
+ funct["(loopage)"] -= 1;
+ return this;
+ } else {
+ if (nexttoken.id !== ";") {
+ if (nexttoken.id === "var") {
+ advance("var");
+ varstatement.fud.call(varstatement);
+ } else {
+ for (;;) {
+ expression(0, "for");
+ if (nexttoken.id !== ",") {
+ break;
+ }
+ comma();
+ }
+ }
+ }
+ nolinebreak(token);
+ advance(";");
+ if (nexttoken.id !== ";") {
+ expression(20);
+ if (nexttoken.id === "=") {
+ if (!option.boss)
+ warning("Assignment in conditional expression");
+ advance("=");
+ expression(20);
+ }
+ }
+ nolinebreak(token);
+ advance(";");
+ if (nexttoken.id === ";") {
+ error("Expected '{a}' and instead saw '{b}'.",
+ nexttoken, ")", ";");
+ }
+ if (nexttoken.id !== ")") {
+ for (;;) {
+ expression(0, "for");
+ if (nexttoken.id !== ",") {
+ break;
+ }
+ comma();
+ }
+ }
+ advance(")", t);
+ nospace(prevtoken, token);
+ block(true, true);
+ funct["(breakage)"] -= 1;
+ funct["(loopage)"] -= 1;
+ return this;
+ }
+ }).labelled = true;
+
+
+ stmt("break", function () {
+ var v = nexttoken.value;
+
+ if (funct["(breakage)"] === 0)
+ warning("Unexpected '{a}'.", nexttoken, this.value);
+
+ if (!option.asi)
+ nolinebreak(this);
+
+ if (nexttoken.id !== ";") {
+ if (token.line === nexttoken.line) {
+ if (funct[v] !== "label") {
+ warning("'{a}' is not a statement label.", nexttoken, v);
+ } else if (scope[v] !== funct) {
+ warning("'{a}' is out of scope.", nexttoken, v);
+ }
+ this.first = nexttoken;
+ advance();
+ }
+ }
+ reachable("break");
+ return this;
+ }).exps = true;
+
+
+ stmt("continue", function () {
+ var v = nexttoken.value;
+
+ if (funct["(breakage)"] === 0)
+ warning("Unexpected '{a}'.", nexttoken, this.value);
+
+ if (!option.asi)
+ nolinebreak(this);
+
+ if (nexttoken.id !== ";") {
+ if (token.line === nexttoken.line) {
+ if (funct[v] !== "label") {
+ warning("'{a}' is not a statement label.", nexttoken, v);
+ } else if (scope[v] !== funct) {
+ warning("'{a}' is out of scope.", nexttoken, v);
+ }
+ this.first = nexttoken;
+ advance();
+ }
+ } else if (!funct["(loopage)"]) {
+ warning("Unexpected '{a}'.", nexttoken, this.value);
+ }
+ reachable("continue");
+ return this;
+ }).exps = true;
+
+
+ stmt("return", function () {
+ if (this.line === nexttoken.line) {
+ if (nexttoken.id === "(regexp)")
+ warning("Wrap the /regexp/ literal in parens to disambiguate the slash operator.");
+
+ if (nexttoken.id !== ";" && !nexttoken.reach) {
+ nonadjacent(token, nexttoken);
+ if (peek().value === "=" && !option.boss) {
+ warningAt("Did you mean to return a conditional instead of an assignment?",
+ token.line, token.character + 1);
+ }
+ this.first = expression(0);
+ }
+ } else if (!option.asi) {
+ nolinebreak(this); // always warn (Line breaking error)
+ }
+ reachable("return");
+ return this;
+ }).exps = true;
+
+
+ stmt("throw", function () {
+ nolinebreak(this);
+ nonadjacent(token, nexttoken);
+ this.first = expression(20);
+ reachable("throw");
+ return this;
+ }).exps = true;
+
+ reserve("class");
+ reserve("const");
+ reserve("enum");
+ reserve("export");
+ reserve("extends");
+ reserve("import");
+ reserve("super");
+
+ reserve("let");
+ reserve("yield");
+ reserve("implements");
+ reserve("interface");
+ reserve("package");
+ reserve("private");
+ reserve("protected");
+ reserve("public");
+ reserve("static");
+
+ function jsonValue() {
+
+ function jsonObject() {
+ var o = {}, t = nexttoken;
+ advance("{");
+ if (nexttoken.id !== "}") {
+ for (;;) {
+ if (nexttoken.id === "(end)") {
+ error("Missing '}' to match '{' from line {a}.",
+ nexttoken, t.line);
+ } else if (nexttoken.id === "}") {
+ warning("Unexpected comma.", token);
+ break;
+ } else if (nexttoken.id === ",") {
+ error("Unexpected comma.", nexttoken);
+ } else if (nexttoken.id !== "(string)") {
+ warning("Expected a string and instead saw {a}.",
+ nexttoken, nexttoken.value);
+ }
+ if (o[nexttoken.value] === true) {
+ warning("Duplicate key '{a}'.",
+ nexttoken, nexttoken.value);
+ } else if ((nexttoken.value === "__proto__" &&
+ !option.proto) || (nexttoken.value === "__iterator__" &&
+ !option.iterator)) {
+ warning("The '{a}' key may produce unexpected results.",
+ nexttoken, nexttoken.value);
+ } else {
+ o[nexttoken.value] = true;
+ }
+ advance();
+ advance(":");
+ jsonValue();
+ if (nexttoken.id !== ",") {
+ break;
+ }
+ advance(",");
+ }
+ }
+ advance("}");
+ }
+
+ function jsonArray() {
+ var t = nexttoken;
+ advance("[");
+ if (nexttoken.id !== "]") {
+ for (;;) {
+ if (nexttoken.id === "(end)") {
+ error("Missing ']' to match '[' from line {a}.",
+ nexttoken, t.line);
+ } else if (nexttoken.id === "]") {
+ warning("Unexpected comma.", token);
+ break;
+ } else if (nexttoken.id === ",") {
+ error("Unexpected comma.", nexttoken);
+ }
+ jsonValue();
+ if (nexttoken.id !== ",") {
+ break;
+ }
+ advance(",");
+ }
+ }
+ advance("]");
+ }
+
+ switch (nexttoken.id) {
+ case "{":
+ jsonObject();
+ break;
+ case "[":
+ jsonArray();
+ break;
+ case "true":
+ case "false":
+ case "null":
+ case "(number)":
+ case "(string)":
+ advance();
+ break;
+ case "-":
+ advance("-");
+ if (token.character !== nexttoken.from) {
+ warning("Unexpected space after '-'.", token);
+ }
+ adjacent(token, nexttoken);
+ advance("(number)");
+ break;
+ default:
+ error("Expected a JSON value.", nexttoken);
+ }
+ }
+ var itself = function (s, o, g) {
+ var a, i, k, x;
+ var optionKeys;
+ var newOptionObj = {};
+
+ if (o && o.scope) {
+ JSHINT.scope = o.scope;
+ } else {
+ JSHINT.errors = [];
+ JSHINT.undefs = [];
+ JSHINT.internals = [];
+ JSHINT.blacklist = {};
+ JSHINT.scope = "(main)";
+ }
+
+ predefined = Object.create(standard);
+ declared = Object.create(null);
+ combine(predefined, g || {});
+
+ if (o) {
+ a = o.predef;
+ if (a) {
+ if (!Array.isArray(a) && typeof a === "object") {
+ a = Object.keys(a);
+ }
+ a.forEach(function (item) {
+ var slice;
+ if (item[0] === "-") {
+ slice = item.slice(1);
+ JSHINT.blacklist[slice] = slice;
+ } else {
+ predefined[item] = true;
+ }
+ });
+ }
+
+ optionKeys = Object.keys(o);
+ for (x = 0; x < optionKeys.length; x++) {
+ newOptionObj[optionKeys[x]] = o[optionKeys[x]];
+
+ if (optionKeys[x] === "newcap" && o[optionKeys[x]] === false)
+ newOptionObj["(explicitNewcap)"] = true;
+
+ if (optionKeys[x] === "indent")
+ newOptionObj.white = true;
+ }
+ }
+
+ option = newOptionObj;
+
+ option.indent = option.indent || 4;
+ option.maxerr = option.maxerr || 50;
+
+ tab = "";
+ for (i = 0; i < option.indent; i += 1) {
+ tab += " ";
+ }
+ indent = 1;
+ global = Object.create(predefined);
+ scope = global;
+ funct = {
+ "(global)": true,
+ "(name)": "(global)",
+ "(scope)": scope,
+ "(breakage)": 0,
+ "(loopage)": 0,
+ "(tokens)": {},
+ "(metrics)": createMetrics(nexttoken)
+ };
+ functions = [funct];
+ urls = [];
+ stack = null;
+ member = {};
+ membersOnly = null;
+ implied = {};
+ inblock = false;
+ lookahead = [];
+ jsonmode = false;
+ warnings = 0;
+ lines = [];
+ unuseds = [];
+
+ if (!isString(s) && !Array.isArray(s)) {
+ errorAt("Input is neither a string nor an array of strings.", 0);
+ return false;
+ }
+
+ if (isString(s) && /^\s*$/g.test(s)) {
+ errorAt("Input is an empty string.", 0);
+ return false;
+ }
+
+ if (s.length === 0) {
+ errorAt("Input is an empty array.", 0);
+ return false;
+ }
+
+ lex.init(s);
+
+ prereg = true;
+ directive = {};
+
+ prevtoken = token = nexttoken = syntax["(begin)"];
+ for (var name in o) {
+ if (is_own(o, name)) {
+ checkOption(name, token);
+ }
+ }
+
+ assume();
+ combine(predefined, g || {});
+ comma.first = true;
+ quotmark = undefined;
+
+ try {
+ advance();
+ switch (nexttoken.id) {
+ case "{":
+ case "[":
+ option.laxbreak = true;
+ jsonmode = true;
+ jsonValue();
+ break;
+ default:
+ directives();
+ if (directive["use strict"] && !option.globalstrict) {
+ warning("Use the function form of \"use strict\".", prevtoken);
+ }
+
+ statements();
+ }
+ advance((nexttoken && nexttoken.value !== ".") ? "(end)" : undefined);
+
+ var markDefined = function (name, context) {
+ do {
+ if (typeof context[name] === "string") {
+
+ if (context[name] === "unused")
+ context[name] = "var";
+ else if (context[name] === "unction")
+ context[name] = "closure";
+
+ return true;
+ }
+
+ context = context["(context)"];
+ } while (context);
+
+ return false;
+ };
+
+ var clearImplied = function (name, line) {
+ if (!implied[name])
+ return;
+
+ var newImplied = [];
+ for (var i = 0; i < implied[name].length; i += 1) {
+ if (implied[name][i] !== line)
+ newImplied.push(implied[name][i]);
+ }
+
+ if (newImplied.length === 0)
+ delete implied[name];
+ else
+ implied[name] = newImplied;
+ };
+
+ var warnUnused = function (name, token) {
+ var line = token.line;
+ var chr = token.character;
+
+ if (option.unused)
+ warningAt("'{a}' is defined but never used.", line, chr, name);
+
+ unuseds.push({
+ name: name,
+ line: line,
+ character: chr
+ });
+ };
+
+ var checkUnused = function (func, key) {
+ var type = func[key];
+ var token = func["(tokens)"][key];
+
+ if (key.charAt(0) === "(")
+ return;
+
+ if (type !== "unused" && type !== "unction")
+ return;
+ if (func["(params)"] && func["(params)"].indexOf(key) !== -1)
+ return;
+
+ warnUnused(key, token);
+ };
+ for (i = 0; i < JSHINT.undefs.length; i += 1) {
+ k = JSHINT.undefs[i].slice(0);
+
+ if (markDefined(k[2].value, k[0])) {
+ clearImplied(k[2].value, k[2].line);
+ } else {
+ warning.apply(warning, k.slice(1));
+ }
+ }
+
+ functions.forEach(function (func) {
+ for (var key in func) {
+ if (is_own(func, key)) {
+ checkUnused(func, key);
+ }
+ }
+
+ if (!func["(params)"])
+ return;
+
+ var params = func["(params)"].slice();
+ var param = params.pop();
+ var type;
+
+ while (param) {
+ type = func[param];
+
+ if (param === "undefined")
+ return;
+
+ if (type !== "unused" && type !== "unction")
+ return;
+
+ warnUnused(param, func["(tokens)"][param]);
+ param = params.pop();
+ }
+ });
+
+ for (var key in declared) {
+ if (is_own(declared, key) && !is_own(global, key)) {
+ warnUnused(key, declared[key]);
+ }
+ }
+ } catch (e) {
+ if (e) {
+ var nt = nexttoken || {};
+ JSHINT.errors.push({
+ raw : e.raw,
+ reason : e.message,
+ line : e.line || nt.line,
+ character : e.character || nt.from
+ }, null);
+ }
+ }
+
+ if (JSHINT.scope === "(main)") {
+ o = o || {};
+
+ for (i = 0; i < JSHINT.internals.length; i += 1) {
+ k = JSHINT.internals[i];
+ o.scope = k.elem;
+ itself(k.value, o, g);
+ }
+ }
+
+ return JSHINT.errors.length === 0;
+ };
+ itself.data = function () {
+ var data = {
+ functions: [],
+ options: option
+ };
+ var implieds = [];
+ var members = [];
+ var fu, f, i, j, n, globals;
+
+ if (itself.errors.length) {
+ data.errors = itself.errors;
+ }
+
+ if (jsonmode) {
+ data.json = true;
+ }
+
+ for (n in implied) {
+ if (is_own(implied, n)) {
+ implieds.push({
+ name: n,
+ line: implied[n]
+ });
+ }
+ }
+
+ if (implieds.length > 0) {
+ data.implieds = implieds;
+ }
+
+ if (urls.length > 0) {
+ data.urls = urls;
+ }
+
+ globals = Object.keys(scope);
+ if (globals.length > 0) {
+ data.globals = globals;
+ }
+
+ for (i = 1; i < functions.length; i += 1) {
+ f = functions[i];
+ fu = {};
+
+ for (j = 0; j < functionicity.length; j += 1) {
+ fu[functionicity[j]] = [];
+ }
+
+ for (j = 0; j < functionicity.length; j += 1) {
+ if (fu[functionicity[j]].length === 0) {
+ delete fu[functionicity[j]];
+ }
+ }
+
+ fu.name = f["(name)"];
+ fu.param = f["(params)"];
+ fu.line = f["(line)"];
+ fu.character = f["(character)"];
+ fu.last = f["(last)"];
+ fu.lastcharacter = f["(lastcharacter)"];
+ data.functions.push(fu);
+ }
+
+ if (unuseds.length > 0) {
+ data.unused = unuseds;
+ }
+
+ members = [];
+ for (n in member) {
+ if (typeof member[n] === "number") {
+ data.member = member;
+ break;
+ }
+ }
+
+ return data;
+ };
+
+ itself.jshint = itself;
+
+ return itself;
}());
+if (typeof exports === "object" && exports) {
+ exports.JSHINT = JSHINT;
+}
-// Make JSHINT a Node module, if possible.
-if (typeof exports == 'object' && exports)
- exports.JSHINT = JSHINT;
-
-});/* -*- Mode: JS; tab-width: 4; indent-tabs-mode: nil; -*-
- * vim: set sw=4 ts=4 et tw=78:
- * ***** BEGIN LICENSE BLOCK *****
- *
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is the Narcissus JavaScript engine.
- *
- * The Initial Developer of the Original Code is
- * Brendan Eich <brendan@mozilla.org>.
- * Portions created by the Initial Developer are Copyright (C) 2004
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Tom Austin <taustin@ucsc.edu>
- * Brendan Eich <brendan@mozilla.org>
- * Shu-Yu Guo <shu@rfrn.org>
- * Dave Herman <dherman@mozilla.com>
- * Dimitris Vardoulakis <dimvar@ccs.neu.edu>
- * Patrick Walton <pcwalton@mozilla.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-/*
- * Narcissus - JS implemented in JS.
- *
- * Parser.
- */
-
-define('ace/narcissus/jsparse', ['require', 'exports', 'module' , 'ace/narcissus/jslex', 'ace/narcissus/jsdefs'], function(require, exports, module) {
-
- var lexer = require("./jslex");
- var definitions = require("./jsdefs");
-
- const StringMap = definitions.StringMap;
- const Stack = definitions.Stack;
-
- // Set constants in the local scope.
- eval(definitions.consts);
-
- // Banned statement types by language version.
- const blackLists = { 160: {}, 185: {}, harmony: {} };
- blackLists[160][IMPORT] = true;
- blackLists[160][EXPORT] = true;
- blackLists[160][LET] = true;
- blackLists[160][MODULE] = true;
- blackLists[160][YIELD] = true;
- blackLists[185][IMPORT] = true;
- blackLists[185][EXPORT] = true;
- blackLists[185][MODULE] = true;
- blackLists.harmony[WITH] = true;
-
- /*
- * pushDestructuringVarDecls :: (node, hoisting node) -> void
- *
- * Recursively add all destructured declarations to varDecls.
- */
- function pushDestructuringVarDecls(n, s) {
- for (var i in n) {
- var sub = n[i];
- if (sub.type === IDENTIFIER) {
- s.varDecls.push(sub);
- } else {
- pushDestructuringVarDecls(sub, s);
- }
- }
- }
-
- function StaticContext(parentScript, parentBlock, inModule, inFunction) {
- this.parentScript = parentScript;
- this.parentBlock = parentBlock || parentScript;
- this.inModule = inModule || false;
- this.inFunction = inFunction || false;
- this.inForLoopInit = false;
- this.topLevel = true;
- this.allLabels = new Stack();
- this.currentLabels = new Stack();
- this.labeledTargets = new Stack();
- this.defaultLoopTarget = null;
- this.defaultTarget = null;
- this.blackList = blackLists[Narcissus.options.version];
- Narcissus.options.ecma3OnlyMode && (this.ecma3OnlyMode = true);
- Narcissus.options.parenFreeMode && (this.parenFreeMode = true);
- }
-
- StaticContext.prototype = {
- ecma3OnlyMode: false,
- parenFreeMode: false,
- // non-destructive update via prototype extension
- update: function(ext) {
- var desc = {};
- for (var key in ext) {
- desc[key] = {
- value: ext[key],
- writable: true,
- enumerable: true,
- configurable: true
- }
- }
- return Object.create(this, desc);
- },
- pushLabel: function(label) {
- return this.update({ currentLabels: this.currentLabels.push(label),
- allLabels: this.allLabels.push(label) });
- },
- pushTarget: function(target) {
- var isDefaultLoopTarget = target.isLoop;
- var isDefaultTarget = isDefaultLoopTarget || target.type === SWITCH;
-
- if (this.currentLabels.isEmpty()) {
- if (isDefaultLoopTarget) this.update({ defaultLoopTarget: target });
- if (isDefaultTarget) this.update({ defaultTarget: target });
- return this;
- }
-
- target.labels = new StringMap();
- this.currentLabels.forEach(function(label) {
- target.labels.set(label, true);
- });
- return this.update({ currentLabels: new Stack(),
- labeledTargets: this.labeledTargets.push(target),
- defaultLoopTarget: isDefaultLoopTarget
- ? target
- : this.defaultLoopTarget,
- defaultTarget: isDefaultTarget
- ? target
- : this.defaultTarget });
- },
- nest: function() {
- return this.topLevel ? this.update({ topLevel: false }) : this;
- },
- allow: function(type) {
- switch (type) {
- case EXPORT:
- if (!this.inModule || this.inFunction || !this.topLevel)
- return false;
- // FALL THROUGH
-
- case IMPORT:
- return !this.inFunction && this.topLevel;
-
- case MODULE:
- return !this.inFunction && this.topLevel;
-
- default:
- return true;
- }
- }
- };
-
- /*
- * Script :: (tokenizer, boolean, boolean) -> node
- *
- * Parses the toplevel and module/function bodies.
- */
- function Script(t, inModule, inFunction) {
- var n = new Node(t, scriptInit());
- Statements(t, new StaticContext(n, n, inModule, inFunction), n);
- return n;
- }
-
- // We extend Array slightly with a top-of-stack method.
- definitions.defineProperty(Array.prototype, "top",
- function() {
- return this.length && this[this.length-1];
- }, false, false, true);
-
- /*
- * Node :: (tokenizer, optional init object) -> node
- */
- function Node(t, init) {
- var token = t.token;
- if (token) {
- // If init.type exists it will override token.type.
- this.type = token.type;
- this.value = token.value;
- this.lineno = token.lineno;
-
- // Start and end are file positions for error handling.
- this.start = token.start;
- this.end = token.end;
- } else {
- this.lineno = t.lineno;
- }
-
- // Node uses a tokenizer for debugging (getSource, filename getter).
- this.tokenizer = t;
- this.children = [];
-
- for (var prop in init)
- this[prop] = init[prop];
- }
-
- /*
- * SyntheticNode :: (tokenizer, optional init object) -> node
- */
- function SyntheticNode(t, init) {
- // print("SYNTHETIC NODE");
- // if (init.type === COMMA) {
- // print("SYNTHETIC COMMA");
- // print(init);
- // }
- this.tokenizer = t;
- this.children = [];
- for (var prop in init)
- this[prop] = init[prop];
- this.synthetic = true;
- }
-
- var Np = Node.prototype = SyntheticNode.prototype = {};
- Np.constructor = Node;
-
- const TO_SOURCE_SKIP = {
- type: true,
- value: true,
- lineno: true,
- start: true,
- end: true,
- tokenizer: true,
- assignOp: true
- };
- function unevalableConst(code) {
- var token = definitions.tokens[code];
- var constName = definitions.opTypeNames.hasOwnProperty(token)
- ? definitions.opTypeNames[token]
- : token in definitions.keywords
- ? token.toUpperCase()
- : token;
- return { toSource: function() { return constName } };
- }
- Np.toSource = function toSource() {
- var mock = {};
- var self = this;
- mock.type = unevalableConst(this.type);
- if ("value" in this)
- mock.value = this.value;
- if ("lineno" in this)
- mock.lineno = this.lineno;
- if ("start" in this)
- mock.start = this.start;
- if ("end" in this)
- mock.end = this.end;
- if (this.assignOp)
- mock.assignOp = unevalableConst(this.assignOp);
- for (var key in this) {
- if (this.hasOwnProperty(key) && !(key in TO_SOURCE_SKIP))
- mock[key] = this[key];
- }
- return mock.toSource();
- };
-
- // Always use push to add operands to an expression, to update start and end.
- Np.push = function (kid) {
- // kid can be null e.g. [1, , 2].
- if (kid !== null) {
- if (kid.start < this.start)
- this.start = kid.start;
- if (this.end < kid.end)
- this.end = kid.end;
- }
- return this.children.push(kid);
- }
-
- Node.indentLevel = 0;
-
- function tokenString(tt) {
- var t = definitions.tokens[tt];
- return /^\W/.test(t) ? definitions.opTypeNames[t] : t.toUpperCase();
- }
-
- Np.toString = function () {
- var a = [];
- for (var i in this) {
- if (this.hasOwnProperty(i) && i !== 'type' && i !== 'target')
- a.push({id: i, value: this[i]});
- }
- a.sort(function (a,b) { return (a.id < b.id) ? -1 : 1; });
- const INDENTATION = " ";
- var n = ++Node.indentLevel;
- var s = "{\n" + INDENTATION.repeat(n) + "type: " + tokenString(this.type);
- for (i = 0; i < a.length; i++)
- s += ",\n" + INDENTATION.repeat(n) + a[i].id + ": " + a[i].value;
- n = --Node.indentLevel;
- s += "\n" + INDENTATION.repeat(n) + "}";
- return s;
- }
-
- Np.getSource = function () {
- return this.tokenizer.source.slice(this.start, this.end);
- };
-
- /*
- * Helper init objects for common nodes.
- */
-
- const LOOP_INIT = { isLoop: true };
-
- function blockInit() {
- return { type: BLOCK, varDecls: [] };
- }
-
- function scriptInit() {
- return { type: SCRIPT,
- funDecls: [],
- varDecls: [],
- modDefns: new StringMap(),
- modAssns: new StringMap(),
- modDecls: new StringMap(),
- modLoads: new StringMap(),
- impDecls: [],
- expDecls: [],
- exports: new StringMap(),
- hasEmptyReturn: false,
- hasReturnWithValue: false,
- isGenerator: false };
- }
-
- definitions.defineGetter(Np, "filename",
- function() {
- return this.tokenizer.filename;
- });
-
- definitions.defineGetter(Np, "length",
- function() {
- throw new Error("Node.prototype.length is gone; " +
- "use n.children.length instead");
- });
-
- definitions.defineProperty(String.prototype, "repeat",
- function(n) {
- var s = "", t = this + s;
- while (--n >= 0)
- s += t;
- return s;
- }, false, false, true);
-
- function MaybeLeftParen(t, x) {
- if (x.parenFreeMode)
- return t.match(LEFT_PAREN) ? LEFT_PAREN : END;
- return t.mustMatch(LEFT_PAREN).type;
- }
-
- function MaybeRightParen(t, p) {
- if (p === LEFT_PAREN)
- t.mustMatch(RIGHT_PAREN);
- }
-
- /*
- * Statements :: (tokenizer, compiler context, node) -> void
- *
- * Parses a sequence of Statements.
- */
- function Statements(t, x, n) {
- try {
- while (!t.done && t.peek(true) !== RIGHT_CURLY)
- n.push(Statement(t, x));
- } catch (e) {
- if (t.done)
- t.unexpectedEOF = true;
- throw e;
- }
- }
-
- function Block(t, x) {
- t.mustMatch(LEFT_CURLY);
- var n = new Node(t, blockInit());
- Statements(t, x.update({ parentBlock: n }).pushTarget(n), n);
- t.mustMatch(RIGHT_CURLY);
- return n;
- }
-
- const DECLARED_FORM = 0, EXPRESSED_FORM = 1, STATEMENT_FORM = 2;
-
- /*
- * Export :: (binding node, boolean) -> Export
- *
- * Static semantic representation of a module export.
- */
- function Export(node, isDefinition) {
- this.node = node; // the AST node declaring this individual export
- this.isDefinition = isDefinition; // is the node an 'export'-annotated definition?
- this.resolved = null; // resolved pointer to the target of this export
- }
-
- /*
- * registerExport :: (StringMap, EXPORT node) -> void
- */
- function registerExport(exports, decl) {
- function register(name, exp) {
- if (exports.has(name))
- throw new SyntaxError("multiple exports of " + name);
- exports.set(name, exp);
- }
-
- switch (decl.type) {
- case MODULE:
- case FUNCTION:
- register(decl.name, new Export(decl, true));
- break;
-
- case VAR:
- for (var i = 0; i < decl.children.length; i++)
- register(decl.children[i].name, new Export(decl.children[i], true));
- break;
-
- case LET:
- case CONST:
- throw new Error("NYI: " + definitions.tokens[decl.type]);
-
- case EXPORT:
- for (var i = 0; i < decl.pathList.length; i++) {
- var path = decl.pathList[i];
- switch (path.type) {
- case OBJECT_INIT:
- for (var j = 0; j < path.children.length; j++) {
- // init :: IDENTIFIER | PROPERTY_INIT
- var init = path.children[j];
- if (init.type === IDENTIFIER)
- register(init.value, new Export(init, false));
- else
- register(init.children[0].value, new Export(init.children[1], false));
- }
- break;
-
- case DOT:
- register(path.children[1].value, new Export(path, false));
- break;
-
- case IDENTIFIER:
- register(path.value, new Export(path, false));
- break;
-
- default:
- throw new Error("unexpected export path: " + definitions.tokens[path.type]);
- }
- }
- break;
-
- default:
- throw new Error("unexpected export decl: " + definitions.tokens[exp.type]);
- }
- }
-
- /*
- * Module :: (node) -> Module
- *
- * Static semantic representation of a module.
- */
- function Module(node) {
- var exports = node.body.exports;
- var modDefns = node.body.modDefns;
-
- var exportedModules = new StringMap();
-
- exports.forEach(function(name, exp) {
- var node = exp.node;
- if (node.type === MODULE) {
- exportedModules.set(name, node);
- } else if (!exp.isDefinition && node.type === IDENTIFIER && modDefns.has(node.value)) {
- var mod = modDefns.get(node.value);
- exportedModules.set(name, mod);
- }
- });
-
- this.node = node;
- this.exports = exports;
- this.exportedModules = exportedModules;
- }
-
- /*
- * Statement :: (tokenizer, compiler context) -> node
- *
- * Parses a Statement.
- */
- function Statement(t, x) {
- var i, label, n, n2, p, c, ss, tt = t.get(true), tt2, x2, x3;
-
- var comments = t.blockComments;
-
- if (x.blackList[tt])
- throw t.newSyntaxError(definitions.tokens[tt] + " statements only allowed in Harmony");
- if (!x.allow(tt))
- throw t.newSyntaxError(definitions.tokens[tt] + " statement in illegal context");
-
- // Cases for statements ending in a right curly return early, avoiding the
- // common semicolon insertion magic after this switch.
- switch (tt) {
- case IMPORT:
- n = new Node(t);
- n.pathList = ImportPathList(t, x);
- x.parentScript.impDecls.push(n);
- break;
-
- case EXPORT:
- switch (t.peek()) {
- case MODULE:
- case FUNCTION:
- case LET:
- case VAR:
- case CONST:
- n = Statement(t, x);
- n.blockComments = comments;
- n.exported = true;
- x.parentScript.expDecls.push(n);
- registerExport(x.parentScript.exports, n);
- return n;
-
- default:
- n = new Node(t);
- n.pathList = ExportPathList(t, x);
- break;
- }
- x.parentScript.expDecls.push(n);
- registerExport(x.parentScript.exports, n);
- break;
-
- case MODULE:
- n = new Node(t);
- n.blockComments = comments;
- t.mustMatch(IDENTIFIER);
- label = t.token.value;
-
- if (t.match(LEFT_CURLY)) {
- n.name = label;
- n.body = Script(t, true, false);
- n.module = new Module(n);
- t.mustMatch(RIGHT_CURLY);
- x.parentScript.modDefns.set(n.name, n);
- return n;
- }
-
- t.unget();
- ModuleVariables(t, x, n);
- return n;
-
- case FUNCTION:
- // DECLARED_FORM extends funDecls of x, STATEMENT_FORM doesn't.
- return FunctionDefinition(t, x, true, x.topLevel ? DECLARED_FORM : STATEMENT_FORM, comments);
-
- case LEFT_CURLY:
- n = new Node(t, blockInit());
- Statements(t, x.update({ parentBlock: n }).pushTarget(n).nest(), n);
- t.mustMatch(RIGHT_CURLY);
- return n;
-
- case IF:
- n = new Node(t);
- n.condition = HeadExpression(t, x);
- x2 = x.pushTarget(n).nest();
- n.thenPart = Statement(t, x2);
- n.elsePart = t.match(ELSE, true) ? Statement(t, x2) : null;
- return n;
-
- case SWITCH:
- // This allows CASEs after a DEFAULT, which is in the standard.
- n = new Node(t, { cases: [], defaultIndex: -1 });
- n.discriminant = HeadExpression(t, x);
- x2 = x.pushTarget(n).nest();
- t.mustMatch(LEFT_CURLY);
- while ((tt = t.get()) !== RIGHT_CURLY) {
- switch (tt) {
- case DEFAULT:
- if (n.defaultIndex >= 0)
- throw t.newSyntaxError("More than one switch default");
- // FALL THROUGH
- case CASE:
- n2 = new Node(t);
- if (tt === DEFAULT)
- n.defaultIndex = n.cases.length;
- else
- n2.caseLabel = Expression(t, x2, COLON);
- break;
-
- default:
- throw t.newSyntaxError("Invalid switch case");
- }
- t.mustMatch(COLON);
- n2.statements = new Node(t, blockInit());
- while ((tt=t.peek(true)) !== CASE && tt !== DEFAULT &&
- tt !== RIGHT_CURLY)
- n2.statements.push(Statement(t, x2));
- n.cases.push(n2);
- }
- return n;
-
- case FOR:
- n = new Node(t, LOOP_INIT);
- n.blockComments = comments;
- if (t.match(IDENTIFIER)) {
- if (t.token.value === "each")
- n.isEach = true;
- else
- t.unget();
- }
- if (!x.parenFreeMode)
- t.mustMatch(LEFT_PAREN);
- x2 = x.pushTarget(n).nest();
- x3 = x.update({ inForLoopInit: true });
- n2 = null;
- if ((tt = t.peek(true)) !== SEMICOLON) {
- if (tt === VAR || tt === CONST) {
- t.get();
- n2 = Variables(t, x3);
- } else if (tt === LET) {
- t.get();
- if (t.peek() === LEFT_PAREN) {
- n2 = LetBlock(t, x3, false);
- } else {
- // Let in for head, we need to add an implicit block
- // around the rest of the for.
- x3.parentBlock = n;
- n.varDecls = [];
- n2 = Variables(t, x3);
- }
- } else {
- n2 = Expression(t, x3);
- }
- }
- if (n2 && t.match(IN)) {
- n.type = FOR_IN;
- n.object = Expression(t, x3);
- if (n2.type === VAR || n2.type === LET) {
- c = n2.children;
-
- // Destructuring turns one decl into multiples, so either
- // there must be only one destructuring or only one
- // decl.
- if (c.length !== 1 && n2.destructurings.length !== 1) {
- throw new SyntaxError("Invalid for..in left-hand side",
- t.filename, n2.lineno);
- }
- if (n2.destructurings.length > 0) {
- n.iterator = n2.destructurings[0];
- } else {
- n.iterator = c[0];
- }
- n.varDecl = n2;
- } else {
- if (n2.type === ARRAY_INIT || n2.type === OBJECT_INIT) {
- n2.destructuredNames = checkDestructuring(t, x3, n2);
- }
- n.iterator = n2;
- }
- } else {
- x3.inForLoopInit = false;
- n.setup = n2;
- t.mustMatch(SEMICOLON);
- if (n.isEach)
- throw t.newSyntaxError("Invalid for each..in loop");
- n.condition = (t.peek(true) === SEMICOLON)
- ? null
- : Expression(t, x3);
- t.mustMatch(SEMICOLON);
- tt2 = t.peek(true);
- n.update = (x.parenFreeMode
- ? tt2 === LEFT_CURLY || definitions.isStatementStartCode[tt2]
- : tt2 === RIGHT_PAREN)
- ? null
- : Expression(t, x3);
- }
- if (!x.parenFreeMode)
- t.mustMatch(RIGHT_PAREN);
- n.body = Statement(t, x2);
- return n;
-
- case WHILE:
- n = new Node(t, { isLoop: true });
- n.blockComments = comments;
- n.condition = HeadExpression(t, x);
- n.body = Statement(t, x.pushTarget(n).nest());
- return n;
-
- case DO:
- n = new Node(t, { isLoop: true });
- n.blockComments = comments;
- n.body = Statement(t, x.pushTarget(n).nest());
- t.mustMatch(WHILE);
- n.condition = HeadExpression(t, x);
- if (!x.ecmaStrictMode) {
- // <script language="JavaScript"> (without version hints) may need
- // automatic semicolon insertion without a newline after do-while.
- // See http://bugzilla.mozilla.org/show_bug.cgi?id=238945.
- t.match(SEMICOLON);
- return n;
- }
- break;
-
- case BREAK:
- case CONTINUE:
- n = new Node(t);
- n.blockComments = comments;
-
- // handle the |foo: break foo;| corner case
- x2 = x.pushTarget(n);
-
- if (t.peekOnSameLine() === IDENTIFIER) {
- t.get();
- n.label = t.token.value;
- }
-
- if (n.label) {
- n.target = x2.labeledTargets.find(function(target) { return target.labels.has(n.label) });
- } else if (tt === CONTINUE) {
- n.target = x2.defaultLoopTarget;
- } else {
- n.target = x2.defaultTarget;
- }
-
- if (!n.target)
- throw t.newSyntaxError("Invalid " + ((tt === BREAK) ? "break" : "continue"));
- if (!n.target.isLoop && tt === CONTINUE)
- throw t.newSyntaxError("Invalid continue");
-
- break;
-
- case TRY:
- n = new Node(t, { catchClauses: [] });
- n.blockComments = comments;
- n.tryBlock = Block(t, x);
- while (t.match(CATCH)) {
- n2 = new Node(t);
- p = MaybeLeftParen(t, x);
- switch (t.get()) {
- case LEFT_BRACKET:
- case LEFT_CURLY:
- // Destructured catch identifiers.
- t.unget();
- n2.varName = DestructuringExpression(t, x, true);
- break;
- case IDENTIFIER:
- n2.varName = t.token.value;
- break;
- default:
- throw t.newSyntaxError("missing identifier in catch");
- break;
- }
- if (t.match(IF)) {
- if (x.ecma3OnlyMode)
- throw t.newSyntaxError("Illegal catch guard");
- if (n.catchClauses.length && !n.catchClauses.top().guard)
- throw t.newSyntaxError("Guarded catch after unguarded");
- n2.guard = Expression(t, x);
- }
- MaybeRightParen(t, p);
- n2.block = Block(t, x);
- n.catchClauses.push(n2);
- }
- if (t.match(FINALLY))
- n.finallyBlock = Block(t, x);
- if (!n.catchClauses.length && !n.finallyBlock)
- throw t.newSyntaxError("Invalid try statement");
- return n;
-
- case CATCH:
- case FINALLY:
- throw t.newSyntaxError(definitions.tokens[tt] + " without preceding try");
-
- case THROW:
- n = new Node(t);
- n.exception = Expression(t, x);
- break;
-
- case RETURN:
- n = ReturnOrYield(t, x);
- break;
-
- case WITH:
- n = new Node(t);
- n.blockComments = comments;
- n.object = HeadExpression(t, x);
- n.body = Statement(t, x.pushTarget(n).nest());
- return n;
-
- case VAR:
- case CONST:
- n = Variables(t, x);
- break;
-
- case LET:
- if (t.peek() === LEFT_PAREN)
- n = LetBlock(t, x, true);
- else
- n = Variables(t, x);
- break;
-
- case DEBUGGER:
- n = new Node(t);
- break;
-
- case NEWLINE:
- case SEMICOLON:
- n = new Node(t, { type: SEMICOLON });
- n.blockComments = comments;
- n.expression = null;
- return n;
-
- default:
- if (tt === IDENTIFIER) {
- tt = t.peek();
- // Labeled statement.
- if (tt === COLON) {
- label = t.token.value;
- if (x.allLabels.has(label))
- throw t.newSyntaxError("Duplicate label");
- t.get();
- n = new Node(t, { type: LABEL, label: label });
- n.blockComments = comments;
- n.statement = Statement(t, x.pushLabel(label).nest());
- n.target = (n.statement.type === LABEL) ? n.statement.target : n.statement;
- return n;
- }
- }
-
- // Expression statement.
- // We unget the current token to parse the expression as a whole.
- n = new Node(t, { type: SEMICOLON });
- t.unget();
- n.blockComments = comments;
- n.expression = Expression(t, x);
- n.end = n.expression.end;
- break;
- }
-
- n.blockComments = comments;
- MagicalSemicolon(t);
- return n;
- }
-
- /*
- * MagicalSemicolon :: (tokenizer) -> void
- */
- function MagicalSemicolon(t) {
- var tt;
- if (t.lineno === t.token.lineno) {
- tt = t.peekOnSameLine();
- if (tt !== END && tt !== NEWLINE && tt !== SEMICOLON && tt !== RIGHT_CURLY)
- throw t.newSyntaxError("missing ; before statement");
- }
- t.match(SEMICOLON);
- }
-
- /*
- * ReturnOrYield :: (tokenizer, compiler context) -> (RETURN | YIELD) node
- */
- function ReturnOrYield(t, x) {
- var n, b, tt = t.token.type, tt2;
-
- var parentScript = x.parentScript;
-
- if (tt === RETURN) {
- if (!x.inFunction)
- throw t.newSyntaxError("Return not in function");
- } else /* if (tt === YIELD) */ {
- if (!x.inFunction)
- throw t.newSyntaxError("Yield not in function");
- parentScript.isGenerator = true;
- }
- n = new Node(t, { value: undefined });
-
- tt2 = (tt === RETURN) ? t.peekOnSameLine(true) : t.peek(true);
- if (tt2 !== END && tt2 !== NEWLINE &&
- tt2 !== SEMICOLON && tt2 !== RIGHT_CURLY
- && (tt !== YIELD ||
- (tt2 !== tt && tt2 !== RIGHT_BRACKET && tt2 !== RIGHT_PAREN &&
- tt2 !== COLON && tt2 !== COMMA))) {
- if (tt === RETURN) {
- n.value = Expression(t, x);
- parentScript.hasReturnWithValue = true;
- } else {
- n.value = AssignExpression(t, x);
- }
- } else if (tt === RETURN) {
- parentScript.hasEmptyReturn = true;
- }
-
- // Disallow return v; in generator.
- if (parentScript.hasReturnWithValue && parentScript.isGenerator)
- throw t.newSyntaxError("Generator returns a value");
-
- return n;
- }
-
- /*
- * ModuleExpression :: (tokenizer, compiler context) -> (STRING | IDENTIFIER | DOT) node
- */
- function ModuleExpression(t, x) {
- return t.match(STRING) ? new Node(t) : QualifiedPath(t, x);
- }
-
- /*
- * ImportPathList :: (tokenizer, compiler context) -> Array[DOT node]
- */
- function ImportPathList(t, x) {
- var a = [];
- do {
- a.push(ImportPath(t, x));
- } while (t.match(COMMA));
- return a;
- }
-
- /*
- * ImportPath :: (tokenizer, compiler context) -> DOT node
- */
- function ImportPath(t, x) {
- var n = QualifiedPath(t, x);
- if (!t.match(DOT)) {
- if (n.type === IDENTIFIER)
- throw t.newSyntaxError("cannot import local variable");
- return n;
- }
-
- var n2 = new Node(t);
- n2.push(n);
- n2.push(ImportSpecifierSet(t, x));
- return n2;
- }
-
- /*
- * ExplicitSpecifierSet :: (tokenizer, compiler context, (tokenizer, compiler context) -> node)
- * -> OBJECT_INIT node
- */
- function ExplicitSpecifierSet(t, x, SpecifierRHS) {
- var n, n2, id, tt;
-
- n = new Node(t, { type: OBJECT_INIT });
- t.mustMatch(LEFT_CURLY);
-
- if (!t.match(RIGHT_CURLY)) {
- do {
- id = Identifier(t, x);
- if (t.match(COLON)) {
- n2 = new Node(t, { type: PROPERTY_INIT });
- n2.push(id);
- n2.push(SpecifierRHS(t, x));
- n.push(n2);
- } else {
- n.push(id);
- }
- } while (!t.match(RIGHT_CURLY) && t.mustMatch(COMMA));
- }
-
- return n;
- }
-
- /*
- * ImportSpecifierSet :: (tokenizer, compiler context) -> (IDENTIFIER | OBJECT_INIT) node
- */
- function ImportSpecifierSet(t, x) {
- return t.match(MUL)
- ? new Node(t, { type: IDENTIFIER, name: "*" })
- : ExplicitSpecifierSet(t, x, Identifier);
- }
-
- /*
- * Identifier :: (tokenizer, compiler context) -> IDENTIFIER node
- */
- function Identifier(t, x) {
- t.mustMatch(IDENTIFIER);
- return new Node(t, { type: IDENTIFIER });
- }
-
- /*
- * IdentifierName :: (tokenizer) -> IDENTIFIER node
- */
- function IdentifierName(t) {
- if (t.match(IDENTIFIER))
- return new Node(t, { type: IDENTIFIER });
- t.get();
- if (t.token.value in definitions.keywords)
- return new Node(t, { type: IDENTIFIER });
- throw t.newSyntaxError("missing IdentifierName");
- }
-
- /*
- * QualifiedPath :: (tokenizer, compiler context) -> (IDENTIFIER | DOT) node
- */
- function QualifiedPath(t, x) {
- var n, n2;
-
- n = Identifier(t, x);
-
- while (t.match(DOT)) {
- if (t.peek() !== IDENTIFIER) {
- // Unget the '.' token, which isn't part of the QualifiedPath.
- t.unget();
- break;
- }
- n2 = new Node(t);
- n2.push(n);
- n2.push(Identifier(t, x));
- n = n2;
- }
-
- return n;
- }
-
- /*
- * ExportPath :: (tokenizer, compiler context) -> (IDENTIFIER | DOT | OBJECT_INIT) node
- */
- function ExportPath(t, x) {
- if (t.peek() === LEFT_CURLY)
- return ExplicitSpecifierSet(t, x, QualifiedPath);
- return QualifiedPath(t, x);
- }
-
- /*
- * ExportPathList :: (tokenizer, compiler context)
- * -> Array[(IDENTIFIER | DOT | OBJECT_INIT) node]
- */
- function ExportPathList(t, x) {
- var a = [];
- do {
- a.push(ExportPath(t, x));
- } while (t.match(COMMA));
- return a;
- }
-
- /*
- * FunctionDefinition :: (tokenizer, compiler context, boolean,
- * DECLARED_FORM or EXPRESSED_FORM or STATEMENT_FORM,
- * [string] or null or undefined)
- * -> node
- */
- function FunctionDefinition(t, x, requireName, functionForm, comments) {
- var tt;
- var f = new Node(t, { params: [], paramComments: [] });
- if (typeof comment === "undefined")
- comment = null;
- f.blockComments = comments;
- if (f.type !== FUNCTION)
- f.type = (f.value === "get") ? GETTER : SETTER;
- if (t.match(IDENTIFIER))
- f.name = t.token.value;
- else if (requireName)
- throw t.newSyntaxError("missing function identifier");
-
- var inModule = x ? x.inModule : false;
- var x2 = new StaticContext(null, null, inModule, true);
-
- t.mustMatch(LEFT_PAREN);
- if (!t.match(RIGHT_PAREN)) {
- do {
- tt = t.get();
- f.paramComments.push(t.lastBlockComment());
- switch (tt) {
- case LEFT_BRACKET:
- case LEFT_CURLY:
- // Destructured formal parameters.
- t.unget();
- f.params.push(DestructuringExpression(t, x2));
- break;
- case IDENTIFIER:
- f.params.push(t.token.value);
- break;
- default:
- throw t.newSyntaxError("missing formal parameter");
- break;
- }
- } while (t.match(COMMA));
- t.mustMatch(RIGHT_PAREN);
- }
-
- // Do we have an expression closure or a normal body?
- tt = t.get();
- if (tt !== LEFT_CURLY)
- t.unget();
-
- if (tt !== LEFT_CURLY) {
- f.body = AssignExpression(t, x2);
- if (f.body.isGenerator)
- throw t.newSyntaxError("Generator returns a value");
- } else {
- f.body = Script(t, inModule, true);
- }
-
- if (tt === LEFT_CURLY)
- t.mustMatch(RIGHT_CURLY);
-
- f.end = t.token.end;
- f.functionForm = functionForm;
- if (functionForm === DECLARED_FORM)
- x.parentScript.funDecls.push(f);
- return f;
- }
-
- /*
- * ModuleVariables :: (tokenizer, compiler context, MODULE node) -> void
- *
- * Parses a comma-separated list of module declarations (and maybe
- * initializations).
- */
- function ModuleVariables(t, x, n) {
- var n1, n2;
- do {
- n1 = Identifier(t, x);
- if (t.match(ASSIGN)) {
- n2 = ModuleExpression(t, x);
- n1.initializer = n2;
- if (n2.type === STRING)
- x.parentScript.modLoads.set(n1.value, n2.value);
- else
- x.parentScript.modAssns.set(n1.value, n1);
- }
- n.push(n1);
- } while (t.match(COMMA));
- }
-
- /*
- * Variables :: (tokenizer, compiler context) -> node
- *
- * Parses a comma-separated list of var declarations (and maybe
- * initializations).
- */
- function Variables(t, x, letBlock) {
- var n, n2, ss, i, s, tt;
-
- tt = t.token.type;
- switch (tt) {
- case VAR:
- case CONST:
- s = x.parentScript;
- break;
- case LET:
- s = x.parentBlock;
- break;
- case LEFT_PAREN:
- tt = LET;
- s = letBlock;
- break;
- }
-
- n = new Node(t, { type: tt, destructurings: [] });
-
- do {
- tt = t.get();
- if (tt === LEFT_BRACKET || tt === LEFT_CURLY) {
- // Need to unget to parse the full destructured expression.
- t.unget();
-
- var dexp = DestructuringExpression(t, x, true);
-
- n2 = new Node(t, { type: IDENTIFIER,
- name: dexp,
- readOnly: n.type === CONST });
- n.push(n2);
- pushDestructuringVarDecls(n2.name.destructuredNames, s);
- n.destructurings.push({ exp: dexp, decl: n2 });
-
- if (x.inForLoopInit && t.peek() === IN) {
- continue;
- }
-
- t.mustMatch(ASSIGN);
- if (t.token.assignOp)
- throw t.newSyntaxError("Invalid variable initialization");
-
- n2.blockComment = t.lastBlockComment();
- n2.initializer = AssignExpression(t, x);
-
- continue;
- }
-
- if (tt !== IDENTIFIER)
- throw t.newSyntaxError("missing variable name");
-
- n2 = new Node(t, { type: IDENTIFIER,
- name: t.token.value,
- readOnly: n.type === CONST });
- n.push(n2);
- s.varDecls.push(n2);
-
- if (t.match(ASSIGN)) {
- var comment = t.lastBlockComment();
- if (t.token.assignOp)
- throw t.newSyntaxError("Invalid variable initialization");
-
- n2.initializer = AssignExpression(t, x);
- } else {
- var comment = t.lastBlockComment();
- }
- n2.blockComment = comment;
- } while (t.match(COMMA));
-
- return n;
- }
-
- /*
- * LetBlock :: (tokenizer, compiler context, boolean) -> node
- *
- * Does not handle let inside of for loop init.
- */
- function LetBlock(t, x, isStatement) {
- var n, n2;
-
- // t.token.type must be LET
- n = new Node(t, { type: LET_BLOCK, varDecls: [] });
- t.mustMatch(LEFT_PAREN);
- n.variables = Variables(t, x, n);
- t.mustMatch(RIGHT_PAREN);
-
- if (isStatement && t.peek() !== LEFT_CURLY) {
- /*
- * If this is really an expression in let statement guise, then we
- * need to wrap the LET_BLOCK node in a SEMICOLON node so that we pop
- * the return value of the expression.
- */
- n2 = new Node(t, { type: SEMICOLON,
- expression: n });
- isStatement = false;
- }
-
- if (isStatement)
- n.block = Block(t, x);
- else
- n.expression = AssignExpression(t, x);
-
- return n;
- }
-
- function checkDestructuring(t, x, n, simpleNamesOnly) {
- if (n.type === ARRAY_COMP)
- throw t.newSyntaxError("Invalid array comprehension left-hand side");
- if (n.type !== ARRAY_INIT && n.type !== OBJECT_INIT)
- return;
-
- var lhss = {};
- var nn, n2, idx, sub, cc, c = n.children;
- for (var i = 0, j = c.length; i < j; i++) {
- if (!(nn = c[i]))
- continue;
- if (nn.type === PROPERTY_INIT) {
- cc = nn.children;
- sub = cc[1];
- idx = cc[0].value;
- } else if (n.type === OBJECT_INIT) {
- // Do we have destructuring shorthand {foo, bar}?
- sub = nn;
- idx = nn.value;
- } else {
- sub = nn;
- idx = i;
- }
-
- if (sub.type === ARRAY_INIT || sub.type === OBJECT_INIT) {
- lhss[idx] = checkDestructuring(t, x, sub, simpleNamesOnly);
- } else {
- if (simpleNamesOnly && sub.type !== IDENTIFIER) {
- // In declarations, lhs must be simple names
- throw t.newSyntaxError("missing name in pattern");
- }
-
- lhss[idx] = sub;
- }
- }
-
- return lhss;
- }
-
- function DestructuringExpression(t, x, simpleNamesOnly) {
- var n = PrimaryExpression(t, x);
- // Keep the list of lefthand sides for varDecls
- n.destructuredNames = checkDestructuring(t, x, n, simpleNamesOnly);
- return n;
- }
-
- function GeneratorExpression(t, x, e) {
- return new Node(t, { type: GENERATOR,
- expression: e,
- tail: ComprehensionTail(t, x) });
- }
-
- function ComprehensionTail(t, x) {
- var body, n, n2, n3, p;
-
- // t.token.type must be FOR
- body = new Node(t, { type: COMP_TAIL });
-
- do {
- // Comprehension tails are always for..in loops.
- n = new Node(t, { type: FOR_IN, isLoop: true });
- if (t.match(IDENTIFIER)) {
- // But sometimes they're for each..in.
- if (t.token.value === "each")
- n.isEach = true;
- else
- t.unget();
- }
- p = MaybeLeftParen(t, x);
- switch(t.get()) {
- case LEFT_BRACKET:
- case LEFT_CURLY:
- t.unget();
- // Destructured left side of for in comprehension tails.
- n.iterator = DestructuringExpression(t, x);
- break;
-
- case IDENTIFIER:
- n.iterator = n3 = new Node(t, { type: IDENTIFIER });
- n3.name = n3.value;
- n.varDecl = n2 = new Node(t, { type: VAR });
- n2.push(n3);
- x.parentScript.varDecls.push(n3);
- // Don't add to varDecls since the semantics of comprehensions is
- // such that the variables are in their own function when
- // desugared.
- break;
-
- default:
- throw t.newSyntaxError("missing identifier");
- }
- t.mustMatch(IN);
- n.object = Expression(t, x);
- MaybeRightParen(t, p);
- body.push(n);
- } while (t.match(FOR));
-
- // Optional guard.
- if (t.match(IF))
- body.guard = HeadExpression(t, x);
-
- return body;
- }
-
- function HeadExpression(t, x) {
- var p = MaybeLeftParen(t, x);
- var n = ParenExpression(t, x);
- MaybeRightParen(t, p);
- if (p === END && !n.parenthesized) {
- var tt = t.peek();
- if (tt !== LEFT_CURLY && !definitions.isStatementStartCode[tt])
- throw t.newSyntaxError("Unparenthesized head followed by unbraced body");
- }
- return n;
- }
-
- function ParenExpression(t, x) {
- // Always accept the 'in' operator in a parenthesized expression,
- // where it's unambiguous, even if we might be parsing the init of a
- // for statement.
- var n = Expression(t, x.update({ inForLoopInit: x.inForLoopInit &&
- (t.token.type === LEFT_PAREN) }));
-
- if (t.match(FOR)) {
- if (n.type === YIELD && !n.parenthesized)
- throw t.newSyntaxError("Yield expression must be parenthesized");
- if (n.type === COMMA && !n.parenthesized)
- throw t.newSyntaxError("Generator expression must be parenthesized");
- n = GeneratorExpression(t, x, n);
- }
-
- return n;
- }
-
- /*
- * Expression :: (tokenizer, compiler context) -> node
- *
- * Top-down expression parser matched against SpiderMonkey.
- */
- function Expression(t, x) {
- var n, n2;
-
- n = AssignExpression(t, x);
- if (t.match(COMMA)) {
- n2 = new Node(t, { type: COMMA });
- n2.push(n);
- n = n2;
- do {
- n2 = n.children[n.children.length-1];
- if (n2.type === YIELD && !n2.parenthesized)
- throw t.newSyntaxError("Yield expression must be parenthesized");
- n.push(AssignExpression(t, x));
- } while (t.match(COMMA));
- }
-
- return n;
- }
-
- function AssignExpression(t, x) {
- var n, lhs;
-
- // Have to treat yield like an operand because it could be the leftmost
- // operand of the expression.
- if (t.match(YIELD, true))
- return ReturnOrYield(t, x);
-
- n = new Node(t, { type: ASSIGN });
- lhs = ConditionalExpression(t, x);
-
- if (!t.match(ASSIGN)) {
- return lhs;
- }
-
- n.blockComment = t.lastBlockComment();
-
- switch (lhs.type) {
- case OBJECT_INIT:
- case ARRAY_INIT:
- lhs.destructuredNames = checkDestructuring(t, x, lhs);
- // FALL THROUGH
- case IDENTIFIER: case DOT: case INDEX: case CALL:
- break;
- default:
- throw t.newSyntaxError("Bad left-hand side of assignment");
- break;
- }
-
- n.assignOp = lhs.assignOp = t.token.assignOp;
- n.push(lhs);
- n.push(AssignExpression(t, x));
-
- return n;
- }
-
- function ConditionalExpression(t, x) {
- var n, n2;
-
- n = OrExpression(t, x);
- if (t.match(HOOK)) {
- n2 = n;
- n = new Node(t, { type: HOOK });
- n.push(n2);
- /*
- * Always accept the 'in' operator in the middle clause of a ternary,
- * where it's unambiguous, even if we might be parsing the init of a
- * for statement.
- */
- n.push(AssignExpression(t, x.update({ inForLoopInit: false })));
- if (!t.match(COLON))
- throw t.newSyntaxError("missing : after ?");
- n.push(AssignExpression(t, x));
- }
-
- return n;
- }
-
- function OrExpression(t, x) {
- var n, n2;
-
- n = AndExpression(t, x);
- while (t.match(OR)) {
- n2 = new Node(t);
- n2.push(n);
- n2.push(AndExpression(t, x));
- n = n2;
- }
-
- return n;
- }
-
- function AndExpression(t, x) {
- var n, n2;
-
- n = BitwiseOrExpression(t, x);
- while (t.match(AND)) {
- n2 = new Node(t);
- n2.push(n);
- n2.push(BitwiseOrExpression(t, x));
- n = n2;
- }
-
- return n;
- }
-
- function BitwiseOrExpression(t, x) {
- var n, n2;
-
- n = BitwiseXorExpression(t, x);
- while (t.match(BITWISE_OR)) {
- n2 = new Node(t);
- n2.push(n);
- n2.push(BitwiseXorExpression(t, x));
- n = n2;
- }
-
- return n;
- }
-
- function BitwiseXorExpression(t, x) {
- var n, n2;
-
- n = BitwiseAndExpression(t, x);
- while (t.match(BITWISE_XOR)) {
- n2 = new Node(t);
- n2.push(n);
- n2.push(BitwiseAndExpression(t, x));
- n = n2;
- }
-
- return n;
- }
-
- function BitwiseAndExpression(t, x) {
- var n, n2;
-
- n = EqualityExpression(t, x);
- while (t.match(BITWISE_AND)) {
- n2 = new Node(t);
- n2.push(n);
- n2.push(EqualityExpression(t, x));
- n = n2;
- }
-
- return n;
- }
-
- function EqualityExpression(t, x) {
- var n, n2;
-
- n = RelationalExpression(t, x);
- while (t.match(EQ) || t.match(NE) ||
- t.match(STRICT_EQ) || t.match(STRICT_NE)) {
- n2 = new Node(t);
- n2.push(n);
- n2.push(RelationalExpression(t, x));
- n = n2;
- }
-
- return n;
- }
-
- function RelationalExpression(t, x) {
- var n, n2;
-
- /*
- * Uses of the in operator in shiftExprs are always unambiguous,
- * so unset the flag that prohibits recognizing it.
- */
- var x2 = x.update({ inForLoopInit: false });
- n = ShiftExpression(t, x2);
- while ((t.match(LT) || t.match(LE) || t.match(GE) || t.match(GT) ||
- (!x.inForLoopInit && t.match(IN)) ||
- t.match(INSTANCEOF))) {
- n2 = new Node(t);
- n2.push(n);
- n2.push(ShiftExpression(t, x2));
- n = n2;
- }
-
- return n;
- }
-
- function ShiftExpression(t, x) {
- var n, n2;
-
- n = AddExpression(t, x);
- while (t.match(LSH) || t.match(RSH) || t.match(URSH)) {
- n2 = new Node(t);
- n2.push(n);
- n2.push(AddExpression(t, x));
- n = n2;
- }
-
- return n;
- }
-
- function AddExpression(t, x) {
- var n, n2;
-
- n = MultiplyExpression(t, x);
- while (t.match(PLUS) || t.match(MINUS)) {
- n2 = new Node(t);
- n2.push(n);
- n2.push(MultiplyExpression(t, x));
- n = n2;
- }
-
- return n;
- }
-
- function MultiplyExpression(t, x) {
- var n, n2;
-
- n = UnaryExpression(t, x);
- while (t.match(MUL) || t.match(DIV) || t.match(MOD)) {
- n2 = new Node(t);
- n2.push(n);
- n2.push(UnaryExpression(t, x));
- n = n2;
- }
-
- return n;
- }
-
- function UnaryExpression(t, x) {
- var n, n2, tt;
-
- switch (tt = t.get(true)) {
- case DELETE: case VOID: case TYPEOF:
- case NOT: case BITWISE_NOT: case PLUS: case MINUS:
- if (tt === PLUS)
- n = new Node(t, { type: UNARY_PLUS });
- else if (tt === MINUS)
- n = new Node(t, { type: UNARY_MINUS });
- else
- n = new Node(t);
- n.push(UnaryExpression(t, x));
- break;
-
- case INCREMENT:
- case DECREMENT:
- // Prefix increment/decrement.
- n = new Node(t);
- n.push(MemberExpression(t, x, true));
- break;
-
- default:
- t.unget();
- n = MemberExpression(t, x, true);
-
- // Don't look across a newline boundary for a postfix {in,de}crement.
- if (t.tokens[(t.tokenIndex + t.lookahead - 1) & 3].lineno ===
- t.lineno) {
- if (t.match(INCREMENT) || t.match(DECREMENT)) {
- n2 = new Node(t, { postfix: true });
- n2.push(n);
- n = n2;
- }
- }
- break;
- }
-
- return n;
- }
-
- function MemberExpression(t, x, allowCallSyntax) {
- var n, n2, name, tt;
-
- if (t.match(NEW)) {
- n = new Node(t);
- n.push(MemberExpression(t, x, false));
- if (t.match(LEFT_PAREN)) {
- n.type = NEW_WITH_ARGS;
- n.push(ArgumentList(t, x));
- }
- } else {
- n = PrimaryExpression(t, x);
- }
-
- while ((tt = t.get()) !== END) {
- switch (tt) {
- case DOT:
- n2 = new Node(t);
- n2.push(n);
- n2.push(IdentifierName(t));
- break;
-
- case LEFT_BRACKET:
- n2 = new Node(t, { type: INDEX });
- n2.push(n);
- n2.push(Expression(t, x));
- t.mustMatch(RIGHT_BRACKET);
- break;
-
- case LEFT_PAREN:
- if (allowCallSyntax) {
- n2 = new Node(t, { type: CALL });
- n2.push(n);
- n2.push(ArgumentList(t, x));
- break;
- }
-
- // FALL THROUGH
- default:
- t.unget();
- return n;
- }
-
- n = n2;
- }
-
- return n;
- }
-
- function ArgumentList(t, x) {
- var n, n2;
-
- n = new Node(t, { type: LIST });
- if (t.match(RIGHT_PAREN, true))
- return n;
- do {
- n2 = AssignExpression(t, x);
- if (n2.type === YIELD && !n2.parenthesized && t.peek() === COMMA)
- throw t.newSyntaxError("Yield expression must be parenthesized");
- if (t.match(FOR)) {
- n2 = GeneratorExpression(t, x, n2);
- if (n.children.length > 1 || t.peek(true) === COMMA)
- throw t.newSyntaxError("Generator expression must be parenthesized");
- }
- n.push(n2);
- } while (t.match(COMMA));
- t.mustMatch(RIGHT_PAREN);
-
- return n;
- }
-
- function PrimaryExpression(t, x) {
- var n, n2, tt = t.get(true);
-
- switch (tt) {
- case FUNCTION:
- n = FunctionDefinition(t, x, false, EXPRESSED_FORM);
- break;
-
- case LEFT_BRACKET:
- n = new Node(t, { type: ARRAY_INIT });
- while ((tt = t.peek(true)) !== RIGHT_BRACKET) {
- if (tt === COMMA) {
- t.get();
- n.push(null);
- continue;
- }
- n.push(AssignExpression(t, x));
- if (tt !== COMMA && !t.match(COMMA))
- break;
- }
-
- // If we matched exactly one element and got a FOR, we have an
- // array comprehension.
- if (n.children.length === 1 && t.match(FOR)) {
- n2 = new Node(t, { type: ARRAY_COMP,
- expression: n.children[0],
- tail: ComprehensionTail(t, x) });
- n = n2;
- }
- t.mustMatch(RIGHT_BRACKET);
- break;
-
- case LEFT_CURLY:
- var id, fd;
- n = new Node(t, { type: OBJECT_INIT });
-
- object_init:
- if (!t.match(RIGHT_CURLY)) {
- do {
- tt = t.get();
- if ((t.token.value === "get" || t.token.value === "set") &&
- t.peek() === IDENTIFIER) {
- if (x.ecma3OnlyMode)
- throw t.newSyntaxError("Illegal property accessor");
- n.push(FunctionDefinition(t, x, true, EXPRESSED_FORM));
- } else {
- var comments = t.blockComments;
- switch (tt) {
- case IDENTIFIER: case NUMBER: case STRING:
- id = new Node(t, { type: IDENTIFIER });
- break;
- case RIGHT_CURLY:
- if (x.ecma3OnlyMode)
- throw t.newSyntaxError("Illegal trailing ,");
- break object_init;
- default:
- if (t.token.value in definitions.keywords) {
- id = new Node(t, { type: IDENTIFIER });
- break;
- }
- throw t.newSyntaxError("Invalid property name");
- }
- if (t.match(COLON)) {
- n2 = new Node(t, { type: PROPERTY_INIT });
- n2.push(id);
- n2.push(AssignExpression(t, x));
- n2.blockComments = comments;
- n.push(n2);
- } else {
- // Support, e.g., |var {x, y} = o| as destructuring shorthand
- // for |var {x: x, y: y} = o|, per proposed JS2/ES4 for JS1.8.
- if (t.peek() !== COMMA && t.peek() !== RIGHT_CURLY)
- throw t.newSyntaxError("missing : after property");
- n.push(id);
- }
- }
- } while (t.match(COMMA));
- t.mustMatch(RIGHT_CURLY);
- }
- break;
-
- case LEFT_PAREN:
- n = ParenExpression(t, x);
- t.mustMatch(RIGHT_PAREN);
- n.parenthesized = true;
- break;
-
- case LET:
- n = LetBlock(t, x, false);
- break;
-
- case NULL: case THIS: case TRUE: case FALSE:
- case IDENTIFIER: case NUMBER: case STRING: case REGEXP:
- n = new Node(t);
- break;
-
- default:
- throw t.newSyntaxError("missing operand");
- break;
- }
-
- return n;
- }
-
- /*
- * parse :: (source, filename, line number) -> node
- */
- function parse(s, f, l) {
- var t = new lexer.Tokenizer(s, f, l);
- var n = Script(t, false, false);
- if (!t.done)
- throw t.newSyntaxError("Syntax error");
-
- return n;
- }
-
- /*
- * parseStdin :: (source, {line number}, string, (string) -> boolean) -> program node
- */
- function parseStdin(s, ln, prefix, isCommand) {
- // the special .begin command is only recognized at the beginning
- if (s.match(/^[\s]*\.begin[\s]*$/)) {
- ++ln.value;
- return parseMultiline(ln, prefix);
- }
-
- // commands at the beginning are treated as the entire input
- if (isCommand(s.trim()))
- s = "";
-
- for (;;) {
- try {
- var t = new lexer.Tokenizer(s, "stdin", ln.value);
- var n = Script(t, false, false);
- ln.value = t.lineno;
- return n;
- } catch (e) {
- if (!t.unexpectedEOF)
- throw e;
-
- // commands in the middle are not treated as part of the input
- var more;
- do {
- if (prefix)
- putstr(prefix);
- more = readline();
- if (!more)
- throw e;
- } while (isCommand(more.trim()));
-
- s += "\n" + more;
- }
- }
- }
-
- /*
- * parseMultiline :: ({line number}, string | null) -> program node
- */
- function parseMultiline(ln, prefix) {
- var s = "";
- for (;;) {
- if (prefix)
- putstr(prefix);
- var more = readline();
- if (more === null)
- return null;
- // the only command recognized in multiline mode is .end
- if (more.match(/^[\s]*\.end[\s]*$/))
- break;
- s += "\n" + more;
- }
- var t = new lexer.Tokenizer(s, "stdin", ln.value);
- var n = Script(t, false, false);
- ln.value = t.lineno;
- return n;
- }
-
- module.exports = {
- parse: parse,
- parseStdin: parseStdin,
- Node: Node,
- SyntheticNode: SyntheticNode,
- DECLARED_FORM: DECLARED_FORM,
- EXPRESSED_FORM: EXPRESSED_FORM,
- STATEMENT_FORM: STATEMENT_FORM,
- Tokenizer: lexer.Tokenizer,
- FunctionDefinition: FunctionDefinition,
- Module: Module,
- Export: Export
- };
-
-});/* vim: set sw=4 ts=4 et tw=78: */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is the Narcissus JavaScript engine.
- *
- * The Initial Developer of the Original Code is
- * Brendan Eich <brendan@mozilla.org>.
- * Portions created by the Initial Developer are Copyright (C) 2004
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Tom Austin <taustin@ucsc.edu>
- * Brendan Eich <brendan@mozilla.org>
- * Shu-Yu Guo <shu@rfrn.org>
- * Dave Herman <dherman@mozilla.com>
- * Dimitris Vardoulakis <dimvar@ccs.neu.edu>
- * Patrick Walton <pcwalton@mozilla.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-/*
- * Narcissus - JS implemented in JS.
- *
- * Lexical scanner.
- */
-
- define('ace/narcissus/jslex', ['require', 'exports', 'module' , 'ace/narcissus/jsdefs'], function(require, exports, module) {
-
- var definitions = require("./jsdefs");
-
- // Set constants in the local scope.
- eval(definitions.consts);
-
- // Banned keywords by language version
- const blackLists = { 160: {}, 185: {}, harmony: {} };
- blackLists[160][LET] = true;
- blackLists[160][MODULE] = true;
- blackLists[160][YIELD] = true;
- blackLists[185][MODULE] = true;
-
- // Build up a trie of operator tokens.
- var opTokens = {};
- for (var op in definitions.opTypeNames) {
- if (op === '\n' || op === '.')
- continue;
-
- var node = opTokens;
- for (var i = 0; i < op.length; i++) {
- var ch = op[i];
- if (!(ch in node))
- node[ch] = {};
- node = node[ch];
- node.op = op;
- }
- }
-
- /*
- * Tokenizer :: (source, filename, line number) -> Tokenizer
- */
- function Tokenizer(s, f, l) {
- this.cursor = 0;
- this.source = String(s);
- this.tokens = [];
- this.tokenIndex = 0;
- this.lookahead = 0;
- this.scanNewlines = false;
- this.unexpectedEOF = false;
- this.filename = f || "";
- this.lineno = l || 1;
- this.blackList = blackLists[Narcissus.options.version];
- this.blockComments = null;
- }
-
- Tokenizer.prototype = {
- get done() {
- // We need to set scanOperand to true here because the first thing
- // might be a regexp.
- return this.peek(true) === END;
- },
-
- get token() {
- return this.tokens[this.tokenIndex];
- },
-
- match: function (tt, scanOperand) {
- return this.get(scanOperand) === tt || this.unget();
- },
-
- mustMatch: function (tt) {
- if (!this.match(tt)) {
- throw this.newSyntaxError("Missing " +
- definitions.tokens[tt].toLowerCase());
- }
- return this.token;
- },
-
- peek: function (scanOperand) {
- var tt, next;
- if (this.lookahead) {
- next = this.tokens[(this.tokenIndex + this.lookahead) & 3];
- tt = (this.scanNewlines && next.lineno !== this.lineno)
- ? NEWLINE
- : next.type;
- } else {
- tt = this.get(scanOperand);
- this.unget();
- }
- return tt;
- },
-
- peekOnSameLine: function (scanOperand) {
- this.scanNewlines = true;
- var tt = this.peek(scanOperand);
- this.scanNewlines = false;
- return tt;
- },
-
- lastBlockComment: function() {
- var length = this.blockComments.length;
- return length ? this.blockComments[length - 1] : null;
- },
-
- // Eat comments and whitespace.
- skip: function () {
- var input = this.source;
- this.blockComments = [];
- for (;;) {
- var ch = input[this.cursor++];
- var next = input[this.cursor];
- // handle \r, \r\n and (always preferable) \n
- if (ch === '\r') {
- // if the next character is \n, we don't care about this at all
- if (next === '\n') continue;
-
- // otherwise, we want to consider this as a newline
- ch = '\n';
- }
-
- if (ch === '\n' && !this.scanNewlines) {
- this.lineno++;
- } else if (ch === '/' && next === '*') {
- var commentStart = ++this.cursor;
- for (;;) {
- ch = input[this.cursor++];
- if (ch === undefined)
- throw this.newSyntaxError("Unterminated comment");
-
- if (ch === '*') {
- next = input[this.cursor];
- if (next === '/') {
- var commentEnd = this.cursor - 1;
- this.cursor++;
- break;
- }
- } else if (ch === '\n') {
- this.lineno++;
- }
- }
- this.blockComments.push(input.substring(commentStart, commentEnd));
- } else if (ch === '/' && next === '/') {
- this.cursor++;
- for (;;) {
- ch = input[this.cursor++];
- next = input[this.cursor];
- if (ch === undefined)
- return;
-
- if (ch === '\r') {
- // check for \r\n
- if (next !== '\n') ch = '\n';
- }
-
- if (ch === '\n') {
- if (this.scanNewlines) {
- this.cursor--;
- } else {
- this.lineno++;
- }
- break;
- }
- }
- } else if (!(ch in definitions.whitespace)) {
- this.cursor--;
- return;
- }
- }
- },
-
- // Lex the exponential part of a number, if present. Return true iff an
- // exponential part was found.
- lexExponent: function() {
- var input = this.source;
- var next = input[this.cursor];
- if (next === 'e' || next === 'E') {
- this.cursor++;
- ch = input[this.cursor++];
- if (ch === '+' || ch === '-')
- ch = input[this.cursor++];
-
- if (ch < '0' || ch > '9')
- throw this.newSyntaxError("Missing exponent");
-
- do {
- ch = input[this.cursor++];
- } while (ch >= '0' && ch <= '9');
- this.cursor--;
-
- return true;
- }
-
- return false;
- },
-
- lexZeroNumber: function (ch) {
- var token = this.token, input = this.source;
- token.type = NUMBER;
-
- ch = input[this.cursor++];
- if (ch === '.') {
- do {
- ch = input[this.cursor++];
- } while (ch >= '0' && ch <= '9');
- this.cursor--;
-
- this.lexExponent();
- token.value = parseFloat(token.start, this.cursor);
- } else if (ch === 'x' || ch === 'X') {
- do {
- ch = input[this.cursor++];
- } while ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') ||
- (ch >= 'A' && ch <= 'F'));
- this.cursor--;
-
- token.value = parseInt(input.substring(token.start, this.cursor));
- } else if (ch >= '0' && ch <= '7') {
- do {
- ch = input[this.cursor++];
- } while (ch >= '0' && ch <= '7');
- this.cursor--;
-
- token.value = parseInt(input.substring(token.start, this.cursor));
- } else {
- this.cursor--;
- this.lexExponent(); // 0E1, &c.
- token.value = 0;
- }
- },
-
- lexNumber: function (ch) {
- var token = this.token, input = this.source;
- token.type = NUMBER;
-
- var floating = false;
- do {
- ch = input[this.cursor++];
- if (ch === '.' && !floating) {
- floating = true;
- ch = input[this.cursor++];
- }
- } while (ch >= '0' && ch <= '9');
-
- this.cursor--;
-
- var exponent = this.lexExponent();
- floating = floating || exponent;
-
- var str = input.substring(token.start, this.cursor);
- token.value = floating ? parseFloat(str) : parseInt(str);
- },
-
- lexDot: function (ch) {
- var token = this.token, input = this.source;
- var next = input[this.cursor];
- if (next >= '0' && next <= '9') {
- do {
- ch = input[this.cursor++];
- } while (ch >= '0' && ch <= '9');
- this.cursor--;
-
- this.lexExponent();
-
- token.type = NUMBER;
- token.value = parseFloat(token.start, this.cursor);
- } else {
- token.type = DOT;
- token.assignOp = null;
- token.value = '.';
- }
- },
-
- lexString: function (ch) {
- var token = this.token, input = this.source;
- token.type = STRING;
-
- var hasEscapes = false;
- var delim = ch;
- if (input.length <= this.cursor)
- throw this.newSyntaxError("Unterminated string literal");
- while ((ch = input[this.cursor++]) !== delim) {
- if (this.cursor == input.length)
- throw this.newSyntaxError("Unterminated string literal");
- if (ch === '\\') {
- hasEscapes = true;
- if (++this.cursor == input.length)
- throw this.newSyntaxError("Unterminated string literal");
- }
- }
-
- token.value = hasEscapes
- ? eval(input.substring(token.start, this.cursor))
- : input.substring(token.start + 1, this.cursor - 1);
- },
-
- lexRegExp: function (ch) {
- var token = this.token, input = this.source;
- token.type = REGEXP;
-
- do {
- ch = input[this.cursor++];
- if (ch === '\\') {
- this.cursor++;
- } else if (ch === '[') {
- do {
- if (ch === undefined)
- throw this.newSyntaxError("Unterminated character class");
-
- if (ch === '\\')
- this.cursor++;
-
- ch = input[this.cursor++];
- } while (ch !== ']');
- } else if (ch === undefined) {
- throw this.newSyntaxError("Unterminated regex");
- }
- } while (ch !== '/');
-
- do {
- ch = input[this.cursor++];
- } while (ch >= 'a' && ch <= 'z');
-
- this.cursor--;
-
- token.value = eval(input.substring(token.start, this.cursor));
- },
-
- lexOp: function (ch) {
- var token = this.token, input = this.source;
-
- // A bit ugly, but it seems wasteful to write a trie lookup routine
- // for only 3 characters...
- var node = opTokens[ch];
- var next = input[this.cursor];
- if (next in node) {
- node = node[next];
- this.cursor++;
- next = input[this.cursor];
- if (next in node) {
- node = node[next];
- this.cursor++;
- next = input[this.cursor];
- }
- }
-
- var op = node.op;
- if (definitions.assignOps[op] && input[this.cursor] === '=') {
- this.cursor++;
- token.type = ASSIGN;
- token.assignOp = definitions.tokenIds[definitions.opTypeNames[op]];
- op += '=';
- } else {
- token.type = definitions.tokenIds[definitions.opTypeNames[op]];
- token.assignOp = null;
- }
-
- token.value = op;
- },
-
- // FIXME: Unicode escape sequences
- lexIdent: function (ch) {
- var token = this.token;
- var id = ch;
-
- while ((ch = this.getValidIdentifierChar(false)) !== null) {
- id += ch;
- }
-
- token.type = definitions.keywords[id] || IDENTIFIER;
- if (token.type in this.blackList) {
- // banned keyword, this is an identifier
- token.type = IDENTIFIER;
- }
- token.value = id;
- },
-
- /*
- * Tokenizer.get :: void -> token type
- *
- * Consume input *only* if there is no lookahead.
- * Dispatch to the appropriate lexing function depending on the input.
- */
- get: function (scanOperand) {
- var token;
- while (this.lookahead) {
- --this.lookahead;
- this.tokenIndex = (this.tokenIndex + 1) & 3;
- token = this.tokens[this.tokenIndex];
- if (token.type !== NEWLINE || this.scanNewlines)
- return token.type;
- }
-
- this.skip();
-
- this.tokenIndex = (this.tokenIndex + 1) & 3;
- token = this.tokens[this.tokenIndex];
- if (!token)
- this.tokens[this.tokenIndex] = token = {};
-
- var input = this.source;
- if (this.cursor >= input.length)
- return token.type = END;
-
- token.start = this.cursor;
- token.lineno = this.lineno;
-
- var ich = this.getValidIdentifierChar(true);
- var ch = (ich === null) ? input[this.cursor++] : null;
- if (ich !== null) {
- this.lexIdent(ich);
- } else if (scanOperand && ch === '/') {
- this.lexRegExp(ch);
- } else if (ch in opTokens) {
- this.lexOp(ch);
- } else if (ch === '.') {
- this.lexDot(ch);
- } else if (ch >= '1' && ch <= '9') {
- this.lexNumber(ch);
- } else if (ch === '0') {
- this.lexZeroNumber(ch);
- } else if (ch === '"' || ch === "'") {
- this.lexString(ch);
- } else if (this.scanNewlines && (ch === '\n' || ch === '\r')) {
- // if this was a \r, look for \r\n
- if (ch === '\r' && input[this.cursor] === '\n') this.cursor++;
- token.type = NEWLINE;
- token.value = '\n';
- this.lineno++;
- } else {
- throw this.newSyntaxError("Illegal token");
- }
-
- token.end = this.cursor;
- return token.type;
- },
-
- /*
- * Tokenizer.unget :: void -> undefined
- *
- * Match depends on unget returning undefined.
- */
- unget: function () {
- if (++this.lookahead === 4) throw "PANIC: too much lookahead!";
- this.tokenIndex = (this.tokenIndex - 1) & 3;
- },
-
- newSyntaxError: function (m) {
- m = (this.filename ? this.filename + ":" : "") + this.lineno + ": " + m;
- var e = new SyntaxError(m, this.filename, this.lineno);
- e.source = this.source;
- e.cursor = this.lookahead
- ? this.tokens[(this.tokenIndex + this.lookahead) & 3].start
- : this.cursor;
- return e;
- },
-
- /* Gets a single valid identifier char from the input stream, or null
- * if there is none.
- * Since JavaScript provides no convenient way to determine if a
- * character is in a particular Unicode category, we use
- * metacircularity to accomplish this (oh yeaaaah!) */
- getValidIdentifierChar: function(first) {
- var input = this.source;
- if (this.cursor >= input.length) return null;
- var ch = input[this.cursor];
-
- // first check for \u escapes
- if (ch === '\\' && input[this.cursor+1] === 'u') {
- // get the character value
- try {
- ch = String.fromCharCode(parseInt(
- input.substring(this.cursor + 2, this.cursor + 6),
- 16));
- } catch (ex) {
- return null;
- }
- this.cursor += 5;
- }
-
- // check directly for ASCII
- if (ch <= "\u007F") {
- if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch === '$' || ch === '_' ||
- (!first && (ch >= '0' && ch <= '9'))) {
- this.cursor++;
- return ch;
- }
- return null;
- }
-
- // create an object to test this in
- var x = {};
- x["x"+ch] = true;
- x[ch] = true;
-
- // then use eval to determine if it's a valid character
- var valid = false;
- try {
- valid = (Function("x", "return (x." + (first?"":"x") + ch + ");")(x) === true);
- } catch (ex) {}
- if (valid) this.cursor++;
- return (valid ? ch : null);
- },
- };
-
-
- module.exports = { Tokenizer: Tokenizer };
-
-});
-/* vim: set sw=4 ts=4 et tw=78: */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is the Narcissus JavaScript engine.
- *
- * The Initial Developer of the Original Code is
- * Brendan Eich <brendan@mozilla.org>.
- * Portions created by the Initial Developer are Copyright (C) 2004
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Tom Austin <taustin@ucsc.edu>
- * Brendan Eich <brendan@mozilla.org>
- * Shu-Yu Guo <shu@rfrn.org>
- * Dave Herman <dherman@mozilla.com>
- * Dimitris Vardoulakis <dimvar@ccs.neu.edu>
- * Patrick Walton <pcwalton@mozilla.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-/*
- * Narcissus - JS implemented in JS.
- *
- * Well-known constants and lookup tables. Many consts are generated from the
- * tokens table via eval to minimize redundancy, so consumers must be compiled
- * separately to take advantage of the simple switch-case constant propagation
- * done by SpiderMonkey.
- */
-
-define('ace/narcissus/jsdefs', ['require', 'exports', 'module' ], function(require, exports, module) {
-
- var narcissus = {
- options: {
- version: 185,
- // Global variables to hide from the interpreter
- hiddenHostGlobals: { Narcissus: true },
- // Desugar SpiderMonkey language extensions?
- desugarExtensions: false
- },
- hostSupportsEvalConst: (function() {
- try {
- return eval("(function(s) { eval(s); return x })('const x = true;')");
- } catch (e) {
- return false;
- }
- })(),
- hostGlobal: this
- };
- Narcissus = narcissus;
-
- var tokens = [
- // End of source.
- "END",
-
- // Operators and punctuators. Some pair-wise order matters, e.g. (+, -)
- // and (UNARY_PLUS, UNARY_MINUS).
- "\n", ";",
- ",",
- "=",
- "?", ":", "CONDITIONAL",
- "||",
- "&&",
- "|",
- "^",
- "&",
- "==", "!=", "===", "!==",
- "<", "<=", ">=", ">",
- "<<", ">>", ">>>",
- "+", "-",
- "*", "/", "%",
- "!", "~", "UNARY_PLUS", "UNARY_MINUS",
- "++", "--",
- ".",
- "[", "]",
- "{", "}",
- "(", ")",
-
- // Nonterminal tree node type codes.
- "SCRIPT", "BLOCK", "LABEL", "FOR_IN", "CALL", "NEW_WITH_ARGS", "INDEX",
- "ARRAY_INIT", "OBJECT_INIT", "PROPERTY_INIT", "GETTER", "SETTER",
- "GROUP", "LIST", "LET_BLOCK", "ARRAY_COMP", "GENERATOR", "COMP_TAIL",
-
- // Terminals.
- "IDENTIFIER", "NUMBER", "STRING", "REGEXP",
-
- // Keywords.
- "break",
- "case", "catch", "const", "continue",
- "debugger", "default", "delete", "do",
- "else", "export",
- "false", "finally", "for", "function",
- "if", "import", "in", "instanceof",
- "let", "module",
- "new", "null",
- "return",
- "switch",
- "this", "throw", "true", "try", "typeof",
- "var", "void",
- "yield",
- "while", "with",
- ];
-
- var statementStartTokens = [
- "break",
- "const", "continue",
- "debugger", "do",
- "for",
- "if",
- "return",
- "switch",
- "throw", "try",
- "var",
- "yield",
- "while", "with",
- ];
-
- // Whitespace characters (see ECMA-262 7.2)
- var whitespaceChars = [
- // normal whitespace:
- "\u0009", "\u000B", "\u000C", "\u0020", "\u00A0", "\uFEFF",
-
- // high-Unicode whitespace:
- "\u1680", "\u180E",
- "\u2000", "\u2001", "\u2002", "\u2003", "\u2004", "\u2005", "\u2006",
- "\u2007", "\u2008", "\u2009", "\u200A",
- "\u202F", "\u205F", "\u3000"
- ];
-
- var whitespace = {};
- for (var i = 0; i < whitespaceChars.length; i++) {
- whitespace[whitespaceChars[i]] = true;
- }
-
- // Operator and punctuator mapping from token to tree node type name.
- // NB: because the lexer doesn't backtrack, all token prefixes must themselves
- // be valid tokens (e.g. !== is acceptable because its prefixes are the valid
- // tokens != and !).
- var opTypeNames = {
- '\n': "NEWLINE",
- ';': "SEMICOLON",
- ',': "COMMA",
- '?': "HOOK",
- ':': "COLON",
- '||': "OR",
- '&&': "AND",
- '|': "BITWISE_OR",
- '^': "BITWISE_XOR",
- '&': "BITWISE_AND",
- '===': "STRICT_EQ",
- '==': "EQ",
- '=': "ASSIGN",
- '!==': "STRICT_NE",
- '!=': "NE",
- '<<': "LSH",
- '<=': "LE",
- '<': "LT",
- '>>>': "URSH",
- '>>': "RSH",
- '>=': "GE",
- '>': "GT",
- '++': "INCREMENT",
- '--': "DECREMENT",
- '+': "PLUS",
- '-': "MINUS",
- '*': "MUL",
- '/': "DIV",
- '%': "MOD",
- '!': "NOT",
- '~': "BITWISE_NOT",
- '.': "DOT",
- '[': "LEFT_BRACKET",
- ']': "RIGHT_BRACKET",
- '{': "LEFT_CURLY",
- '}': "RIGHT_CURLY",
- '(': "LEFT_PAREN",
- ')': "RIGHT_PAREN"
- };
-
- // Hash of keyword identifier to tokens index. NB: we must null __proto__ to
- // avoid toString, etc. namespace pollution.
- var keywords = {__proto__: null};
-
- // Define const END, etc., based on the token names. Also map name to index.
- var tokenIds = {};
-
- // Building up a string to be eval'd in different contexts.
- var consts = Narcissus.hostSupportsEvalConst ? "const " : "var ";
- for (var i = 0, j = tokens.length; i < j; i++) {
- if (i > 0)
- consts += ", ";
- var t = tokens[i];
- var name;
- if (/^[a-z]/.test(t)) {
- name = t.toUpperCase();
- keywords[t] = i;
- } else {
- name = (/^\W/.test(t) ? opTypeNames[t] : t);
- }
- consts += name + " = " + i;
- tokenIds[name] = i;
- tokens[t] = i;
- }
- consts += ";";
-
- var isStatementStartCode = {__proto__: null};
- for (i = 0, j = statementStartTokens.length; i < j; i++)
- isStatementStartCode[keywords[statementStartTokens[i]]] = true;
-
- // Map assignment operators to their indexes in the tokens array.
- var assignOps = ['|', '^', '&', '<<', '>>', '>>>', '+', '-', '*', '/', '%'];
-
- for (i = 0, j = assignOps.length; i < j; i++) {
- t = assignOps[i];
- assignOps[t] = tokens[t];
- }
-
- function defineGetter(obj, prop, fn, dontDelete, dontEnum) {
- Object.defineProperty(obj, prop,
- { get: fn, configurable: !dontDelete, enumerable: !dontEnum });
- }
-
- function defineGetterSetter(obj, prop, getter, setter, dontDelete, dontEnum) {
- Object.defineProperty(obj, prop, {
- get: getter,
- set: setter,
- configurable: !dontDelete,
- enumerable: !dontEnum
- });
- }
-
- function defineMemoGetter(obj, prop, fn, dontDelete, dontEnum) {
- Object.defineProperty(obj, prop, {
- get: function() {
- var val = fn();
- defineProperty(obj, prop, val, dontDelete, true, dontEnum);
- return val;
- },
- configurable: true,
- enumerable: !dontEnum
- });
- }
-
- function defineProperty(obj, prop, val, dontDelete, readOnly, dontEnum) {
- Object.defineProperty(obj, prop,
- { value: val, writable: !readOnly, configurable: !dontDelete,
- enumerable: !dontEnum });
- }
-
- // Returns true if fn is a native function. (Note: SpiderMonkey specific.)
- function isNativeCode(fn) {
- // Relies on the toString method to identify native code.
- return ((typeof fn) === "function") && fn.toString().match(/\[native code\]/);
- }
-
- function getPropertyDescriptor(obj, name) {
- while (obj) {
- if (({}).hasOwnProperty.call(obj, name))
- return Object.getOwnPropertyDescriptor(obj, name);
- obj = Object.getPrototypeOf(obj);
- }
- }
-
- function getPropertyNames(obj) {
- var table = Object.create(null, {});
- while (obj) {
- var names = Object.getOwnPropertyNames(obj);
- for (var i = 0, n = names.length; i < n; i++)
- table[names[i]] = true;
- obj = Object.getPrototypeOf(obj);
- }
- return Object.keys(table);
- }
-
- function getOwnProperties(obj) {
- var map = {};
- for (var name in Object.getOwnPropertyNames(obj))
- map[name] = Object.getOwnPropertyDescriptor(obj, name);
- return map;
- }
-
- function blacklistHandler(target, blacklist) {
- var mask = Object.create(null, {});
- var redirect = StringMap.create(blacklist).mapObject(function(name) { return mask; });
- return mixinHandler(redirect, target);
- }
-
- function whitelistHandler(target, whitelist) {
- var catchall = Object.create(null, {});
- var redirect = StringMap.create(whitelist).mapObject(function(name) { return target; });
- return mixinHandler(redirect, catchall);
- }
-
- function mirrorHandler(target, writable) {
- var handler = makePassthruHandler(target);
-
- var defineProperty = handler.defineProperty;
- handler.defineProperty = function(name, desc) {
- if (!desc.enumerable)
- throw new Error("mirror property must be enumerable");
- if (!desc.configurable)
- throw new Error("mirror property must be configurable");
- if (desc.writable !== writable)
- throw new Error("mirror property must " + (writable ? "" : "not ") + "be writable");
- defineProperty(name, desc);
- };
-
- handler.fix = function() { };
- handler.getOwnPropertyDescriptor = handler.getPropertyDescriptor;
- handler.getOwnPropertyNames = getPropertyNames.bind(handler, target);
- handler.keys = handler.enumerate;
- handler["delete"] = function() { return false; };
- handler.hasOwn = handler.has;
- return handler;
- }
-
- /*
- * Mixin proxies break the single-inheritance model of prototypes, so
- * the handler treats all properties as own-properties:
- *
- * X
- * |
- * +------------+------------+
- * | O |
- * | | |
- * | O O O |
- * | | | | |
- * | O O O O |
- * | | | | | |
- * | O O O O O |
- * | | | | | | |
- * +-(*)--(w)--(x)--(y)--(z)-+
- */
-
- function mixinHandler(redirect, catchall) {
- function targetFor(name) {
- return hasOwn(redirect, name) ? redirect[name] : catchall;
- }
-
- function getMuxPropertyDescriptor(name) {
- var desc = getPropertyDescriptor(targetFor(name), name);
- if (desc)
- desc.configurable = true;
- return desc;
- }
-
- function getMuxPropertyNames() {
- var names1 = Object.getOwnPropertyNames(redirect).filter(function(name) {
- return name in redirect[name];
- });
- var names2 = getPropertyNames(catchall).filter(function(name) {
- return !hasOwn(redirect, name);
- });
- return names1.concat(names2);
- }
-
- function enumerateMux() {
- var result = Object.getOwnPropertyNames(redirect).filter(function(name) {
- return name in redirect[name];
- });
- for (name in catchall) {
- if (!hasOwn(redirect, name))
- result.push(name);
- };
- return result;
- }
-
- function hasMux(name) {
- return name in targetFor(name);
- }
-
- return {
- getOwnPropertyDescriptor: getMuxPropertyDescriptor,
- getPropertyDescriptor: getMuxPropertyDescriptor,
- getOwnPropertyNames: getMuxPropertyNames,
- defineProperty: function(name, desc) {
- Object.defineProperty(targetFor(name), name, desc);
- },
- "delete": function(name) {
- var target = targetFor(name);
- return delete target[name];
- },
- // FIXME: ha ha ha
- fix: function() { },
- has: hasMux,
- hasOwn: hasMux,
- get: function(receiver, name) {
- var target = targetFor(name);
- return target[name];
- },
- set: function(receiver, name, val) {
- var target = targetFor(name);
- target[name] = val;
- return true;
- },
- enumerate: enumerateMux,
- keys: enumerateMux
- };
- }
-
- function makePassthruHandler(obj) {
- // Handler copied from
- // http://wiki.ecmascript.org/doku.php?id=harmony:proxies&s=proxy%20object#examplea_no-op_forwarding_proxy
- return {
- getOwnPropertyDescriptor: function(name) {
- var desc = Object.getOwnPropertyDescriptor(obj, name);
-
- // a trapping proxy's properties must always be configurable
- desc.configurable = true;
- return desc;
- },
- getPropertyDescriptor: function(name) {
- var desc = getPropertyDescriptor(obj, name);
-
- // a trapping proxy's properties must always be configurable
- desc.configurable = true;
- return desc;
- },
- getOwnPropertyNames: function() {
- return Object.getOwnPropertyNames(obj);
- },
- defineProperty: function(name, desc) {
- Object.defineProperty(obj, name, desc);
- },
- "delete": function(name) { return delete obj[name]; },
- fix: function() {
- if (Object.isFrozen(obj)) {
- return getOwnProperties(obj);
- }
-
- // As long as obj is not frozen, the proxy won't allow itself to be fixed.
- return undefined; // will cause a TypeError to be thrown
- },
-
- has: function(name) { return name in obj; },
- hasOwn: function(name) { return ({}).hasOwnProperty.call(obj, name); },
- get: function(receiver, name) { return obj[name]; },
-
- // bad behavior when set fails in non-strict mode
- set: function(receiver, name, val) { obj[name] = val; return true; },
- enumerate: function() {
- var result = [];
- for (name in obj) { result.push(name); };
- return result;
- },
- keys: function() { return Object.keys(obj); }
- };
- }
-
- var hasOwnProperty = ({}).hasOwnProperty;
-
- function hasOwn(obj, name) {
- return hasOwnProperty.call(obj, name);
- }
-
- function StringMap(table, size) {
- this.table = table || Object.create(null, {});
- this.size = size || 0;
- }
-
- StringMap.create = function(table) {
- var init = Object.create(null, {});
- var size = 0;
- var names = Object.getOwnPropertyNames(table);
- for (var i = 0, n = names.length; i < n; i++) {
- var name = names[i];
- init[name] = table[name];
- size++;
- }
- return new StringMap(init, size);
- };
-
- StringMap.prototype = {
- has: function(x) { return hasOwnProperty.call(this.table, x); },
- set: function(x, v) {
- if (!hasOwnProperty.call(this.table, x))
- this.size++;
- this.table[x] = v;
- },
- get: function(x) { return this.table[x]; },
- getDef: function(x, thunk) {
- if (!hasOwnProperty.call(this.table, x)) {
- this.size++;
- this.table[x] = thunk();
- }
- return this.table[x];
- },
- forEach: function(f) {
- var table = this.table;
- for (var key in table)
- f.call(this, key, table[key]);
- },
- map: function(f) {
- var table1 = this.table;
- var table2 = Object.create(null, {});
- this.forEach(function(key, val) {
- table2[key] = f.call(this, val, key);
- });
- return new StringMap(table2, this.size);
- },
- mapObject: function(f) {
- var table1 = this.table;
- var table2 = Object.create(null, {});
- this.forEach(function(key, val) {
- table2[key] = f.call(this, val, key);
- });
- return table2;
- },
- toObject: function() {
- return this.mapObject(function(val) { return val; });
- },
- choose: function() {
- return Object.getOwnPropertyNames(this.table)[0];
- },
- remove: function(x) {
- if (hasOwnProperty.call(this.table, x)) {
- this.size--;
- delete this.table[x];
- }
- },
- copy: function() {
- var table = Object.create(null, {});
- for (var key in this.table)
- table[key] = this.table[key];
- return new StringMap(table, this.size);
- },
- toString: function() { return "[object StringMap]" }
- };
-
- // an object-key table with poor asymptotics (replace with WeakMap when possible)
- function ObjectMap(array) {
- this.array = array || [];
- }
-
- function searchMap(map, key, found, notFound) {
- var a = map.array;
- for (var i = 0, n = a.length; i < n; i++) {
- var pair = a[i];
- if (pair.key === key)
- return found(pair, i);
- }
- return notFound();
- }
-
- ObjectMap.prototype = {
- has: function(x) {
- return searchMap(this, x, function() { return true }, function() { return false });
- },
- set: function(x, v) {
- var a = this.array;
- searchMap(this, x,
- function(pair) { pair.value = v },
- function() { a.push({ key: x, value: v }) });
- },
- get: function(x) {
- return searchMap(this, x,
- function(pair) { return pair.value },
- function() { return null });
- },
- getDef: function(x, thunk) {
- var a = this.array;
- return searchMap(this, x,
- function(pair) { return pair.value },
- function() {
- var v = thunk();
- a.push({ key: x, value: v });
- return v;
- });
- },
- forEach: function(f) {
- var a = this.array;
- for (var i = 0, n = a.length; i < n; i++) {
- var pair = a[i];
- f.call(this, pair.key, pair.value);
- }
- },
- choose: function() {
- return this.array[0].key;
- },
- get size() {
- return this.array.length;
- },
- remove: function(x) {
- var a = this.array;
- searchMap(this, x,
- function(pair, i) { a.splice(i, 1) },
- function() { });
- },
- copy: function() {
- return new ObjectMap(this.array.map(function(pair) {
- return { key: pair.key, value: pair.value }
- }));
- },
- clear: function() {
- this.array = [];
- },
- toString: function() { return "[object ObjectMap]" }
- };
-
- // non-destructive stack
- function Stack(elts) {
- this.elts = elts || null;
- }
-
- Stack.prototype = {
- push: function(x) {
- return new Stack({ top: x, rest: this.elts });
- },
- top: function() {
- if (!this.elts)
- throw new Error("empty stack");
- return this.elts.top;
- },
- isEmpty: function() {
- return this.top === null;
- },
- find: function(test) {
- for (var elts = this.elts; elts; elts = elts.rest) {
- if (test(elts.top))
- return elts.top;
- }
- return null;
- },
- has: function(x) {
- return Boolean(this.find(function(elt) { return elt === x }));
- },
- forEach: function(f) {
- for (var elts = this.elts; elts; elts = elts.rest) {
- f(elts.top);
- }
- }
- };
-
- module.exports = {
- tokens: tokens,
- whitespace: whitespace,
- opTypeNames: opTypeNames,
- keywords: keywords,
- isStatementStartCode: isStatementStartCode,
- tokenIds: tokenIds,
- consts: consts,
- assignOps: assignOps,
- defineGetter: defineGetter,
- defineGetterSetter: defineGetterSetter,
- defineMemoGetter: defineMemoGetter,
- defineProperty: defineProperty,
- isNativeCode: isNativeCode,
- mirrorHandler: mirrorHandler,
- mixinHandler: mixinHandler,
- whitelistHandler: whitelistHandler,
- blacklistHandler: blacklistHandler,
- makePassthruHandler: makePassthruHandler,
- StringMap: StringMap,
- ObjectMap: ObjectMap,
- Stack: Stack
- };
}); \ No newline at end of file