diff options
Diffstat (limited to 'vendor/assets/javascripts/ace-src-noconflict/worker-javascript.js')
-rw-r--r-- | vendor/assets/javascripts/ace-src-noconflict/worker-javascript.js | 10319 |
1 files changed, 0 insertions, 10319 deletions
diff --git a/vendor/assets/javascripts/ace-src-noconflict/worker-javascript.js b/vendor/assets/javascripts/ace-src-noconflict/worker-javascript.js deleted file mode 100644 index 671d7bec547..00000000000 --- a/vendor/assets/javascripts/ace-src-noconflict/worker-javascript.js +++ /dev/null @@ -1,10319 +0,0 @@ -"no use strict"; - -var console = { - log: function(msgs) { - postMessage({type: "log", data: arguments.join(" ")}); - } -}; -var window = { - console: console -}; - -var normalizeModule = function(parentId, moduleName) { - // normalize plugin requires - if (moduleName.indexOf("!") !== -1) { - var chunks = moduleName.split("!"); - return normalizeModule(parentId, chunks[0]) + "!" + normalizeModule(parentId, chunks[1]); - } - // normalize relative requires - if (moduleName.charAt(0) == ".") { - var base = parentId.split("/").slice(0, -1).join("/"); - var moduleName = base + "/" + moduleName; - - while(moduleName.indexOf(".") !== -1 && previous != moduleName) { - var previous = moduleName; - var moduleName = moduleName.replace(/\/\.\//, "/").replace(/[^\/]+\/\.\.\//, ""); - } - } - - return moduleName; -}; - -var require = function(parentId, id) { - if (!id.charAt) - throw new Error("worker.js require() accepts only (parentId, id) as arguments"); - - var id = normalizeModule(parentId, id); - - var module = require.modules[id]; - if (module) { - if (!module.initialized) { - module.initialized = true; - module.exports = module.factory().exports; - } - return module.exports; - } - - var chunks = id.split("/"); - chunks[0] = require.tlns[chunks[0]] || chunks[0]; - var path = chunks.join("/") + ".js"; - - require.id = id; - importScripts(path); - return require(parentId, id); -}; - -require.modules = {}; -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; - } - - if (id.indexOf("text!") === 0) - return; - - var req = function(deps, factory) { - return require(id, deps, factory); - }; - - require.modules[id] = { - factory: function() { - var module = { - exports: {} - }; - var returnExports = factory(req, module.exports, module); - if (returnExports) - module.exports = returnExports; - return module; - } - }; -}; - -function initBaseUrls(topLevelNamespaces) { - require.tlns = topLevelNamespaces; -} - -function initSender() { - - var EventEmitter = require(null, "ace/lib/event_emitter").EventEmitter; - var oop = require(null, "ace/lib/oop"); - - var Sender = function() {}; - - (function() { - - oop.implement(this, EventEmitter); - - this.callback = function(data, callbackId) { - postMessage({ - type: "call", - id: callbackId, - data: data - }); - }; - - this.emit = function(name, data) { - postMessage({ - type: "event", - name: name, - data: data - }); - }; - - }).call(Sender.prototype); - - return new Sender(); -} - -var main; -var sender; - -onmessage = function(e) { - var msg = e.data; - if (msg.command) { - main[msg.command].apply(main, msg.args); - } - else if (msg.init) { - initBaseUrls(msg.tlns); - require(null, "ace/lib/fixoldbrowsers"); - sender = initSender(); - var clazz = require(null, msg.module)[msg.classname]; - main = new clazz(sender); - } - else if (msg.event && sender) { - sender._emit(msg.event, msg.data); - } -}; -// 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) { - - -require("./regexp"); -require("./es5-shim"); - -}); - -define('ace/lib/regexp', ['require', 'exports', 'module' ], function(require, exports, module) { - - - //--------------------------------- - // Private variables - //--------------------------------- - - var real = { - exec: RegExp.prototype.exec, - test: RegExp.prototype.test, - match: String.prototype.match, - replace: String.prototype.replace, - split: String.prototype.split - }, - compliantExecNpcg = real.exec.call(/()??/, "")[1] === undefined, // check `exec` handling of nonparticipating capturing groups - compliantLastIndexIncrement = function () { - var x = /^/g; - real.test.call(x, ""); - return !x.lastIndex; - }(); - - if (compliantLastIndexIncrement && compliantExecNpcg) - return; - - //--------------------------------- - // 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. - RegExp.prototype.exec = function (str) { - var match = real.exec.apply(this, arguments), - name, r2; - if ( typeof(str) == 'string' && match) { - // Fix browsers whose `exec` methods don't consistently return `undefined` for - // nonparticipating capturing groups - 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) - match[i] = undefined; - } - }); - } - // Attach named capture properties - if (this._xregexp && this._xregexp.captureNames) { - for (var i = 1; i < match.length; i++) { - name = this._xregexp.captureNames[i - 1]; - if (name) - 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 - return array.indexOf(item, from); - for (var i = from || 0; i < array.length; i++) { - if (array[i] === item) - 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; - var self = new F; - - var result = target.apply( - self, - args.concat(slice.call(arguments)) - ); - if (result !== null && Object(result) === result) - return result; - 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)) - ); - - } - - }; - // 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; -var lookupSetter; -var supportsAccessors; -if ((supportsAccessors = owns(prototypeOfObject, "__defineGetter__"))) { - defineGetter = call.bind(prototypeOfObject.__defineGetter__); - defineSetter = call.bind(prototypeOfObject.__defineSetter__); - 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 - } - - for (var i = 0; i < length; i++) { - if (i in self) - result[i] = fun.call(thisp, self[i], i, self); - } - 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 - } - - for (var i = 0; i < length; i++) { - if (i in self && fun.call(thisp, self[i], i, self)) - result.push(self[i]); - } - 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 - } - - for (var i = 0; i < length; i++) { - if (i in self && !fun.call(thisp, self[i], i, self)) - return false; - } - 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 - } - - for (var i = 0; i < length; i++) { - if (i in self && fun.call(thisp, self[i], i, self)) - return true; - } - 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 - - var i = 0; - var result; - if (arguments.length >= 2) { - result = arguments[1]; - } else { - do { - if (i in self) { - result = self[i++]; - break; - } - - // if array contains no values, no initial value to return - if (++i >= length) - throw new TypeError(); // TODO message - } while (true); - } - - for (; i < length; i++) { - if (i in self) - result = fun.call(void 0, result, self[i], i, self); - } - - 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 - - var result, i = length - 1; - if (arguments.length >= 2) { - result = arguments[1]; - } else { - do { - if (i in self) { - result = self[i--]; - break; - } - - // if array contains no values, no initial value to return - if (--i < 0) - throw new TypeError(); // TODO message - } while (true); - } - - do { - if (i in this) - result = fun.call(void 0, result, self[i], i, self); - } while (i--); - - 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), - length = self.length >>> 0; - - if (!length) - return -1; - - 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) { - return i; - } - } - 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), - length = self.length >>> 0; - - if (!length) - return -1; - 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]) - return i; - } - 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 ? - object.constructor.prototype : - prototypeOfObject - ); - }; -} - -// 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) { - Object.create = function create(prototype, properties) { - var object; - if (prototype === null) { - object = { "__proto__": null }; - } 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) - Object.defineProperties(object, properties); - return object; - }; -} - -// 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" || - doesDefinePropertyWork(document.createElement("div")); - if (!definePropertyWorksOnObject || !definePropertyWorksOnDom) { - var definePropertyFallback = Object.defineProperty; - } -} - -if (!Object.defineProperty || definePropertyFallback) { - var ERR_NON_OBJECT_DESCRIPTOR = "Property description must be an object: "; - var ERR_NON_OBJECT_TARGET = "Object.defineProperty called on non-object: " - var ERR_ACCESSORS_NOT_SUPPORTED = "getters & setters can not be defined " + - "on this javascript engine"; - - Object.defineProperty = function defineProperty(object, property, descriptor) { - if ((typeof object != "object" && typeof object != "function") || object === null) - 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; - } - } 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")) - defineSetter(object, property, descriptor.set); - } - - 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) { - if (owns(properties, property)) - Object.defineProperty(object, property, properties[property]); - } - 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) { - Object.freeze = (function freeze(freezeObject) { - return function freeze(object) { - if (typeof object == "function") { - return object; - } else { - return freezeObject(object); - } - }; - })(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 += '?'; - } - object[name] = true; - var returnValue = owns(object, name); - delete object[name]; - 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", - "toLocaleString", - "valueOf", - "hasOwnProperty", - "isPrototypeOf", - "propertyIsEnumerable", - "constructor" - ], - dontEnumsLength = dontEnums.length; - - for (var key in {"toString": null}) - hasDontEnumBug = false; - - Object.keys = function keys(object) { - - if ((typeof object != "object" && typeof object != "function") || object === null) - throw new TypeError("Object.keys called on a non-object"); - - var keys = []; - for (var name in object) { - if (owns(object, name)) { - keys.push(name); - } - } - - if (hasDontEnumBug) { - for (var i = 0, ii = dontEnumsLength; i < ii; i++) { - var dontEnum = dontEnums[i]; - if (owns(object, dontEnum)) { - keys.push(dontEnum); - } - } - } - - return 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(); - year = (year < 0 ? '-' : (year > 9999 ? '+' : '')) + ('00000' + Math.abs(year)).slice(0 <= year && year <= 9999 ? -4 : -6); - - 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) : - length >= 4 ? new NativeDate(Y, M, D, h) : - length >= 3 ? new NativeDate(Y, M, D) : - 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 - "(?:-(\\d{2})" + // optional day capture - "(?:" + // capture hours:minutes:seconds.milliseconds - "T(\\d{2})" + // hours capture - ":(\\d{2})" + // minutes capture - "(?:" + // optional :seconds.milliseconds - ":(\\d{2})" + // seconds capture - "(?:\\.(\\d{3}))?" + // milliseconds capture - ")?" + - "(?:" + // capture UTC offset component - "Z|" + // UTC capture - "(?:" + // offset specifier +/-hours:minutes - "([-+])" + // sign capture - "(\\d{2})" + // hours offset capture - ":(\\d{2})" + // minutes offset capture - ")" + - ")?)?)?)?" + - "$"); - - // 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); - }; - - 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 + "*$"); - String.prototype.trim = function 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 - n = 0; - else if (n !== 0 && n !== (1/0) && n !== -(1/0)) - n = (n > 0 || -1) * Math.floor(Math.abs(n)); - return 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); - }; -}); - -define('ace/lib/event_emitter', ['require', 'exports', 'module' ], function(require, exports, module) { - - -var EventEmitter = {}; - -EventEmitter._emit = -EventEmitter._dispatchEvent = function(eventName, e) { - this._eventRegistry = this._eventRegistry || {}; - this._defaultHandlers = this._defaultHandlers || {}; - - var listeners = this._eventRegistry[eventName] || []; - var defaultHandler = this._defaultHandlers[eventName]; - if (!listeners.length && !defaultHandler) - return; - - if (typeof e != "object" || !e) - e = {}; - - if (!e.type) - e.type = eventName; - - if (!e.stopPropagation) { - e.stopPropagation = function() { - this.propagationStopped = true; - }; - } - - if (!e.preventDefault) { - e.preventDefault = function() { - this.defaultPrevented = true; - }; - } - - for (var i=0; i<listeners.length; i++) { - listeners[i](e); - if (e.propagationStopped) - break; - } - - if (defaultHandler && !e.defaultPrevented) - return defaultHandler(e); -}; - -EventEmitter.setDefaultHandler = function(eventName, callback) { - this._defaultHandlers = this._defaultHandlers || {}; - - if (this._defaultHandlers[eventName]) - throw new Error("The default handler for '" + eventName + "' is already set"); - - this._defaultHandlers[eventName] = callback; -}; - -EventEmitter.on = -EventEmitter.addEventListener = function(eventName, callback) { - this._eventRegistry = this._eventRegistry || {}; - - var listeners = this._eventRegistry[eventName]; - if (!listeners) - listeners = this._eventRegistry[eventName] = []; - - if (listeners.indexOf(callback) == -1) - listeners.push(callback); -}; - -EventEmitter.removeListener = -EventEmitter.removeEventListener = function(eventName, callback) { - this._eventRegistry = this._eventRegistry || {}; - - var listeners = this._eventRegistry[eventName]; - if (!listeners) - return; - - var index = listeners.indexOf(callback); - if (index !== -1) - listeners.splice(index, 1); -}; - -EventEmitter.removeAllListeners = function(eventName) { - if (this._eventRegistry) this._eventRegistry[eventName] = []; -}; - -exports.EventEmitter = EventEmitter; - -}); - -define('ace/lib/oop', ['require', 'exports', 'module' ], function(require, exports, module) { - - -exports.inherits = (function() { - var tempCtor = function() {}; - return function(ctor, superCtor) { - tempCtor.prototype = superCtor.prototype; - ctor.super_ = superCtor.prototype; - ctor.prototype = new tempCtor(); - ctor.prototype.constructor = ctor; - }; -}()); - -exports.mixin = function(obj, mixin) { - for (var key in mixin) { - obj[key] = mixin[key]; - } -}; - -exports.implement = function(proto, mixin) { - exports.mixin(proto, mixin); -}; - -}); - -define('ace/mode/javascript_worker', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/worker/mirror', 'ace/worker/jshint', 'ace/narcissus/parser'], function(require, exports, module) { - - -var oop = require("../lib/oop"); -var Mirror = require("../worker/mirror").Mirror; -var lint = require("../worker/jshint").JSHINT; -var parser = require("../narcissus/parser"); - -var JavaScriptWorker = exports.JavaScriptWorker = function(sender) { - Mirror.call(this, sender); - this.setTimeout(500); -}; - -oop.inherits(JavaScriptWorker, Mirror); - -(function() { - - this.onUpdate = function() { - var value = this.doc.getValue(); - value = value.replace(/^#!.*\n/, "\n"); - -// var start = new Date(); - 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" - }); - 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)); - } - -}).call(JavaScriptWorker.prototype); - -}); -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"); - -var Mirror = exports.Mirror = function(sender) { - this.sender = sender; - var doc = this.doc = new Document(""); - - var deferredUpdate = this.deferredUpdate = lang.deferredCall(this.onUpdate.bind(this)); - - var _self = this; - sender.on("change", function(e) { - doc.applyDeltas([e.data]); - deferredUpdate.schedule(_self.$timeout); - }); -}; - -(function() { - - this.$timeout = 500; - - this.setTimeout = function(timeout) { - this.$timeout = timeout; - }; - - this.setValue = function(value) { - this.doc.setValue(value); - this.deferredUpdate.schedule(this.$timeout); - }; - - this.getValue = function(callbackId) { - this.sender.callback(this.doc.getValue(), callbackId); - }; - - this.onUpdate = function() { - // abstract method - }; - -}).call(Mirror.prototype); - -}); - -define('ace/document', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/event_emitter', 'ace/range', 'ace/anchor'], function(require, exports, module) { - - -var oop = require("./lib/oop"); -var EventEmitter = require("./lib/event_emitter").EventEmitter; -var Range = require("./range").Range; -var Anchor = require("./anchor").Anchor; - - /** - * new Document([text]) - * - text (String | Array): The starting text - * - * Creates a new `Document`. If `text` is included, the `Document` contains those strings; otherwise, it's empty. - * - **/ - -var Document = function(text) { - this.$lines = []; - - // 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. - if (text.length == 0) { - this.$lines = [""]; - } else if (Array.isArray(text)) { - this.insertLines(0, text); - } else { - this.insert({row: 0, column:0}, 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"); - } - else - this.$split = function(text) { - return text.split(/\r\n|\r|\n/); - }; - this.$detectNewLine = function(text) { - var match = text.match(/^.*?(\r\n|\r|\n)/m); - if (match) { - this.$autoNewLine = match[1]; - } else { - this.$autoNewLine = "\n"; - } - }; - this.getNewLineCharacter = function() { - switch (this.$newLineMode) { - case "windows": - return "\r\n"; - - case "unix": - return "\n"; - - case "auto": - return this.$autoNewLine; - } - }; - - this.$autoNewLine = "\n"; - this.$newLineMode = "auto"; - this.setNewLineMode = function(newLineMode) { - if (this.$newLineMode === newLineMode) - return; - - this.$newLineMode = newLineMode; - }; - this.getNewLineMode = function() { - return this.$newLineMode; - }; - this.isNewLine = function(text) { - return (text == "\r\n" || text == "\r" || text == "\n"); - }; - this.getLine = function(row) { - return this.$lines[row] || ""; - }; - this.getLines = function(firstRow, lastRow) { - return this.$lines.slice(firstRow, lastRow + 1); - }; - 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 = 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()); - } - }; - this.$clipPosition = function(position) { - var length = this.getLength(); - if (position.row >= length) { - position.row = Math.max(0, length - 1); - position.column = this.getLine(length-1).length; - } - return position; - }; - this.insert = function(position, text) { - if (!text || text.length === 0) - return position; - - position = this.$clipPosition(position); - - // only detect new lines if the document has no line break yet - if (this.getLength() <= 1) - this.$detectNewLine(text); - - var lines = this.$split(text); - var firstLine = lines.splice(0, 1)[0]; - var lastLine = lines.length == 0 ? null : lines.splice(lines.length - 1, 1)[0]; - - position = this.insertInLine(position, firstLine); - if (lastLine !== null) { - position = this.insertNewLine(position); // terminate first line - position = this.insertLines(position.row, lines); - position = this.insertInLine(position, lastLine || ""); - } - return position; - }; - /** - * Document@change(e) - * - e (Object): Contains at least one property called `"action"`. `"action"` indicates the action that triggered the change. Each action also has a set of additional properties. - * - * Fires whenever the document changes. - * - * Several methods trigger different `"change"` events. Below is a list of each action type, followed by each property that's also available: - * - * * `"insertLines"` (emitted by [[Document.insertLines]]) - * * `range`: the [[Range]] of the change within the document - * * `lines`: the lines in the document that are changing - * * `"insertText"` (emitted by [[Document.insertNewLine]]) - * * `range`: the [[Range]] of the change within the document - * * `text`: the text that's being added - * * `"removeLines"` (emitted by [[Document.insertLines]]) - * * `range`: the [[Range]] of the change within the document - * * `lines`: the lines in the document that were removed - * * `nl`: the new line character (as defined by [[Document.getNewLineCharacter]]) - * * `"removeText"` (emitted by [[Document.removeInLine]] and [[Document.removeNewLine]]) - * * `range`: the [[Range]] of the change within the document - * * `text`: the text that's being removed - * - **/ - this.insertLines = function(row, lines) { - if (lines.length == 0) - return {row: row, column: 0}; - - // apply doesn't work for big arrays (smallest threshold is on safari 0xFFFF) - // to circumvent that we have to break huge inserts into smaller chunks here - 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); - this.$lines.splice.apply(this.$lines, args); - - var range = new Range(row, 0, row + lines.length, 0); - var delta = { - action: "insertLines", - range: range, - lines: lines - }; - this._emit("change", { data: delta }); - return end || range.end; - }; - this.insertNewLine = function(position) { - position = this.$clipPosition(position); - var line = this.$lines[position.row] || ""; - - this.$lines[position.row] = line.substring(0, position.column); - this.$lines.splice(position.row + 1, 0, line.substring(position.column, line.length)); - - var end = { - row : position.row + 1, - column : 0 - }; - - var delta = { - action: "insertText", - range: Range.fromPoints(position, end), - text: this.getNewLineCharacter() - }; - this._emit("change", { data: delta }); - - return end; - }; - this.insertInLine = function(position, text) { - if (text.length == 0) - return position; - - var line = this.$lines[position.row] || ""; - - this.$lines[position.row] = line.substring(0, position.column) + text - + line.substring(position.column); - - var end = { - row : position.row, - column : position.column + text.length - }; - - var delta = { - action: "insertText", - range: Range.fromPoints(position, end), - text: text - }; - this._emit("change", { data: delta }); - - return end; - }; - this.remove = function(range) { - // clip to document - range.start = this.$clipPosition(range.start); - range.end = this.$clipPosition(range.end); - - if (range.isEmpty()) - return range.start; - - var firstRow = range.start.row; - var lastRow = range.end.row; - - if (range.isMultiLine()) { - var firstFullRow = range.start.column == 0 ? firstRow : firstRow + 1; - var lastFullRow = lastRow - 1; - - if (range.end.column > 0) - this.removeInLine(lastRow, 0, range.end.column); - - if (lastFullRow >= firstFullRow) - this.removeLines(firstFullRow, lastFullRow); - - if (firstFullRow != firstRow) { - this.removeInLine(firstRow, range.start.column, this.getLine(firstRow).length); - this.removeNewLine(range.start.row); - } - } - else { - this.removeInLine(firstRow, range.start.column, range.end.column); - } - return range.start; - }; - this.removeInLine = function(row, startColumn, endColumn) { - if (startColumn == endColumn) - return; - - var range = new Range(row, startColumn, row, endColumn); - var line = this.getLine(row); - var removed = line.substring(startColumn, endColumn); - var newLine = line.substring(0, startColumn) + line.substring(endColumn, line.length); - this.$lines.splice(row, 1, newLine); - - var delta = { - action: "removeText", - range: range, - text: removed - }; - this._emit("change", { data: delta }); - return range.start; - }; - this.removeLines = function(firstRow, lastRow) { - var range = new Range(firstRow, 0, lastRow + 1, 0); - var removed = this.$lines.splice(firstRow, lastRow - firstRow + 1); - - var delta = { - action: "removeLines", - range: range, - nl: this.getNewLineCharacter(), - lines: removed - }; - this._emit("change", { data: delta }); - return removed; - }; - this.removeNewLine = function(row) { - var firstLine = this.getLine(row); - var secondLine = this.getLine(row+1); - - var range = new Range(row, firstLine.length, row+1, 0); - var line = firstLine + secondLine; - - this.$lines.splice(row, 2, line); - - var delta = { - action: "removeText", - range: range, - text: this.getNewLineCharacter() - }; - 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; - - this.remove(range); - if (text) { - var end = this.insert(range.start, text); - } - else { - end = range.start; - } - - return end; - }; - this.applyDeltas = function(deltas) { - for (var i=0; i<deltas.length; i++) { - var delta = deltas[i]; - var range = Range.fromPoints(delta.range.start, delta.range.end); - - if (delta.action == "insertLines") - this.insertLines(range.start.row, delta.lines); - else if (delta.action == "insertText") - this.insert(range.start, delta.text); - else if (delta.action == "removeLines") - this.removeLines(range.start.row, range.end.row - 1); - else if (delta.action == "removeText") - this.remove(range); - } - }; - this.revertDeltas = function(deltas) { - for (var i=deltas.length-1; i>=0; i--) { - var delta = deltas[i]; - - var range = Range.fromPoints(delta.range.start, delta.range.end); - - if (delta.action == "insertLines") - this.removeLines(range.start.row, range.end.row - 1); - else if (delta.action == "insertText") - this.remove(range); - else if (delta.action == "removeLines") - this.insertLines(range.start.row, delta.lines); - else if (delta.action == "removeText") - this.insert(range.start, delta.text); - } - }; - -}).call(Document.prototype); - -exports.Document = Document; -}); - -define('ace/range', ['require', 'exports', 'module' ], function(require, exports, module) { - - -/** - * class Range - * - * This object is used in various places to indicate a region within the editor. To better visualize how this works, imagine a rectangle. Each quadrant of the rectangle is analogus to a range, as ranges contain a starting row and starting column, and an ending row, and ending column. - * - **/ - -/** - * new Range(startRow, startColumn, endRow, endColumn) - * - startRow (Number): The starting row - * - startColumn (Number): The starting column - * - endRow (Number): The ending row - * - endColumn (Number): The ending column - * - * Creates a new `Range` object with the given starting and ending row and column points. - * - **/ -var Range = function(startRow, startColumn, endRow, endColumn) { - this.start = { - row: startRow, - column: startColumn - }; - - this.end = { - row: endRow, - column: endColumn - }; -}; - -(function() { - /** - * Range.isEqual(range) -> Boolean - * - range (Range): A range to check against - * - * Returns `true` if and only if the starting row and column, and ending tow and column, are equivalent to those given by `range`. - * - **/ - 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; - }; - this.compareRange = function(range) { - var cmp, - end = range.end, - start = range.start; - - cmp = this.compare(end.row, end.column); - if (cmp == 1) { - cmp = this.compare(start.row, start.column); - if (cmp == 1) { - return 2; - } else if (cmp == 0) { - return 1; - } else { - return 0; - } - } else if (cmp == -1) { - return -2; - } else { - cmp = this.compare(start.row, start.column); - if (cmp == -1) { - return -1; - } else if (cmp == 1) { - return 42; - } else { - return 0; - } - } - } - - /** related to: Range.compare - * Range.comparePoint(p) -> Number - * - p (Range): A point to compare with - * + (Number): This method returns one of the following numbers:<br/> - * * `0` if the two points are exactly equal<br/> - * * `-1` if `p.row` is less then the calling range<br/> - * * `1` if `p.row` is greater than the calling range<br/> - * <br/> - * If the starting row of the calling range is equal to `p.row`, and:<br/> - * * `p.column` is greater than or equal to the calling range's starting column, this returns `0`<br/> - * * Otherwise, it returns -1<br/> - *<br/> - * If the ending row of the calling range is equal to `p.row`, and:<br/> - * * `p.column` is less than or equal to the calling range's ending column, this returns `0`<br/> - * * Otherwise, it returns 1<br/> - * - * Checks the row and column points of `p` with the row and column points of the calling range. - * - * - * - **/ - this.comparePoint = function(p) { - return this.compare(p.row, p.column); - } - - /** related to: Range.comparePoint - * Range.containsRange(range) -> Boolean - * - range (Range): A range to compare with - * - * Checks the start and end points of `range` and compares them to the calling range. Returns `true` if the `range` is contained within the caller's range. - * - **/ - this.containsRange = function(range) { - return this.comparePoint(range.start) == 0 && this.comparePoint(range.end) == 0; - } - - /** - * Range.intersects(range) -> Boolean - * - range (Range): A range to compare with - * - * Returns `true` if passed in `range` intersects with the one calling this method. - * - **/ - this.intersects = function(range) { - var cmp = this.compareRange(range); - return (cmp == -1 || cmp == 0 || cmp == 1); - } - - /** - * Range.isEnd(row, column) -> Boolean - * - row (Number): A row point to compare with - * - column (Number): A column point to compare with - * - * Returns `true` if the caller's ending row point is the same as `row`, and if the caller's ending column is the same as `column`. - * - **/ - this.isEnd = function(row, column) { - return this.end.row == row && this.end.column == column; - } - - /** - * Range.isStart(row, column) -> Boolean - * - row (Number): A row point to compare with - * - column (Number): A column point to compare with - * - * Returns `true` if the caller's starting row point is the same as `row`, and if the caller's starting column is the same as `column`. - * - **/ - this.isStart = function(row, column) { - return this.start.row == row && this.start.column == column; - } - - /** - * Range.setStart(row, column) - * - row (Number): A row point to set - * - column (Number): A column point to set - * - * Sets the starting row and column for the range. - * - **/ - this.setStart = function(row, column) { - if (typeof row == "object") { - this.start.column = row.column; - this.start.row = row.row; - } else { - this.start.row = row; - this.start.column = column; - } - } - - /** - * Range.setEnd(row, column) - * - row (Number): A row point to set - * - column (Number): A column point to set - * - * Sets the starting row and column for the range. - * - **/ - this.setEnd = function(row, column) { - if (typeof row == "object") { - this.end.column = row.column; - this.end.row = row.row; - } else { - this.end.row = row; - this.end.column = column; - } - } - - /** related to: Range.compare - * Range.inside(row, column) -> Boolean - * - row (Number): A row point to compare with - * - column (Number): A column point to compare with - * - * Returns `true` if the `row` and `column` are within the given range. - * - **/ - this.inside = function(row, column) { - if (this.compare(row, column) == 0) { - if (this.isEnd(row, column) || this.isStart(row, column)) { - return false; - } else { - return true; - } - } - return false; - } - - /** related to: Range.compare - * Range.insideStart(row, column) -> Boolean - * - row (Number): A row point to compare with - * - column (Number): A column point to compare with - * - * Returns `true` if the `row` and `column` are within the given range's starting points. - * - **/ - this.insideStart = function(row, column) { - if (this.compare(row, column) == 0) { - if (this.isEnd(row, column)) { - return false; - } else { - return true; - } - } - return false; - } - - /** related to: Range.compare - * Range.insideEnd(row, column) -> Boolean - * - row (Number): A row point to compare with - * - column (Number): A column point to compare with - * - * Returns `true` if the `row` and `column` are within the given range's ending points. - * - **/ - this.insideEnd = function(row, column) { - if (this.compare(row, column) == 0) { - if (this.isStart(row, column)) { - return false; - } else { - return true; - } - } - return false; - } - - /** - * Range.compare(row, column) -> Number - * - row (Number): A row point to compare with - * - column (Number): A column point to compare with - * + (Number): This method returns one of the following numbers:<br/> - * * `0` if the two points are exactly equal <br/> - * * `-1` if `p.row` is less then the calling range <br/> - * * `1` if `p.row` is greater than the calling range <br/> - * <br/> - * If the starting row of the calling range is equal to `p.row`, and: <br/> - * * `p.column` is greater than or equal to the calling range's starting column, this returns `0`<br/> - * * Otherwise, it returns -1<br/> - * <br/> - * If the ending row of the calling range is equal to `p.row`, and: <br/> - * * `p.column` is less than or equal to the calling range's ending column, this returns `0` <br/> - * * Otherwise, it returns 1 - * - * Checks the row and column points with the row and column points of the calling range. - * - * - **/ - this.compare = function(row, column) { - if (!this.isMultiLine()) { - if (row === this.start.row) { - return column < this.start.column ? -1 : (column > this.end.column ? 1 : 0); - }; - } - - if (row < this.start.row) - return -1; - - if (row > this.end.row) - return 1; - - if (this.start.row === row) - return column >= this.start.column ? 0 : -1; - - if (this.end.row === row) - return column <= this.end.column ? 0 : 1; - - return 0; - }; - this.compareStart = function(row, column) { - if (this.start.row == row && this.start.column == column) { - return -1; - } else { - return this.compare(row, column); - } - } - - /** - * Range.compareEnd(row, column) -> Number - * - row (Number): A row point to compare with - * - column (Number): A column point to compare with - * + (Number): This method returns one of the following numbers:<br/> - * * `0` if the two points are exactly equal<br/> - * * `-1` if `p.row` is less then the calling range<br/> - * * `1` if `p.row` is greater than the calling range, or if `isEnd` is `true.<br/> - * <br/> - * If the starting row of the calling range is equal to `p.row`, and:<br/> - * * `p.column` is greater than or equal to the calling range's starting column, this returns `0`<br/> - * * Otherwise, it returns -1<br/> - *<br/> - * If the ending row of the calling range is equal to `p.row`, and:<br/> - * * `p.column` is less than or equal to the calling range's ending column, this returns `0`<br/> - * * Otherwise, it returns 1 - * - * Checks the row and column points with the row and column points of the calling range. - * - * - **/ - this.compareEnd = function(row, column) { - if (this.end.row == row && this.end.column == column) { - return 1; - } else { - return this.compare(row, column); - } - } - - /** - * Range.compareInside(row, column) -> Number - * - row (Number): A row point to compare with - * - column (Number): A column point to compare with - * + (Number): This method returns one of the following numbers:<br/> - * * `1` if the ending row of the calling range is equal to `row`, and the ending column of the calling range is equal to `column`<br/> - * * `-1` if the starting row of the calling range is equal to `row`, and the starting column of the calling range is equal to `column`<br/> - * <br/> - * Otherwise, it returns the value after calling [[Range.compare `compare()`]]. - * - * Checks the row and column points with the row and column points of the calling range. - * - * - * - **/ - this.compareInside = function(row, column) { - if (this.end.row == row && this.end.column == column) { - return 1; - } else if (this.start.row == row && this.start.column == column) { - return -1; - } else { - return this.compare(row, column); - } - } - - /** - * Range.clipRows(firstRow, lastRow) -> Range - * - firstRow (Number): The starting row - * - lastRow (Number): The ending row - * - * Returns the part of the current `Range` that occurs within the boundaries of `firstRow` and `lastRow` as a new `Range` object. - * - **/ - this.clipRows = function(firstRow, lastRow) { - if (this.end.row > lastRow) { - var end = { - row: lastRow+1, - column: 0 - }; - } - - if (this.start.row > lastRow) { - var start = { - row: lastRow+1, - column: 0 - }; - } - - if (this.start.row < firstRow) { - var start = { - row: firstRow, - column: 0 - }; - } - - if (this.end.row < firstRow) { - var end = { - row: firstRow, - column: 0 - }; - } - return Range.fromPoints(start || this.start, end || this.end); - }; - this.extend = function(row, column) { - var cmp = this.compare(row, column); - - if (cmp == 0) - return this; - else if (cmp == -1) - var start = {row: row, column: column}; - else - var end = {row: row, column: column}; - - return Range.fromPoints(start || this.start, end || this.end); - }; - - 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); - var screenPosEnd = - session.documentToScreenPosition(this.end); - - return new Range( - screenPosStart.row, screenPosStart.column, - screenPosEnd.row, screenPosEnd.column - ); - }; - -}).call(Range.prototype); -Range.fromPoints = function(start, end) { - return new Range(start.row, start.column, end.row, end.column); -}; - -exports.Range = Range; -}); - -define('ace/anchor', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/event_emitter'], function(require, exports, module) { - - -var oop = require("./lib/oop"); -var EventEmitter = require("./lib/event_emitter").EventEmitter; - -/** - * new Anchor(doc, row, column) - * - doc (Document): The document to associate with the anchor - * - row (Number): The starting row position - * - column (Number): The starting column position - * - * Creates a new `Anchor` and associates it with a document. - * - **/ - -var Anchor = exports.Anchor = function(doc, row, column) { - this.document = doc; - - if (typeof column == "undefined") - this.setPosition(row.row, row.column); - else - this.setPosition(row, column); - - this.$onChange = this.onChange.bind(this); - doc.on("change", this.$onChange); -}; - -(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; - - if (range.start.row == range.end.row && range.start.row != this.row) - return; - - if (range.start.row > this.row) - return; - - if (range.start.row == this.row && range.start.column > this.column) - return; - - var row = this.row; - var column = this.column; - - if (delta.action === "insertText") { - if (range.start.row === row && range.start.column <= column) { - if (range.start.row === range.end.row) { - column += range.end.column - range.start.column; - } - else { - column -= range.start.column; - row += range.end.row - range.start.row; - } - } - else if (range.start.row !== range.end.row && range.start.row < row) { - row += range.end.row - range.start.row; - } - } else if (delta.action === "insertLines") { - if (range.start.row <= row) { - row += range.end.row - range.start.row; - } - } - else if (delta.action == "removeText") { - if (range.start.row == row && range.start.column < column) { - if (range.end.column >= column) - column = range.start.column; - else - column = Math.max(0, column - (range.end.column - range.start.column)); - - } else if (range.start.row !== range.end.row && range.start.row < row) { - if (range.end.row == row) { - column = Math.max(0, column - range.end.column) + range.start.column; - } - row -= (range.end.row - range.start.row); - } - else if (range.end.row == row) { - row -= range.end.row - range.start.row; - column = Math.max(0, column - range.end.column) + range.start.column; - } - } else if (delta.action == "removeLines") { - if (range.start.row <= row) { - if (range.end.row <= row) - row -= range.end.row - range.start.row; - else { - row = range.start.row; - column = 0; - } - } - } - - this.setPosition(row, column, true); - }; - - this.setPosition = function(row, column, noClip) { - var pos; - if (noClip) { - pos = { - row: row, - column: column - }; - } - else { - pos = this.$clipPositionToDocument(row, column); - } - - if (this.row == pos.row && this.column == pos.column) - return; - - var old = { - row: this.row, - column: this.column - }; - - this.row = pos.row; - this.column = pos.column; - this._emit("change", { - old: old, - value: pos - }); - }; - - this.detach = function() { - this.document.removeEventListener("change", this.$onChange); - }; - - this.$clipPositionToDocument = function(row, column) { - var pos = {}; - - if (row >= this.document.getLength()) { - pos.row = Math.max(0, this.document.getLength() - 1); - pos.column = this.document.getLine(pos.row).length; - } - else if (row < 0) { - pos.row = 0; - pos.column = 0; - } - else { - pos.row = row; - pos.column = Math.min(this.document.getLine(pos.row).length, Math.max(0, column)); - } - - if (column < 0) - pos.column = 0; - - return pos; - }; - -}).call(Anchor.prototype); - -}); - -define('ace/lib/lang', ['require', 'exports', 'module' ], function(require, exports, module) { - - -exports.stringReverse = function(string) { - return string.split("").reverse().join(""); -}; - -exports.stringRepeat = function (string, count) { - return new Array(count + 1).join(string); -}; - -var trimBeginRegexp = /^\s\s*/; -var trimEndRegexp = /\s\s*$/; - -exports.stringTrimLeft = function (string) { - return string.replace(trimBeginRegexp, ''); -}; - -exports.stringTrimRight = function (string) { - return string.replace(trimEndRegexp, ''); -}; - -exports.copyObject = function(obj) { - var copy = {}; - for (var key in obj) { - copy[key] = obj[key]; - } - return copy; -}; - -exports.copyArray = function(array){ - var copy = []; - for (var i=0, l=array.length; i<l; i++) { - if (array[i] && typeof array[i] == "object") - copy[i] = this.copyObject( array[i] ); - else - copy[i] = array[i]; - } - return copy; -}; - -exports.deepCopy = function (obj) { - if (typeof obj != "object") { - return obj; - } - - var copy = obj.constructor(); - for (var key in obj) { - if (typeof obj[key] == "object") { - copy[key] = this.deepCopy(obj[key]); - } else { - copy[key] = obj[key]; - } - } - return copy; -}; - -exports.arrayToMap = function(arr) { - var map = {}; - for (var i=0; i<arr.length; i++) { - map[arr[i]] = 1; - } - return map; - -}; - -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]) { - array.splice(i, 1); - } - } -}; - -exports.escapeRegExp = function(str) { - return str.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1'); -}; - -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; - var callback = function() { - timer = null; - fcn(); - }; - - var deferred = function(timeout) { - deferred.cancel(); - timer = setTimeout(callback, timeout || 0); - return deferred; - }; - - deferred.schedule = deferred; - - deferred.call = function() { - this.cancel(); - fcn(); - return deferred; - }; - - deferred.cancel = function() { - clearTimeout(timer); - timer = null; - return deferred; - }; - - 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 - }, - unused: [ - { - 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, indent:4 -*/ - -/*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, Audio, - 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, DOMParser, Drag, - E, Enumerator, Enumerable, Element, Elements, Error, Effect, EvalError, Event, - Events, FadeAnimation, Field, Flash, Float32Array, Float64Array, Form, - FormField, Frame, FormData, Function, Fx, GetObject, Group, Hash, HotKey, - HTMLElement, HTMLAnchorElement, HTMLBaseElement, HTMLBlockquoteElement, - HTMLBodyElement, HTMLBRElement, HTMLButtonElement, HTMLCanvasElement, HTMLDirectoryElement, - HTMLDivElement, HTMLDListElement, HTMLFieldSetElement, - HTMLFontElement, HTMLFormElement, HTMLFrameElement, HTMLFrameSetElement, - HTMLHeadElement, HTMLHeadingElement, HTMLHRElement, HTMLHtmlElement, - HTMLIFrameElement, HTMLImageElement, HTMLInputElement, HTMLIsIndexElement, - HTMLLabelElement, HTMLLayerElement, HTMLLegendElement, HTMLLIElement, - HTMLLinkElement, HTMLMapElement, HTMLMenuElement, HTMLMetaElement, - HTMLModElement, HTMLObjectElement, HTMLOListElement, HTMLOptGroupElement, - HTMLOptionElement, HTMLParagraphElement, HTMLParamElement, HTMLPreElement, - HTMLQuoteElement, HTMLScriptElement, HTMLSelectElement, HTMLStyleElement, - HtmlTable, HTMLTableCaptionElement, HTMLTableCellElement, HTMLTableColElement, - HTMLTableElement, HTMLTableRowElement, HTMLTableSectionElement, - HTMLTextAreaElement, HTMLTitleElement, HTMLUListElement, HTMLVideoElement, - Iframe, IframeShim, Image, Int16Array, Int32Array, Int8Array, - Insertion, InputValidator, JSON, Keyboard, Locale, LN10, LN2, LOG10E, LOG2E, - MAX_VALUE, MIN_VALUE, Mask, Math, MenuItem, MessageChannel, MessageEvent, MessagePort, - 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, SharedWorker, String, Style, SyntaxError, Sortable, Sortables, - SortableObserver, Sound, Spinner, System, Swiff, Text, TextArea, Template, - Timer, Tips, Type, TypeError, Toggle, Try, "use strict", unescape, URI, URIError, URL, - VBArray, WSH, WScript, XDomainRequest, Web, Window, XMLDOM, XMLHttpRequest, XMLSerializer, - XPathEvaluator, XPathException, XPathExpression, XPathNamespace, XPathNSResolver, XPathResult, - "\\", a, addEventListener, address, alert, apply, applicationCache, arguments, arity, asi, atob, - b, basic, basicToken, bitwise, block, blur, boolOptions, boss, browser, btoa, 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, else, emit, encodeURI, encodeURIComponent, - entityify, eqeqeq, eqnull, errors, es5, escape, esnext, eval, event, evidence, evil, - ex, exception, exec, exps, expr, exports, FileReader, first, floor, focus, - forin, fragment, frames, from, fromCharCode, fud, funcscope, funct, function, functions, - g, gc, getComputedStyle, getRow, getter, getterToken, GLOBAL, global, globals, globalstrict, - hasOwnProperty, help, history, i, id, identifier, immed, implieds, importPackage, include, - indent, indexOf, init, ins, instanceOf, isAlpha, isApplicationRunning, isArray, - isDigit, isFinite, isNaN, iterator, java, join, jshint, - JSHINT, json, jquery, jQuery, keys, label, labelled, last, lastsemic, laxbreak, laxcomma, - latedef, lbp, led, left, length, line, load, loadClass, localStorage, location, - log, loopfunc, m, match, maxerr, maxlen, member,message, meta, module, moveBy, - moveTo, mootools, multistr, name, navigator, new, newcap, noarg, node, noempty, nomen, - nonew, nonstandard, nud, onbeforeunload, onblur, onerror, onevar, onecase, onfocus, - onload, onresize, onunload, open, openDatabase, openURL, opener, opera, options, outer, param, - parent, parseFloat, parseInt, passfail, plusplus, predef, print, process, prompt, - proto, prototype, prototypejs, provides, 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, sessionStorage, setInterval, setTimeout, setter, setterToken, shift, slice, - smarttabs, 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, undefs, unused, urls, validthis, - value, valueOf, var, version, WebSocket, withstmt, 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 () { - - - 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 - 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 - // enables 'strict') - 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 omitted for the trailing - // statements inside of a one-line blocks. - 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 - // loops - 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 - // 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 - nonstandard : true, // if non-standard (but widely adopted) globals should - // be predefined - nomen : true, // if names should be checked - onevar : true, // if only one var statement per function should be - // allowed - 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 - // predefined - regexdash : true, // if unescaped first/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 - smarttabs : true, // if smarttabs should be tolerated - // (http://www.emacswiki.org/emacs/SmartTabs) - strict : true, // require the 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 - validthis : true, // if 'this' inside a non-constructor function is valid. - // This is a function scoped option only. - withstmt : true, // if with statements should be allowed - white : true, // if strict whitespace rules apply - wsh : true // if the Windows Scripting Host environment globals - // should be predefined - }, - - // These are the JSHint options that can take any value - // (we use this object to detect invalid options) - valOptions = { - maxlen: false, - indent: false, - maxerr: false, - predef: false - }, - - - // browser contains a set of global names which are commonly provided by a - // web browser environment. - browser = { - ArrayBuffer : false, - ArrayBufferView : false, - Audio : 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, - 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, - 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 - }, - - 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, - Buffer : false, - console : false, - exports : false, - 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 - }, - - 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 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 - }, - - // widely adopted global names that are not part of ECMAScript standard - nonstandard = { - escape : false, - unescape : 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 - }, - - directive, - syntax = {}, - tab, - token, - urls, - useESNextSyntax, - warnings, - - wsh = { - ActiveXObject : true, - Enumerator : true, - GetObject : true, - ScriptEngine : true, - ScriptEngineBuildVersion : true, - ScriptEngineMajorVersion : true, - ScriptEngineMinorVersion : true, - VBArray : true, - WSH : true, - WScript : true, - XDomainRequest : 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*!|</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); - } - - function checkOption(name, t) { - if (valOptions[name] === undefined && boolOptions[name] === undefined) { - warning("Bad option: '" + name + "'.", t); - } - } - -// 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, '&') - .replace(/</g, '<') - .replace(/>/g, '>'); - }; - } - - 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); - 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.wsh) { - combine(predefined, wsh); - } - - if (option.esnext) { - useESNextSyntax(); - } - - 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).", - 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, - 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); - } - - 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; - - // If smarttabs option is used check for spaces followed by tabs only. - // Otherwise check for any occurrence of mixed tabs and spaces. - if (option.smarttabs) - at = s.search(/ \t/); - 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); - - // Check for trailing whitespaces - tw = option.trailing && s.match(/^(.*?)\s+$/); - if (tw && !/^\s+$/.test(s)) { - warningAt("Trailing whitespace.", line, tw[1].length + 1); - } - 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) === '_')) { - if (!option.node || token.id === '.' || - (value !== '__dirname' && value !== '__filename')) { - 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' || - i === 'case'); - } - 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; - } - - }, - - - // token -- this is called by advance to get the next token - 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); - } - - 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'; - // Octal literals fail in strict mode - // check if the number is between 00 and 07 - // where 'n' is the token next to 'c' - 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 '': - // last character is escape character - // always allow new line if escaped, but show - // warning if option is not set - 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; - 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 { - - // 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( -"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 '//': - s = ''; - token.comment = true; - break; - - // /* comment - - case '/*': - 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 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( -"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( -"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, '^'); - } - } - 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( -"Unexpected escaped character '{a}' in regular expression.", line, from + l, c); - } - l += 1; - - // \w, \s and \d are never part of a character range - 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( -"'{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 && type !== "exception") - 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 (o === '/*jshint') { - checkOption(t.value, 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 (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 (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, 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'; - 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; - } - - -// 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) { - 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.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.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); - } - - -// 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 (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 ((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}'.", 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, 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 (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( -"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') { - 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; - - if (t.id === ";") { - 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 === ',') { - return comma(); - } - - if (nexttoken.id !== ';') { - if (!option.asi) { - // If this is the last statement in a block that ends on - // the same line *and* option lastsemic is on, ignore the warning. - // Otherwise, complain about missing semicolon. - if (!option.lastsemic || nexttoken.id !== '}' || - nexttoken.line !== token.line) { - warningAt("Missing semicolon.", token.line, token.character); - } - } - } else { - adjacent(token, nexttoken); - advance(';'); - nonadjacent(token, nexttoken); - } - } - -// Restore the indentation. - - indent = i; - scope = s; - return r; - } - - - function statements(startLine) { - var a = [], f, 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; - } - - - /* - * read all directives - * recognizes a simple form of asi, but always - * warns, if it is used - */ - 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 === "}") { - // directive with no other statements, warn about missing semicolon - 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") { - option.newcap = true; - option.undef = true; - } - - // there's no directive negation, so always set to true - directive[token.value] = true; - - if (p.id === ";") { - advance(";"); - } - continue; - } - break; - } - } - - - /* - * 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). - * isfunc - true if block is a function body - */ - 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; - - 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); - - 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; - // test indentation only if statement is in new line - 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."); - } - 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; - } - } else if (funct['(global)']) { - // 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. - - if (option.undef && typeof predefined[v] !== 'boolean') { - // Attempting to subscript a null reference will throw an - // error, even within the typeof and delete operators - if (!(anonname === 'typeof' || anonname === 'delete') || - (nexttoken && (nexttoken.value === '.' || nexttoken.value === '['))) { - - isundef(funct, "'{a}' is not defined.", token, v); - } - } - note_implied(token); - } else { - // If the name is already defined in the current - // function, but not as outer, then there is a scope error. - - 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 (option.undef) { - // Attempting to subscript a null reference will throw an - // error, even within the typeof and delete operators - 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': - 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 (directive['use strict'] && funct['(global)']) { - warning("Strict violation.", x); - } - }); - reservevar('eval'); - reservevar('false'); - reservevar('Infinity'); - reservevar('NaN'); - 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.", 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 (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 (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 === '(' || - (nexttoken.id === '.' && (peek().value === 'call' || peek().value === 'apply'))) { - warning( -"Move the invocation into the parens that contain the function.", nexttoken); - } else { - 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(')'); - 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, false, true); - scope = oldScope; - option = oldOption; - funct['(last)'] = token.line; - funct = funct['(context)']; - return f; - } - - - (function (x) { - x.nud = function () { - var b, f, i, j, 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); - - // Check for lonely setters if in the ES5 mode. - 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('{'))); - -// This Function is called when esnext option is set to true -// it adds the `const` statement to JSHINT - - 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) { - // 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 (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'); - 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'); - doFunction(i, 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; - - 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: - // 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') { - 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; - 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 && (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); - - 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; - -// 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 = []; - JSHINT.undefs = []; - 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 = []; - stack = null; - member = {}; - membersOnly = null; - implied = {}; - inblock = false; - lookahead = []; - jsonmode = false; - warnings = 0; - lex.init(s); - prereg = true; - directive = {}; - - prevtoken = token = nexttoken = syntax['(begin)']; - - // Check options - for (var name in o) { - if (is_own(o, name)) { - checkOption(name, token); - } - } - - assume(); - - // combine the passed globals after we've assumed all our options - combine(predefined, g || {}); - - //reset values - comma.first = true; - - 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('(end)'); - - var markDefined = function (name, context) { - do { - if (typeof context[name] === 'string') { - // JSHINT marks unused variables as 'unused' and - // unused function declaration as 'unction'. This - // code changes such instances back 'var' and - // 'closure' so that the code in JSHINT.data() - // doesn't think they're unused. - - 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; - }; - - // Check queued 'x is not defined' instances to see if they're still undefined. - 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)); - } - } - } 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); - } - } - - return JSHINT.errors.length === 0; - }; - - // Data summary. - itself.data = function () { - - var data = { functions: [], options: option }, 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> <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> <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; - - return itself; -}()); - -// Make JSHINT a Node module, if possible. -if (typeof exports === 'object' && exports) - exports.JSHINT = JSHINT; - -}); - -/* - * Narcissus - JS implemented in JS. - * - * Parser. - */ - -define('ace/narcissus/parser', ['require', 'exports', 'module' , 'ace/narcissus/lexer', 'ace/narcissus/definitions', 'ace/narcissus/options'], function(require, exports, module) { - -var lexer = require('./lexer'); -var definitions = require('./definitions'); -var options = require('./options'); -var Tokenizer = lexer.Tokenizer; - -var Dict = definitions.Dict; -var Stack = definitions.Stack; - -// Set constants in the local scope. -eval(definitions.consts); -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 Parser(tokenizer) { - tokenizer.parser = this; - this.t = tokenizer; - this.x = null; - this.unexpectedEOF = false; - options.mozillaMode && (this.mozillaMode = true); - options.parenFreeMode && (this.parenFreeMode = true); -} - -function StaticContext(parentScript, parentBlock, inModule, inFunction, strictMode) { - 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.strictMode = strictMode; -} - -StaticContext.prototype = { - // 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 Dict(); - 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; - }, - canImport: function() { - return this.topLevel && !this.inFunction; - }, - canExport: function() { - return this.inModule && this.topLevel && !this.inFunction; - }, - banWith: function() { - return this.strictMode || this.inModule; - }, - modulesAllowed: function() { - return this.topLevel && !this.inFunction; - } -}; - -var Pp = Parser.prototype; - -Pp.mozillaMode = false; - -Pp.parenFreeMode = false; - -Pp.withContext = function(x, f) { - var x0 = this.x; - this.x = x; - var result = f.call(this); - // NB: we don't bother with finally, since exceptions trash the parser - this.x = x0; - return result; -}; - -Pp.newNode = function newNode(opts) { - return new Node(this.t, opts); -}; - -Pp.fail = function fail(msg) { - throw this.t.newSyntaxError(msg); -}; - -Pp.match = function match(tt, scanOperand, keywordIsName) { - return this.t.match(tt, scanOperand, keywordIsName); -}; - -Pp.mustMatch = function mustMatch(tt, keywordIsName) { - return this.t.mustMatch(tt, keywordIsName); -}; - -Pp.peek = function peek(scanOperand) { - return this.t.peek(scanOperand); -}; - -Pp.peekOnSameLine = function peekOnSameLine(scanOperand) { - return this.t.peekOnSameLine(scanOperand); -}; - -Pp.done = function done() { - return this.t.done; -}; -Pp.Script = function Script(inModule, inFunction, expectEnd) { - var node = this.newNode(scriptInit()); - var x2 = new StaticContext(node, node, inModule, inFunction); - this.withContext(x2, function() { - this.Statements(node, true); - }); - if (expectEnd && !this.done()) - this.fail("expected end of input"); - return node; -}; -function Pragma(n) { - if (n.type === SEMICOLON) { - var e = n.expression; - if (e.type === STRING && e.value === "use strict") { - n.pragma = "strict"; - return true; - } - } - return false; -} - -/* - * 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; - } - - this.filename = t.filename; - this.children = []; - - for (var prop in init) - this[prop] = init[prop]; -} - -/* - * SyntheticNode :: (optional init object) -> node - */ -function SyntheticNode(init) { - this.children = []; - for (var prop in init) - this[prop] = init[prop]; - this.synthetic = true; -} - -var Np = Node.prototype = SyntheticNode.prototype = {}; -Np.constructor = Node; - -var 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); - // avoid infinite recursion in case of back-links - if (this.generatingSource) - return mock.toSource(); - this.generatingSource = true; - 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]; - } - try { - return mock.toSource(); - } finally { - delete this.generatingSource; - } -}; - -// 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; }); - var 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.synth = function(init) { - var node = new SyntheticNode(init); - node.filename = this.filename; - node.lineno = this.lineno; - node.start = this.start; - node.end = this.end; - return node; -}; - -var LOOP_INIT = { isLoop: true }; - -function blockInit() { - return { type: BLOCK, varDecls: [] }; -} - -function scriptInit() { - return { type: SCRIPT, - funDecls: [], - varDecls: [], - modDefns: new Dict(), - modAssns: new Dict(), - modDecls: new Dict(), - modLoads: new Dict(), - impDecls: [], - expDecls: [], - exports: new Dict(), - hasEmptyReturn: false, - hasReturnWithValue: false, - hasYield: false }; -} - -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); - -Pp.MaybeLeftParen = function MaybeLeftParen() { - if (this.parenFreeMode) - return this.match(LEFT_PAREN) ? LEFT_PAREN : END; - return this.mustMatch(LEFT_PAREN).type; -}; - -Pp.MaybeRightParen = function MaybeRightParen(p) { - if (p === LEFT_PAREN) - this.mustMatch(RIGHT_PAREN); -} - -/* - * Statements :: (node[, boolean]) -> void - * - * Parses a sequence of Statements. - */ -Pp.Statements = function Statements(n, topLevel) { - var prologue = !!topLevel; - try { - while (!this.done() && this.peek(true) !== RIGHT_CURLY) { - var n2 = this.Statement(); - n.push(n2); - if (prologue && Pragma(n2)) { - this.x.strictMode = true; - n.strict = true; - } else { - prologue = false; - } - } - } catch (e) { - try { - if (this.done()) - this.unexpectedEOF = true; - } catch(e) {} - throw e; - } -} - -Pp.Block = function Block() { - this.mustMatch(LEFT_CURLY); - var n = this.newNode(blockInit()); - var x2 = this.x.update({ parentBlock: n }).pushTarget(n); - this.withContext(x2, function() { - this.Statements(n); - }); - this.mustMatch(RIGHT_CURLY); - return n; -} - -var DECLARED_FORM = 0, EXPRESSED_FORM = 1, STATEMENT_FORM = 2; -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 :: (Dict, 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 Dict(); - - 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 :: () -> node - * - * Parses a Statement. - */ -Pp.Statement = function Statement() { - var i, label, n, n2, p, c, ss, tt = this.t.get(true), tt2, x0, x2, x3; - - var comments = this.t.blockComments; - - // Cases for statements ending in a right curly return early, avoiding the - // common semicolon insertion magic after this switch. - switch (tt) { - case IMPORT: - if (!this.x.canImport()) - this.fail("illegal context for import statement"); - n = this.newNode(); - n.pathList = this.ImportPathList(); - this.x.parentScript.impDecls.push(n); - break; - - case EXPORT: - if (!this.x.canExport()) - this.fail("export statement not in module top level"); - switch (this.peek()) { - case MODULE: - case FUNCTION: - case LET: - case VAR: - case CONST: - n = this.Statement(); - n.blockComments = comments; - n.exported = true; - this.x.parentScript.expDecls.push(n); - registerExport(this.x.parentScript.exports, n); - return n; - } - n = this.newNode(); - n.pathList = this.ExportPathList(); - this.x.parentScript.expDecls.push(n); - registerExport(this.x.parentScript.exports, n); - break; - - case FUNCTION: - // DECLARED_FORM extends funDecls of x, STATEMENT_FORM doesn't. - return this.FunctionDefinition(true, this.x.topLevel ? DECLARED_FORM : STATEMENT_FORM, comments); - - case LEFT_CURLY: - n = this.newNode(blockInit()); - x2 = this.x.update({ parentBlock: n }).pushTarget(n).nest(); - this.withContext(x2, function() { - this.Statements(n); - }); - this.mustMatch(RIGHT_CURLY); - return n; - - case IF: - n = this.newNode(); - n.condition = this.HeadExpression(); - x2 = this.x.pushTarget(n).nest(); - this.withContext(x2, function() { - n.thenPart = this.Statement(); - n.elsePart = this.match(ELSE, true) ? this.Statement() : null; - }); - return n; - - case SWITCH: - // This allows CASEs after a DEFAULT, which is in the standard. - n = this.newNode({ cases: [], defaultIndex: -1 }); - n.discriminant = this.HeadExpression(); - x2 = this.x.pushTarget(n).nest(); - this.withContext(x2, function() { - this.mustMatch(LEFT_CURLY); - while ((tt = this.t.get()) !== RIGHT_CURLY) { - switch (tt) { - case DEFAULT: - if (n.defaultIndex >= 0) - this.fail("More than one switch default"); - // FALL THROUGH - case CASE: - n2 = this.newNode(); - if (tt === DEFAULT) - n.defaultIndex = n.cases.length; - else - n2.caseLabel = this.Expression(COLON); - break; - - default: - this.fail("Invalid switch case"); - } - this.mustMatch(COLON); - n2.statements = this.newNode(blockInit()); - while ((tt=this.peek(true)) !== CASE && tt !== DEFAULT && - tt !== RIGHT_CURLY) - n2.statements.push(this.Statement()); - n.cases.push(n2); - } - }); - return n; - - case FOR: - n = this.newNode(LOOP_INIT); - n.blockComments = comments; - if (this.match(IDENTIFIER)) { - if (this.t.token.value === "each") - n.isEach = true; - else - this.t.unget(); - } - if (!this.parenFreeMode) - this.mustMatch(LEFT_PAREN); - x2 = this.x.pushTarget(n).nest(); - x3 = this.x.update({ inForLoopInit: true }); - n2 = null; - if ((tt = this.peek(true)) !== SEMICOLON) { - this.withContext(x3, function() { - if (tt === VAR || tt === CONST) { - this.t.get(); - n2 = this.Variables(); - } else if (tt === LET) { - this.t.get(); - if (this.peek() === LEFT_PAREN) { - n2 = this.LetBlock(false); - } else { - // Let in for head, we need to add an implicit block - // around the rest of the for. - this.x.parentBlock = n; - n.varDecls = []; - n2 = this.Variables(); - } - } else { - n2 = this.Expression(); - } - }); - } - if (n2 && this.match(IN)) { - n.type = FOR_IN; - this.withContext(x3, function() { - n.object = this.Expression(); - 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) { - // FIXME: this.fail ? - throw new SyntaxError("Invalid for..in left-hand side", - this.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 = this.checkDestructuring(n2); - } - n.iterator = n2; - } - }); - } else { - x3.inForLoopInit = false; - n.setup = n2; - this.mustMatch(SEMICOLON); - if (n.isEach) - this.fail("Invalid for each..in loop"); - this.withContext(x3, function() { - n.condition = (this.peek(true) === SEMICOLON) - ? null - : this.Expression(); - this.mustMatch(SEMICOLON); - tt2 = this.peek(true); - n.update = (this.parenFreeMode - ? tt2 === LEFT_CURLY || definitions.isStatementStartCode[tt2] - : tt2 === RIGHT_PAREN) - ? null - : this.Expression(); - }); - } - if (!this.parenFreeMode) - this.mustMatch(RIGHT_PAREN); - this.withContext(x2, function() { - n.body = this.Statement(); - }); - return n; - - case WHILE: - n = this.newNode({ isLoop: true }); - n.blockComments = comments; - n.condition = this.HeadExpression(); - x2 = this.x.pushTarget(n).nest(); - this.withContext(x2, function() { - n.body = this.Statement(); - }); - return n; - - case DO: - n = this.newNode({ isLoop: true }); - n.blockComments = comments; - x2 = this.x.pushTarget(n).next(); - this.withContext(x2, function() { - n.body = this.Statement(); - }); - this.mustMatch(WHILE); - n.condition = this.HeadExpression(); - // <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. - this.match(SEMICOLON); - return n; - - case BREAK: - case CONTINUE: - n = this.newNode(); - n.blockComments = comments; - - // handle the |foo: break foo;| corner case - x2 = this.x.pushTarget(n); - - if (this.peekOnSameLine() === IDENTIFIER) { - this.t.get(); - n.label = this.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) - this.fail("Invalid " + ((tt === BREAK) ? "break" : "continue")); - if (!n.target.isLoop && tt === CONTINUE) - this.fail("Invalid continue"); - - break; - - case TRY: - n = this.newNode({ catchClauses: [] }); - n.blockComments = comments; - n.tryBlock = this.Block(); - while (this.match(CATCH)) { - n2 = this.newNode(); - p = this.MaybeLeftParen(); - switch (this.t.get()) { - case LEFT_BRACKET: - case LEFT_CURLY: - // Destructured catch identifiers. - this.t.unget(); - n2.varName = this.DestructuringExpression(true); - break; - case IDENTIFIER: - n2.varName = this.t.token.value; - break; - default: - this.fail("missing identifier in catch"); - break; - } - if (this.match(IF)) { - if (!this.mozillaMode) - this.fail("Illegal catch guard"); - if (n.catchClauses.length && !n.catchClauses.top().guard) - this.fail("Guarded catch after unguarded"); - n2.guard = this.Expression(); - } - this.MaybeRightParen(p); - n2.block = this.Block(); - n.catchClauses.push(n2); - } - if (this.match(FINALLY)) - n.finallyBlock = this.Block(); - if (!n.catchClauses.length && !n.finallyBlock) - this.fail("Invalid try statement"); - return n; - - case CATCH: - case FINALLY: - this.fail(definitions.tokens[tt] + " without preceding try"); - - case THROW: - n = this.newNode(); - n.exception = this.Expression(); - break; - - case RETURN: - n = this.ReturnOrYield(); - break; - - case WITH: - if (this.x.banWith()) - this.fail("with statements not allowed in strict code or modules"); - n = this.newNode(); - n.blockComments = comments; - n.object = this.HeadExpression(); - x2 = this.x.pushTarget(n).next(); - this.withContext(x2, function() { - n.body = this.Statement(); - }); - return n; - - case VAR: - case CONST: - n = this.Variables(); - break; - - case LET: - if (this.peek() === LEFT_PAREN) { - n = this.LetBlock(true); - return n; - } - n = this.Variables(); - break; - - case DEBUGGER: - n = this.newNode(); - break; - - case NEWLINE: - case SEMICOLON: - n = this.newNode({ type: SEMICOLON }); - n.blockComments = comments; - n.expression = null; - return n; - - case IDENTIFIER: - case USE: - case MODULE: - switch (this.t.token.value) { - case "use": - if (!isPragmaToken(this.peekOnSameLine())) { - this.t.unget(); - break; - } - return this.newNode({ type: USE, params: this.Pragmas() }); - - case "module": - if (!this.x.modulesAllowed()) - this.fail("module declaration not at top level"); - this.x.parentScript.hasModules = true; - tt = this.peekOnSameLine(); - if (tt !== IDENTIFIER && tt !== LEFT_CURLY) { - this.t.unget(); - break; - } - n = this.newNode({ type: MODULE }); - n.blockComments = comments; - this.mustMatch(IDENTIFIER); - label = this.t.token.value; - - if (this.match(LEFT_CURLY)) { - n.name = label; - n.body = this.Script(true, false); - n.module = new Module(n); - this.mustMatch(RIGHT_CURLY); - this.x.parentScript.modDefns.set(n.name, n); - return n; - } - - this.t.unget(); - this.ModuleVariables(n); - return n; - - default: - tt = this.peek(); - // Labeled statement. - if (tt === COLON) { - label = this.t.token.value; - if (this.x.allLabels.has(label)) - this.fail("Duplicate label: " + label); - this.t.get(); - n = this.newNode({ type: LABEL, label: label }); - n.blockComments = comments; - x2 = this.x.pushLabel(label).nest(); - this.withContext(x2, function() { - n.statement = this.Statement(); - }); - n.target = (n.statement.type === LABEL) ? n.statement.target : n.statement; - return n; - } - // FALL THROUGH - } - // FALL THROUGH - - default: - // Expression statement. - // We unget the current token to parse the expression as a whole. - n = this.newNode({ type: SEMICOLON }); - this.t.unget(); - n.blockComments = comments; - n.expression = this.Expression(); - n.end = n.expression.end; - break; - } - - n.blockComments = comments; - this.MagicalSemicolon(); - return n; -} - -/* - * isPragmaToken :: (number) -> boolean - */ -function isPragmaToken(tt) { - switch (tt) { - case IDENTIFIER: - case STRING: - case NUMBER: - case NULL: - case TRUE: - case FALSE: - return true; - } - return false; -} - -/* - * Pragmas :: () -> Array[Array[token]] - */ -Pp.Pragmas = function Pragmas() { - var pragmas = []; - do { - pragmas.push(this.Pragma()); - } while (this.match(COMMA)); - this.MagicalSemicolon(); - return pragmas; -} - -/* - * Pragmas :: () -> Array[token] - */ -Pp.Pragma = function Pragma() { - var items = []; - var tt; - do { - tt = this.t.get(true); - items.push(this.t.token); - } while (isPragmaToken(this.peek())); - return items; -} - -/* - * MagicalSemicolon :: () -> void - */ -Pp.MagicalSemicolon = function MagicalSemicolon() { - var tt; - if (this.t.lineno === this.t.token.lineno) { - tt = this.peekOnSameLine(); - if (tt !== END && tt !== NEWLINE && tt !== SEMICOLON && tt !== RIGHT_CURLY) - this.fail("missing ; before statement"); - } - this.match(SEMICOLON); -} - -/* - * ReturnOrYield :: () -> (RETURN | YIELD) node - */ -Pp.ReturnOrYield = function ReturnOrYield() { - var n, b, tt = this.t.token.type, tt2; - - var parentScript = this.x.parentScript; - - if (tt === RETURN) { - if (!this.x.inFunction) - this.fail("Return not in function"); - } else /* if (tt === YIELD) */ { - if (!this.x.inFunction) - this.fail("Yield not in function"); - parentScript.hasYield = true; - } - n = this.newNode({ value: undefined }); - - tt2 = (tt === RETURN) ? this.peekOnSameLine(true) : this.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 = this.Expression(); - parentScript.hasReturnWithValue = true; - } else { - n.value = this.AssignExpression(); - } - } else if (tt === RETURN) { - parentScript.hasEmptyReturn = true; - } - - return n; -} - -/* - * ModuleExpression :: () -> (STRING | IDENTIFIER | DOT) node - */ -Pp.ModuleExpression = function ModuleExpression() { - return this.match(STRING) ? this.newNode() : this.QualifiedPath(); -} - -/* - * ImportPathList :: () -> Array[DOT node] - */ -Pp.ImportPathList = function ImportPathList() { - var a = []; - do { - a.push(this.ImportPath()); - } while (this.match(COMMA)); - return a; -} - -/* - * ImportPath :: () -> DOT node - */ -Pp.ImportPath = function ImportPath() { - var n = this.QualifiedPath(); - if (!this.match(DOT)) { - if (n.type === IDENTIFIER) - this.fail("cannot import local variable"); - return n; - } - - var n2 = this.newNode(); - n2.push(n); - n2.push(this.ImportSpecifierSet()); - return n2; -} - -/* - * ExplicitSpecifierSet :: (() -> node) -> OBJECT_INIT node - */ -Pp.ExplicitSpecifierSet = function ExplicitSpecifierSet(SpecifierRHS) { - var n, n2, id, tt; - - n = this.newNode({ type: OBJECT_INIT }); - this.mustMatch(LEFT_CURLY); - - if (!this.match(RIGHT_CURLY)) { - do { - id = this.Identifier(); - if (this.match(COLON)) { - n2 = this.newNode({ type: PROPERTY_INIT }); - n2.push(id); - n2.push(SpecifierRHS()); - n.push(n2); - } else { - n.push(id); - } - } while (!this.match(RIGHT_CURLY) && this.mustMatch(COMMA)); - } - - return n; -} - -/* - * ImportSpecifierSet :: () -> (IDENTIFIER | OBJECT_INIT) node - */ -Pp.ImportSpecifierSet = function ImportSpecifierSet() { - var self = this; - return this.match(MUL) - ? this.newNode({ type: IDENTIFIER, name: "*" }) - : ExplicitSpecifierSet(function() { return self.Identifier() }); -} - -/* - * Identifier :: () -> IDENTIFIER node - */ -Pp.Identifier = function Identifier() { - this.mustMatch(IDENTIFIER); - return this.newNode({ type: IDENTIFIER }); -} - -/* - * IdentifierName :: () -> IDENTIFIER node - */ -Pp.IdentifierName = function IdentifierName() { - this.mustMatch(IDENTIFIER, true); - return this.newNode({ type: IDENTIFIER }); -} - -/* - * QualifiedPath :: () -> (IDENTIFIER | DOT) node - */ -Pp.QualifiedPath = function QualifiedPath() { - var n, n2; - - n = this.Identifier(); - - while (this.match(DOT)) { - if (this.peek() !== IDENTIFIER) { - // Unget the '.' token, which isn't part of the QualifiedPath. - this.t.unget(); - break; - } - n2 = this.newNode(); - n2.push(n); - n2.push(this.Identifier()); - n = n2; - } - - return n; -} - -/* - * ExportPath :: () -> (IDENTIFIER | DOT | OBJECT_INIT) node - */ -Pp.ExportPath = function ExportPath() { - var self = this; - if (this.peek() === LEFT_CURLY) - return this.ExplicitSpecifierSet(function() { return self.QualifiedPath() }); - return this.QualifiedPath(); -} - -/* - * ExportPathList :: () -> Array[(IDENTIFIER | DOT | OBJECT_INIT) node] - */ -Pp.ExportPathList = function ExportPathList() { - var a = []; - do { - a.push(this.ExportPath()); - } while (this.match(COMMA)); - return a; -} - -/* - * FunctionDefinition :: (boolean, - * DECLARED_FORM or EXPRESSED_FORM or STATEMENT_FORM, - * [string] or null or undefined) - * -> node - */ -Pp.FunctionDefinition = function FunctionDefinition(requireName, functionForm, comments) { - var tt; - var f = this.newNode({ params: [], paramComments: [] }); - if (typeof comments === "undefined") - comments = null; - f.blockComments = comments; - if (f.type !== FUNCTION) - f.type = (f.value === "get") ? GETTER : SETTER; - if (this.match(MUL)) - f.isExplicitGenerator = true; - if (this.match(IDENTIFIER, false, true)) - f.name = this.t.token.value; - else if (requireName) - this.fail("missing function identifier"); - - var inModule = this.x.inModule; - x2 = new StaticContext(null, null, inModule, true, this.x.strictMode); - this.withContext(x2, function() { - this.mustMatch(LEFT_PAREN); - if (!this.match(RIGHT_PAREN)) { - do { - tt = this.t.get(); - f.paramComments.push(this.t.lastBlockComment()); - switch (tt) { - case LEFT_BRACKET: - case LEFT_CURLY: - // Destructured formal parameters. - this.t.unget(); - f.params.push(this.DestructuringExpression()); - break; - case IDENTIFIER: - f.params.push(this.t.token.value); - break; - default: - this.fail("missing formal parameter"); - } - } while (this.match(COMMA)); - this.mustMatch(RIGHT_PAREN); - } - - // Do we have an expression closure or a normal body? - tt = this.t.get(true); - if (tt !== LEFT_CURLY) - this.t.unget(); - - if (tt !== LEFT_CURLY) { - f.body = this.AssignExpression(); - } else { - f.body = this.Script(inModule, true); - } - }); - - if (tt === LEFT_CURLY) - this.mustMatch(RIGHT_CURLY); - - f.end = this.t.token.end; - f.functionForm = functionForm; - if (functionForm === DECLARED_FORM) - this.x.parentScript.funDecls.push(f); - - if (this.x.inModule && !f.isExplicitGenerator && f.body.hasYield) - this.fail("yield in non-generator function"); - - if (f.isExplicitGenerator || f.body.hasYield) - f.body = this.newNode({ type: GENERATOR, body: f.body }); - - return f; -} - -/* - * ModuleVariables :: (MODULE node) -> void - * - * Parses a comma-separated list of module declarations (and maybe - * initializations). - */ -Pp.ModuleVariables = function ModuleVariables(n) { - var n1, n2; - do { - n1 = this.Identifier(); - if (this.match(ASSIGN)) { - n2 = this.ModuleExpression(); - n1.initializer = n2; - if (n2.type === STRING) - this.x.parentScript.modLoads.set(n1.value, n2.value); - else - this.x.parentScript.modAssns.set(n1.value, n1); - } - n.push(n1); - } while (this.match(COMMA)); -} - -/* - * Variables :: () -> node - * - * Parses a comma-separated list of var declarations (and maybe - * initializations). - */ -Pp.Variables = function Variables(letBlock) { - var n, n2, ss, i, s, tt; - - tt = this.t.token.type; - switch (tt) { - case VAR: - case CONST: - s = this.x.parentScript; - break; - case LET: - s = this.x.parentBlock; - break; - case LEFT_PAREN: - tt = LET; - s = letBlock; - break; - } - - n = this.newNode({ type: tt, destructurings: [] }); - - do { - tt = this.t.get(); - if (tt === LEFT_BRACKET || tt === LEFT_CURLY) { - // Need to unget to parse the full destructured expression. - this.t.unget(); - - var dexp = this.DestructuringExpression(true); - - n2 = this.newNode({ type: IDENTIFIER, - name: dexp, - readOnly: n.type === CONST }); - n.push(n2); - pushDestructuringVarDecls(n2.name.destructuredNames, s); - n.destructurings.push({ exp: dexp, decl: n2 }); - - if (this.x.inForLoopInit && this.peek() === IN) { - continue; - } - - this.mustMatch(ASSIGN); - if (this.t.token.assignOp) - this.fail("Invalid variable initialization"); - - n2.blockComment = this.t.lastBlockComment(); - n2.initializer = this.AssignExpression(); - - continue; - } - - if (tt !== IDENTIFIER) - this.fail("missing variable name"); - - n2 = this.newNode({ type: IDENTIFIER, - name: this.t.token.value, - readOnly: n.type === CONST }); - n.push(n2); - s.varDecls.push(n2); - - if (this.match(ASSIGN)) { - var comment = this.t.lastBlockComment(); - if (this.t.token.assignOp) - this.fail("Invalid variable initialization"); - - n2.initializer = this.AssignExpression(); - } else { - var comment = this.t.lastBlockComment(); - } - n2.blockComment = comment; - } while (this.match(COMMA)); - - return n; -} - -/* - * LetBlock :: (boolean) -> node - * - * Does not handle let inside of for loop init. - */ -Pp.LetBlock = function LetBlock(isStatement) { - var n, n2; - - // t.token.type must be LET - n = this.newNode({ type: LET_BLOCK, varDecls: [] }); - this.mustMatch(LEFT_PAREN); - n.variables = this.Variables(n); - this.mustMatch(RIGHT_PAREN); - - if (isStatement && this.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 = this.newNode({ type: SEMICOLON, expression: n }); - isStatement = false; - } - - if (isStatement) - n.block = this.Block(); - else - n.expression = this.AssignExpression(); - - return n; -} - -Pp.checkDestructuring = function checkDestructuring(n, simpleNamesOnly) { - if (n.type === ARRAY_COMP) - this.fail("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] = this.checkDestructuring(sub, simpleNamesOnly); - } else { - if (simpleNamesOnly && sub.type !== IDENTIFIER) { - // In declarations, lhs must be simple names - this.fail("missing name in pattern"); - } - - lhss[idx] = sub; - } - } - - return lhss; -} - -Pp.DestructuringExpression = function DestructuringExpression(simpleNamesOnly) { - var n = this.PrimaryExpression(); - // Keep the list of lefthand sides for varDecls - n.destructuredNames = this.checkDestructuring(n, simpleNamesOnly); - return n; -} - -Pp.GeneratorExpression = function GeneratorExpression(e) { - return this.newNode({ type: GENERATOR, - expression: e, - tail: this.ComprehensionTail() }); -} - -Pp.ComprehensionTail = function ComprehensionTail() { - var body, n, n2, n3, p; - - // t.token.type must be FOR - body = this.newNode({ type: COMP_TAIL }); - - do { - // Comprehension tails are always for..in loops. - n = this.newNode({ type: FOR_IN, isLoop: true }); - if (this.match(IDENTIFIER)) { - // But sometimes they're for each..in. - if (this.mozillaMode && this.t.token.value === "each") - n.isEach = true; - else - this.t.unget(); - } - p = this.MaybeLeftParen(); - switch(this.t.get()) { - case LEFT_BRACKET: - case LEFT_CURLY: - this.t.unget(); - // Destructured left side of for in comprehension tails. - n.iterator = this.DestructuringExpression(); - break; - - case IDENTIFIER: - n.iterator = n3 = this.newNode({ type: IDENTIFIER }); - n3.name = n3.value; - n.varDecl = n2 = this.newNode({ type: VAR }); - n2.push(n3); - this.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: - this.fail("missing identifier"); - } - this.mustMatch(IN); - n.object = this.Expression(); - this.MaybeRightParen(p); - body.push(n); - } while (this.match(FOR)); - - // Optional guard. - if (this.match(IF)) - body.guard = this.HeadExpression(); - - return body; -} - -Pp.HeadExpression = function HeadExpression() { - var p = this.MaybeLeftParen(); - var n = this.ParenExpression(); - this.MaybeRightParen(p); - if (p === END && !n.parenthesized) { - var tt = this.peek(); - if (tt !== LEFT_CURLY && !definitions.isStatementStartCode[tt]) - this.fail("Unparenthesized head followed by unbraced body"); - } - return n; -} - -Pp.ParenExpression = function ParenExpression() { - // 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 x2 = this.x.update({ - inForLoopInit: this.x.inForLoopInit && (this.t.token.type === LEFT_PAREN) - }); - var n = this.withContext(x2, function() { - return this.Expression(); - }); - if (this.match(FOR)) { - if (n.type === YIELD && !n.parenthesized) - this.fail("Yield expression must be parenthesized"); - if (n.type === COMMA && !n.parenthesized) - this.fail("Generator expression must be parenthesized"); - n = this.GeneratorExpression(n); - } - - return n; -} - -/* - * Expression :: () -> node - * - * Top-down expression parser matched against SpiderMonkey. - */ -Pp.Expression = function Expression() { - var n, n2; - - n = this.AssignExpression(); - if (this.match(COMMA)) { - n2 = this.newNode({ type: COMMA }); - n2.push(n); - n = n2; - do { - n2 = n.children[n.children.length-1]; - if (n2.type === YIELD && !n2.parenthesized) - this.fail("Yield expression must be parenthesized"); - n.push(this.AssignExpression()); - } while (this.match(COMMA)); - } - - return n; -} - -Pp.AssignExpression = function AssignExpression() { - var n, lhs; - - // Have to treat yield like an operand because it could be the leftmost - // operand of the expression. - if (this.match(YIELD, true)) - return this.ReturnOrYield(); - - n = this.newNode({ type: ASSIGN }); - lhs = this.ConditionalExpression(); - - if (!this.match(ASSIGN)) { - return lhs; - } - - n.blockComment = this.t.lastBlockComment(); - - switch (lhs.type) { - case OBJECT_INIT: - case ARRAY_INIT: - lhs.destructuredNames = this.checkDestructuring(lhs); - // FALL THROUGH - case IDENTIFIER: case DOT: case INDEX: case CALL: - break; - default: - this.fail("Bad left-hand side of assignment"); - break; - } - - n.assignOp = lhs.assignOp = this.t.token.assignOp; - n.push(lhs); - n.push(this.AssignExpression()); - - return n; -} - -Pp.ConditionalExpression = function ConditionalExpression() { - var n, n2; - - n = this.OrExpression(); - if (this.match(HOOK)) { - n2 = n; - n = this.newNode({ type: HOOK }); - n.push(n2); - var x2 = this.x.update({ inForLoopInit: false }); - this.withContext(x2, function() { - n.push(this.AssignExpression()); - }); - if (!this.match(COLON)) - this.fail("missing : after ?"); - n.push(this.AssignExpression()); - } - - return n; -} - -Pp.OrExpression = function OrExpression() { - var n, n2; - - n = this.AndExpression(); - while (this.match(OR)) { - n2 = this.newNode(); - n2.push(n); - n2.push(this.AndExpression()); - n = n2; - } - - return n; -} - -Pp.AndExpression = function AndExpression() { - var n, n2; - - n = this.BitwiseOrExpression(); - while (this.match(AND)) { - n2 = this.newNode(); - n2.push(n); - n2.push(this.BitwiseOrExpression()); - n = n2; - } - - return n; -} - -Pp.BitwiseOrExpression = function BitwiseOrExpression() { - var n, n2; - - n = this.BitwiseXorExpression(); - while (this.match(BITWISE_OR)) { - n2 = this.newNode(); - n2.push(n); - n2.push(this.BitwiseXorExpression()); - n = n2; - } - - return n; -} - -Pp.BitwiseXorExpression = function BitwiseXorExpression() { - var n, n2; - - n = this.BitwiseAndExpression(); - while (this.match(BITWISE_XOR)) { - n2 = this.newNode(); - n2.push(n); - n2.push(this.BitwiseAndExpression()); - n = n2; - } - - return n; -} - -Pp.BitwiseAndExpression = function BitwiseAndExpression() { - var n, n2; - - n = this.EqualityExpression(); - while (this.match(BITWISE_AND)) { - n2 = this.newNode(); - n2.push(n); - n2.push(this.EqualityExpression()); - n = n2; - } - - return n; -} - -Pp.EqualityExpression = function EqualityExpression() { - var n, n2; - - n = this.RelationalExpression(); - while (this.match(EQ) || this.match(NE) || - this.match(STRICT_EQ) || this.match(STRICT_NE)) { - n2 = this.newNode(); - n2.push(n); - n2.push(this.RelationalExpression()); - n = n2; - } - - return n; -} - -Pp.RelationalExpression = function RelationalExpression() { - var n, n2; - var x2 = this.x.update({ inForLoopInit: false }); - this.withContext(x2, function() { - n = this.ShiftExpression(); - while ((this.match(LT) || this.match(LE) || this.match(GE) || this.match(GT) || - (!this.x.inForLoopInit && this.match(IN)) || - this.match(INSTANCEOF))) { - n2 = this.newNode(); - n2.push(n); - n2.push(this.ShiftExpression()); - n = n2; - } - }); - - return n; -} - -Pp.ShiftExpression = function ShiftExpression() { - var n, n2; - - n = this.AddExpression(); - while (this.match(LSH) || this.match(RSH) || this.match(URSH)) { - n2 = this.newNode(); - n2.push(n); - n2.push(this.AddExpression()); - n = n2; - } - - return n; -} - -Pp.AddExpression = function AddExpression() { - var n, n2; - - n = this.MultiplyExpression(); - while (this.match(PLUS) || this.match(MINUS)) { - n2 = this.newNode(); - n2.push(n); - n2.push(this.MultiplyExpression()); - n = n2; - } - - return n; -} - -Pp.MultiplyExpression = function MultiplyExpression() { - var n, n2; - - n = this.UnaryExpression(); - while (this.match(MUL) || this.match(DIV) || this.match(MOD)) { - n2 = this.newNode(); - n2.push(n); - n2.push(this.UnaryExpression()); - n = n2; - } - - return n; -} - -Pp.UnaryExpression = function UnaryExpression() { - var n, n2, tt; - - switch (tt = this.t.get(true)) { - case DELETE: case VOID: case TYPEOF: - case NOT: case BITWISE_NOT: case PLUS: case MINUS: - if (tt === PLUS) - n = this.newNode({ type: UNARY_PLUS }); - else if (tt === MINUS) - n = this.newNode({ type: UNARY_MINUS }); - else - n = this.newNode(); - n.push(this.UnaryExpression()); - break; - - case INCREMENT: - case DECREMENT: - // Prefix increment/decrement. - n = this.newNode(); - n.push(this.MemberExpression(true)); - break; - - default: - this.t.unget(); - n = this.MemberExpression(true); - - // Don't look across a newline boundary for a postfix {in,de}crement. - if (this.t.tokens[(this.t.tokenIndex + this.t.lookahead - 1) & 3].lineno === - this.t.lineno) { - if (this.match(INCREMENT) || this.match(DECREMENT)) { - n2 = this.newNode({ postfix: true }); - n2.push(n); - n = n2; - } - } - break; - } - - return n; -} - -Pp.MemberExpression = function MemberExpression(allowCallSyntax) { - var n, n2, name, tt; - - if (this.match(NEW)) { - n = this.newNode(); - n.push(this.MemberExpression(false)); - if (this.match(LEFT_PAREN)) { - n.type = NEW_WITH_ARGS; - n.push(this.ArgumentList()); - } - } else { - n = this.PrimaryExpression(); - } - - while ((tt = this.t.get()) !== END) { - switch (tt) { - case DOT: - n2 = this.newNode(); - n2.push(n); - n2.push(this.IdentifierName()); - break; - - case LEFT_BRACKET: - n2 = this.newNode({ type: INDEX }); - n2.push(n); - n2.push(this.Expression()); - this.mustMatch(RIGHT_BRACKET); - break; - - case LEFT_PAREN: - if (allowCallSyntax) { - n2 = this.newNode({ type: CALL }); - n2.push(n); - n2.push(this.ArgumentList()); - break; - } - - // FALL THROUGH - default: - this.t.unget(); - return n; - } - - n = n2; - } - - return n; -} - -Pp.ArgumentList = function ArgumentList() { - var n, n2; - - n = this.newNode({ type: LIST }); - if (this.match(RIGHT_PAREN, true)) - return n; - do { - n2 = this.AssignExpression(); - if (n2.type === YIELD && !n2.parenthesized && this.peek() === COMMA) - this.fail("Yield expression must be parenthesized"); - if (this.match(FOR)) { - n2 = this.GeneratorExpression(n2); - if (n.children.length > 1 || this.peek(true) === COMMA) - this.fail("Generator expression must be parenthesized"); - } - n.push(n2); - } while (this.match(COMMA)); - this.mustMatch(RIGHT_PAREN); - - return n; -} - -Pp.PrimaryExpression = function PrimaryExpression() { - var n, n2, tt = this.t.get(true); - - switch (tt) { - case FUNCTION: - n = this.FunctionDefinition(false, EXPRESSED_FORM); - break; - - case LEFT_BRACKET: - n = this.newNode({ type: ARRAY_INIT }); - while ((tt = this.peek(true)) !== RIGHT_BRACKET) { - if (tt === COMMA) { - this.t.get(); - n.push(null); - continue; - } - n.push(this.AssignExpression()); - if (tt !== COMMA && !this.match(COMMA)) - break; - } - - // If we matched exactly one element and got a FOR, we have an - // array comprehension. - if (n.children.length === 1 && this.match(FOR)) { - n2 = this.newNode({ type: ARRAY_COMP, - expression: n.children[0], - tail: this.ComprehensionTail() }); - n = n2; - } - this.mustMatch(RIGHT_BRACKET); - break; - - case LEFT_CURLY: - var id, fd; - n = this.newNode({ type: OBJECT_INIT }); - - object_init: - if (!this.match(RIGHT_CURLY)) { - do { - tt = this.t.get(); - if ((this.t.token.value === "get" || this.t.token.value === "set") && - this.peek() === IDENTIFIER) { - n.push(this.FunctionDefinition(true, EXPRESSED_FORM)); - } else { - var comments = this.t.blockComments; - switch (tt) { - case IDENTIFIER: case NUMBER: case STRING: - id = this.newNode({ type: IDENTIFIER }); - break; - case RIGHT_CURLY: - break object_init; - default: - if (this.t.token.value in definitions.keywords) { - id = this.newNode({ type: IDENTIFIER }); - break; - } - this.fail("Invalid property name"); - } - if (this.match(COLON)) { - n2 = this.newNode({ type: PROPERTY_INIT }); - n2.push(id); - n2.push(this.AssignExpression()); - 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 (this.peek() !== COMMA && this.peek() !== RIGHT_CURLY) - this.fail("missing : after property"); - n.push(id); - } - } - } while (this.match(COMMA)); - this.mustMatch(RIGHT_CURLY); - } - break; - - case LEFT_PAREN: - n = this.ParenExpression(); - this.mustMatch(RIGHT_PAREN); - n.parenthesized = true; - break; - - case LET: - n = this.LetBlock(false); - break; - - case NULL: case THIS: case TRUE: case FALSE: - case IDENTIFIER: case NUMBER: case STRING: case REGEXP: - n = this.newNode(); - break; - - default: - this.fail("missing operand; found " + definitions.tokens[tt]); - break; - } - - return n; -} - -/* - * parse :: (source, filename, line number) -> node - */ -function parse(s, f, l) { - var t = new Tokenizer(s, f, l, options.allowHTMLComments); - var p = new Parser(t); - return p.Script(false, false, true); -} - -/* - * parseFunction :: (source, boolean, - * DECLARED_FORM or EXPRESSED_FORM or STATEMENT_FORM, - * filename, line number) - * -> node - */ -function parseFunction(s, requireName, form, f, l) { - var t = new Tokenizer(s, f, l); - var p = new Parser(t); - p.x = new StaticContext(null, null, false, false, false); - return p.FunctionDefinition(requireName, form); -} - -/* - * 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 Tokenizer(s, "stdin", ln.value, false); - var p = new Parser(t); - var n = p.Script(false, false); - ln.value = t.lineno; - return n; - } catch (e) { - if (!p.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 Tokenizer(s, "stdin", ln.value, false); - var p = new Parser(t); - var n = p.Script(false, false); - ln.value = t.lineno; - return n; -} - -exports.parse = parse; -exports.parseStdin = parseStdin; -exports.parseFunction = parseFunction; -exports.Node = Node; -exports.DECLARED_FORM = DECLARED_FORM; -exports.EXPRESSED_FORM = EXPRESSED_FORM; -exports.STATEMENT_FORM = STATEMENT_FORM; -exports.Tokenizer = Tokenizer; -exports.Parser = Parser; -exports.Module = Module; -exports.Export = Export; - -}); - -/* - * Narcissus - JS implemented in JS. - * - * Lexical scanner. - */ - - define('ace/narcissus/lexer', ['require', 'exports', 'module' , 'ace/narcissus/definitions'], function(require, exports, module) { - -var definitions = require('./definitions'); - -// Set constants in the local scope. -eval(definitions.consts); - -// 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; - } -} - -/* - * 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!) - */ -function isValidIdentifierChar(ch, first) { - // check directly for ASCII - if (ch <= "\u007F") { - if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch === '$' || ch === '_' || - (!first && (ch >= '0' && ch <= '9'))) { - return true; - } - return false; - } - - // 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) {} - - return valid; -} - -function isIdentifier(str) { - if (typeof str !== "string") - return false; - - if (str.length === 0) - return false; - - if (!isValidIdentifierChar(str[0], true)) - return false; - - for (var i = 1; i < str.length; i++) { - if (!isValidIdentifierChar(str[i], false)) - return false; - } - - return true; -} - -/* - * Tokenizer :: (source, filename, line number, boolean) -> Tokenizer - */ -function Tokenizer(s, f, l, allowHTMLComments) { - this.cursor = 0; - this.source = String(s); - this.tokens = []; - this.tokenIndex = 0; - this.lookahead = 0; - this.scanNewlines = false; - this.filename = f || ""; - this.lineno = l || 1; - this.allowHTMLComments = allowHTMLComments; - 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, keywordIsName) { - return this.get(scanOperand, keywordIsName) === tt || this.unget(); - }, - - mustMatch: function (tt, keywordIsName) { - if (!this.match(tt, false, keywordIsName)) { - 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.allowHTMLComments && ch === '<' && next === '!' && - input[this.cursor + 1] === '-' && input[this.cursor + 2] === '-' && - (this.cursor += 2))) { - 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( - input.substring(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( - input.substring(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 (ch == '\n' || ch == '\r') - throw this.newSyntaxError("Unterminated string literal"); - 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, keywordIsName) { - var token = this.token; - var id = ch; - - while ((ch = this.getValidIdentifierChar(false)) !== null) { - id += ch; - } - - token.type = IDENTIFIER; - token.value = id; - - if (keywordIsName) - return; - - var kw; - - if (this.parser.mozillaMode) { - kw = definitions.mozillaKeywords[id]; - if (kw) { - token.type = kw; - return; - } - } - - if (this.parser.x.strictMode) { - kw = definitions.strictKeywords[id]; - if (kw) { - token.type = kw; - return; - } - } - - kw = definitions.keywords[id]; - if (kw) - token.type = kw; - }, - - /* - * Tokenizer.get :: ([boolean[, boolean]]) -> token type - * - * Consume input *only* if there is no lookahead. - * Dispatch to the appropriate lexing function depending on the input. - */ - get: function (scanOperand, keywordIsName) { - 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, keywordIsName); - } 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. - */ - 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; - } - - var valid = isValidIdentifierChar(ch, first); - if (valid) this.cursor++; - return (valid ? ch : null); - }, -}; - - -exports.isIdentifier = isIdentifier; -exports.Tokenizer = Tokenizer; - -}); - -/* - * 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/definitions', ['require', 'exports', 'module' ], function(require, exports, module) { - -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", - - // Contextual keywords. - "IMPLEMENTS", "INTERFACE", "LET", "MODULE", "PACKAGE", "PRIVATE", - "PROTECTED", "PUBLIC", "STATIC", "USE", "YIELD", - - // 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", - "new", "null", - "return", - "switch", - "this", "throw", "true", "try", "typeof", - "var", "void", - "while", "with", -]; - -var strictKeywords = { - __proto__: null, - "implements": true, - "interface": true, - "let": true, - //"module": true, - "package": true, - "private": true, - "protected": true, - "public": true, - "static": true, - "use": true, - "yield": true -}; - -var statementStartTokens = [ - "break", - "const", "continue", - "debugger", "do", - "for", - "if", - "let", - "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}; -var mozillaKeywords = {__proto__: null}; - -// Define const END, etc., based on the token names. Also map name to index. -var tokenIds = {}; - -var hostSupportsEvalConst = (function() { - try { - return eval("(function(s) { eval(s); return x })('const x = true;')"); - } catch (e) { - return false; - } -})(); - -// Building up a string to be eval'd in different contexts. -var consts = 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(); - if (name === "LET" || name === "YIELD") - mozillaKeywords[name] = i; - if (strictKeywords[name]) - strictKeywords[name] = i; - 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\]/); -} - -var Fpapply = Function.prototype.apply; - -function apply(f, o, a) { - return Fpapply.call(f, [o].concat(a)); -} - -var applyNew; - -// ES5's bind is a simpler way to implement applyNew -if (Function.prototype.bind) { - applyNew = function applyNew(f, a) { - return new (f.bind.apply(f, [,].concat(Array.prototype.slice.call(a))))(); - }; -} else { - applyNew = function applyNew(f, a) { - switch (a.length) { - case 0: - return new f(); - case 1: - return new f(a[0]); - case 2: - return new f(a[0], a[1]); - case 3: - return new f(a[0], a[1], a[2]); - default: - var argStr = "a[0]"; - for (var i = 1, n = a.length; i < n; i++) - argStr += ",a[" + i + "]"; - return eval("new f(" + argStr + ")"); - } - }; -} - -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 = Dict.create(blacklist).mapObject(function(name) { return mask; }); - return mixinHandler(redirect, target); -} - -function whitelistHandler(target, whitelist) { - var catchall = Object.create(null, {}); - var redirect = Dict.create(whitelist).mapObject(function(name) { return target; }); - return mixinHandler(redirect, catchall); -} - -/* - * 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 Dict(table, size) { - this.table = table || Object.create(null, {}); - this.size = size || 0; -} - -Dict.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 Dict(init, size); -}; - -Dict.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 Dict(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 Dict(table, this.size); - }, - keys: function() { - return Object.keys(this.table); - }, - toString: function() { return "[object Dict]" } -}; - -var _WeakMap = typeof WeakMap === "function" ? WeakMap : (function() { - // shim for ES6 WeakMap with poor asymptotics - function WeakMap(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(); - } - - WeakMap.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 }); - }, - "delete": function(x) { - var a = this.array; - searchMap(this, x, - function(pair, i) { a.splice(i, 1) }, - function() { }); - }, - toString: function() { return "[object WeakMap]" } - }; - - return WeakMap; -})(); - -// 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); - } - } -}; - -if (!Array.prototype.copy) { - defineProperty(Array.prototype, "copy", - function() { - var result = []; - for (var i = 0, n = this.length; i < n; i++) - result[i] = this[i]; - return result; - }, false, false, true); -} - -if (!Array.prototype.top) { - defineProperty(Array.prototype, "top", - function() { - return this.length && this[this.length-1]; - }, false, false, true); -} - -exports.tokens = tokens; -exports.whitespace = whitespace; -exports.opTypeNames = opTypeNames; -exports.keywords = keywords; -exports.mozillaKeywords = mozillaKeywords; -exports.strictKeywords = strictKeywords; -exports.isStatementStartCode = isStatementStartCode; -exports.tokenIds = tokenIds; -exports.consts = consts; -exports.assignOps = assignOps; -exports.defineGetter = defineGetter; -exports.defineGetterSetter = defineGetterSetter; -exports.defineMemoGetter = defineMemoGetter; -exports.defineProperty = defineProperty; -exports.isNativeCode = isNativeCode; -exports.apply = apply; -exports.applyNew = applyNew; -exports.mixinHandler = mixinHandler; -exports.whitelistHandler = whitelistHandler; -exports.blacklistHandler = blacklistHandler; -exports.makePassthruHandler = makePassthruHandler; -exports.Dict = Dict; -exports.WeakMap = _WeakMap; -exports.Stack = Stack; - -}); - -define('ace/narcissus/options', ['require', 'exports', 'module' ], function(require, exports, module) { - -// Global variables to hide from the interpreter -exports.hiddenHostGlobals = { Narcissus: true }; - -// Desugar SpiderMonkey language extensions? -exports.desugarExtensions = false; - -// Allow HTML comments? -exports.allowHTMLComments = false; - -// Allow non-standard Mozilla extensions? -exports.mozillaMode = true; - -// Allow experimental paren-free mode? -exports.parenFreeMode = false; - -}); |