var console = { log: function(msg) { postMessage({type: "log", data: msg}); } }; 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) { var id = normalizeModule(parentId, id); var module = require.modules[id]; if (module) { if (!module.initialized) { module.exports = module.factory().exports; module.initialized = true; } return module.exports; } var chunks = id.split("/"); chunks[0] = require.tlns[chunks[0]] || chunks[0]; 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; } 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._dispatchEvent(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) { // Based on code from: // // XRegExp 1.5.0 // (c) 2007-2010 Steven Levithan // MIT License // // Provides an augmented, extensible, cross-browser implementation of regular expressions, // including support for additional syntax, flags, and methods //--------------------------------- // 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; }(); //--------------------------------- // 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 (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 // 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); }; });/* vim:ts=4:sts=4:sw=4: * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Ajax.org Code Editor (ACE). * * The Initial Developer of the Original Code is * Ajax.org B.V. * Portions created by the Initial Developer are Copyright (C) 2010 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Fabian Jakobs * Irakli Gozalishvili (http://jeditoolkit.com) * Mike de Boer * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ define('ace/lib/event_emitter', ['require', 'exports', 'module' ], function(require, exports, module) { 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; e = e || {}; 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 * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ define('ace/lib/oop', ['require', 'exports', 'module' ], function(require, exports, module) { 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); }; }); /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Ajax.org Code Editor (ACE). * * The Initial Developer of the Original Code is * Ajax.org B.V. * Portions created by the Initial Developer are Copyright (C) 2010 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Fabian Jakobs * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ define('ace/mode/javascript_worker', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/worker/mirror', 'ace/worker/jshint', 'ace/narcissus/jsparse'], function(require, exports, module) { var oop = require("../lib/oop"); var Mirror = require("../worker/mirror").Mirror; var lint = require("../worker/jshint").JSHINT; 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(); var parser = require("../narcissus/jsparse"); try { parser.parse(value); } catch(e) { // console.log("narcissus") // console.log(e); var chunks = e.message.split(":") var message = chunks.pop().trim(); var lineNumber = parseInt(chunks.pop().trim()) - 1; this.sender.emit("narcissus", { row: lineNumber, column: null, // TODO convert e.cursor text: message, type: "error" }); 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); });/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Ajax.org Code Editor (ACE). * * The Initial Developer of the Original Code is * Ajax.org B.V. * Portions created by the Initial Developer are Copyright (C) 2010 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Fabian Jakobs * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ define('ace/document', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/event_emitter', 'ace/range', 'ace/anchor'], function(require, exports, module) { var oop = require("./lib/oop"); var EventEmitter = require("./lib/event_emitter").EventEmitter; var Range = require("./range").Range; var Anchor = require("./anchor").Anchor; var Document = function(text) { this.$lines = []; if (Array.isArray(text)) { this.insertLines(0, text); } // There has to be one line at least in the document. If you pass an empty // string to the insert function, nothing will happen. Workaround. else if (text.length == 0) { this.$lines = [""]; } 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"); }; /** * Get a verbatim copy of the given line as it is in the document */ this.getLine = function(row) { return this.$lines[row] || ""; }; this.getLines = function(firstRow, lastRow) { return this.$lines.slice(firstRow, lastRow + 1); }; /** * Returns all lines in the document as string array. Warning: The caller * should not modify this array! */ this.getAllLines = function() { return this.getLines(0, this.getLength()); }; this.getLength = function() { return this.$lines.length; }; this.getTextRange = function(range) { if (range.start.row == range.end.row) { return this.$lines[range.start.row].substring(range.start.column, range.end.column); } else { var lines = []; lines.push(this.$lines[range.start.row].substring(range.start.column)); lines.push.apply(lines, this.getLines(range.start.row+1, range.end.row-1)); lines.push(this.$lines[range.end.row].substring(0, range.end.column)); 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.length == 0) return position; position = this.$clipPosition(position); 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; }; this.insertLines = function(row, lines) { if (lines.length == 0) return {row: row, column: 0}; 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._dispatchEvent("change", { data: delta }); return 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._dispatchEvent("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._dispatchEvent("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._dispatchEvent("change", { data: delta }); return range.start; }; /** * Removes a range of full lines * * @param firstRow {Integer} The first row to be removed * @param lastRow {Integer} The last row to be removed * @return {String[]} The removed lines */ this.removeLines = function(firstRow, lastRow) { var range = new Range(firstRow, 0, lastRow + 1, 0); var removed = this.$lines.splice(firstRow, lastRow - firstRow + 1); var delta = { action: "removeLines", range: range, nl: this.getNewLineCharacter(), lines: removed }; this._dispatchEvent("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._dispatchEvent("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=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; }); /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Ajax.org Code Editor (ACE). * * The Initial Developer of the Original Code is * Ajax.org B.V. * Portions created by the Initial Developer are Copyright (C) 2010 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Fabian Jakobs * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ define('ace/range', ['require', 'exports', 'module' ], function(require, exports, module) { var Range = function(startRow, startColumn, endRow, endColumn) { this.start = { row: startRow, column: startColumn }; this.end = { row: endRow, column: endColumn }; }; (function() { this.isEequal = function(range) { return this.start.row == range.start.row && this.end.row == range.end.row && this.start.column == range.start.column && this.end.column == range.end.column }; this.toString = function() { return ("Range: [" + this.start.row + "/" + this.start.column + "] -> [" + this.end.row + "/" + this.end.column + "]"); }; this.contains = function(row, column) { return this.compare(row, column) == 0; }; /** * Compares this range (A) with another range (B), where B is the passed in * range. * * Return values: * -2: (B) is infront of (A) and doesn't intersect with (A) * -1: (B) begins before (A) but ends inside of (A) * 0: (B) is completly inside of (A) OR (A) is complety inside of (B) * +1: (B) begins inside of (A) but ends outside of (A) * +2: (B) is after (A) and doesn't intersect with (A) * * 42: FTW state: (B) ends in (A) but starts outside of (A) */ this.compareRange = function(range) { var cmp, end = range.end, 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; } } } this.comparePoint = function(p) { return this.compare(p.row, p.column); } this.containsRange = function(range) { return this.comparePoint(range.start) == 0 && this.comparePoint(range.end) == 0; } this.isEnd = function(row, column) { return this.end.row == row && this.end.column == column; } this.isStart = function(row, column) { return this.start.row == row && this.start.column == column; } this.setStart = function(row, column) { if (typeof row == "object") { this.start.column = row.column; this.start.row = row.row; } else { this.start.row = row; this.start.column = column; } } 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; } } 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; } this.insideStart = function(row, column) { if (this.compare(row, column) == 0) { if (this.isEnd(row, column)) { return false; } else { return true; } } return false; } this.insideEnd = function(row, column) { if (this.compare(row, column) == 0) { if (this.isStart(row, column)) { return false; } else { return true; } } return false; } 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; }; /** * Like .compare(), but if isStart is true, return -1; */ this.compareStart = function(row, column) { if (this.start.row == row && this.start.column == column) { return -1; } else { return this.compare(row, column); } } /** * Like .compare(), but if isEnd is true, return 1; */ this.compareEnd = function(row, column) { if (this.end.row == row && this.end.column == column) { return 1; } else { return this.compare(row, column); } } this.compareInside = function(row, column) { if (this.end.row == row && this.end.column == column) { return 1; } else if (this.start.row == row && this.start.column == column) { return -1; } else { return this.compare(row, column); } } 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; }); /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Ajax.org Code Editor (ACE). * * The Initial Developer of the Original Code is * Ajax.org B.V. * Portions created by the Initial Developer are Copyright (C) 2010 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Fabian Jakobs * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ define('ace/anchor', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/event_emitter'], function(require, exports, module) { var oop = require("./lib/oop"); var EventEmitter = require("./lib/event_emitter").EventEmitter; /** * An Anchor is a floating pointer in the document. Whenever text is inserted or * deleted before the cursor, the position of the cursor is updated */ var Anchor = exports.Anchor = function(doc, row, column) { this.document = doc; 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._dispatchEvent("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); }); /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Ajax.org Code Editor (ACE). * * The Initial Developer of the Original Code is * Ajax.org B.V. * Portions created by the Initial Developer are Copyright (C) 2010 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Fabian Jakobs * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ define('ace/lib/lang', ['require', 'exports', 'module' ], function(require, exports, module) { 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. var myReport = JSHINT.report(limited); If limited is true, then the report will be limited to only errors. You can request a data structure which contains JSHint's results. var myData = JSHINT.data(); It returns a structure with this form: { errors: [ { line: NUMBER, character: NUMBER, reason: STRING, evidence: STRING } ], functions: [ name: STRING, line: NUMBER, last: NUMBER, param: [ STRING ], closure: [ STRING ], var: [ STRING ], exception: [ STRING ], outer: [ STRING ], unused: [ STRING ], global: [ STRING ], label: [ STRING ] ], globals: [ STRING ], member: { STRING: NUMBER }, unuseds: [ { name: STRING, line: NUMBER } ], implieds: [ { name: STRING, line: NUMBER } ], urls: [ STRING ], json: BOOLEAN } Empty arrays will not be included. */ /*jshint evil: true, nomen: false, onevar: false, regexp: false, strict: true, boss: true, undef: true, maxlen: 100 */ /*members "\b", "\t", "\n", "\f", "\r", "!=", "!==", "\"", "%", "(begin)", "(breakage)", "(context)", "(error)", "(global)", "(identifier)", "(last)", "(line)", "(loopage)", "(name)", "(onevar)", "(params)", "(scope)", "(statement)", "(verb)", "*", "+", "++", "-", "--", "\/", "<", "<=", "==", "===", ">", ">=", $, $$, $A, $F, $H, $R, $break, $continue, $w, Abstract, Ajax, __filename, __dirname, ActiveXObject, Array, ArrayBuffer, ArrayBufferView, Autocompleter, Assets, Boolean, Builder, Buffer, Browser, COM, CScript, Canvas, CustomAnimation, Class, Control, Chain, Color, Cookie, Core, DataView, Date, Debug, Draggable, Draggables, Droppables, Document, DomReady, DOMReady, Drag, E, Enumerator, Enumerable, Element, Elements, Error, Effect, EvalError, Event, Events, FadeAnimation, Field, Flash, Float32Array, Float64Array, Form, FormField, Frame, Function, Fx, GetObject, Group, Hash, HotKey, HTMLElement, HtmlTable, Iframe, IframeShim, Image, Int16Array, Int32Array, Int8Array, Insertion, InputValidator, JSON, Keyboard, Locale, LN10, LN2, LOG10E, LOG2E, MAX_VALUE, MIN_VALUE, Mask, Math, MenuItem, MoveAnimation, MooTools, Native, NEGATIVE_INFINITY, Number, Object, ObjectRange, Option, Options, OverText, PI, POSITIVE_INFINITY, PeriodicalExecuter, Point, Position, Prototype, RangeError, Rectangle, ReferenceError, RegExp, ResizeAnimation, Request, RotateAnimation, SQRT1_2, SQRT2, ScrollBar, ScriptEngine, ScriptEngineBuildVersion, ScriptEngineMajorVersion, ScriptEngineMinorVersion, Scriptaculous, Scroller, Slick, Slider, Selector, String, Style, SyntaxError, Sortable, Sortables, SortableObserver, Sound, Spinner, System, Swiff, Text, TextArea, Template, Timer, Tips, Type, TypeError, Toggle, Try, URI, URIError, URL, VBArray, WSH, WScript, Web, Window, XMLDOM, XMLHttpRequest, XPathEvaluator, XPathException, XPathExpression, XPathNamespace, XPathNSResolver, XPathResult, "\\", a, addEventListener, address, alert, apply, applicationCache, arguments, arity, asi, b, bitwise, block, blur, boolOptions, boss, browser, c, call, callee, caller, cases, charAt, charCodeAt, character, clearInterval, clearTimeout, close, closed, closure, comment, condition, confirm, console, constructor, content, couch, create, css, curly, d, data, datalist, dd, debug, decodeURI, decodeURIComponent, defaultStatus, defineClass, deserialize, devel, document, dojo, dijit, dojox, define, edition, else, emit, encodeURI, encodeURIComponent, entityify, eqeqeq, eqnull, errors, es5, escape, eval, event, evidence, evil, ex, exception, exec, exps, expr, exports, FileReader, first, floor, focus, forin, fragment, frames, from, fromCharCode, fud, funct, function, functions, g, gc, getComputedStyle, getRow, GLOBAL, global, globals, globalstrict, hasOwnProperty, help, history, i, id, identifier, immed, implieds, include, indent, indexOf, init, ins, instanceOf, isAlpha, isApplicationRunning, isArray, isDigit, isFinite, isNaN, iterator, join, jshint, JSHINT, json, jquery, jQuery, keys, label, labelled, last, lastsemic, laxbreak, latedef, lbp, led, left, length, line, load, loadClass, localStorage, location, log, loopfunc, m, match, maxerr, maxlen, member,message, meta, module, moveBy, moveTo, mootools, name, navigator, new, newcap, noarg, node, noempty, nomen, nonew, nud, onbeforeunload, onblur, onerror, onevar, onfocus, onload, onresize, onunload, open, openDatabase, openURL, opener, opera, outer, param, parent, parseFloat, parseInt, passfail, plusplus, predef, print, process, prompt, proto, prototype, prototypejs, push, quit, range, raw, reach, reason, regexp, readFile, readUrl, regexdash, removeEventListener, replace, report, require, reserved, resizeBy, resizeTo, resolvePath, resumeUpdates, respond, rhino, right, runCommand, scroll, screen, scripturl, scrollBy, scrollTo, scrollbar, search, seal, send, serialize, setInterval, setTimeout, shift, slice, sort,spawn, split, stack, status, start, strict, sub, substr, supernew, shadow, supplant, sum, sync, test, toLowerCase, toString, toUpperCase, toint32, token, top, trailing, type, typeOf, Uint16Array, Uint32Array, Uint8Array, undef, unused, urls, value, valueOf, var, version, WebSocket, white, window, Worker, wsh*/ /*global exports: false */ // We build the application inside a function so that we produce only a single // global variable. That function will be invoked immediately, and its return // value is the JSHINT function itself. var JSHINT = (function () { "use strict"; var anonname, // The guessed name for anonymous functions. // These are operators that should not be used with the ! operator. bang = { '<' : true, '<=' : true, '==' : true, '===': true, '!==': true, '!=' : true, '>' : true, '>=' : true, '+' : true, '-' : true, '*' : true, '/' : true, '%' : true }, // These are the JSHint boolean options. boolOptions = { asi : true, // if automatic semicolon insertion should be tolerated bitwise : true, // if bitwise operators should not be allowed boss : true, // if advanced usage of assignments should be allowed browser : true, // if the standard browser globals should be predefined couch : true, // if CouchDB globals should be predefined curly : true, // if curly braces around all blocks should be required debug : true, // if debugger statements should be allowed devel : true, // if logging globals should be predefined (console, alert, etc.) dojo : true, // if Dojo Toolkit globals should be predefined eqeqeq : true, // if === should be required eqnull : true, // if == null comparisons should be tolerated es5 : true, // if ES5 syntax should be allowed evil : true, // if eval should be allowed expr : true, // if ExpressionStatement should be allowed as Programs forin : true, // if for in statements must filter globalstrict: true, // if global "use strict"; should be allowed (also enables 'strict') immed : true, // if immediate invocations must be wrapped in parens iterator : true, // if the `__iterator__` property should be disallowed jquery : true, // if jQuery globals should be predefined latedef : true, // if the use before definition should not be tolerated laxbreak : true, // if line breaks should not be checked loopfunc : true, // if functions should be allowed to be defined within loops mootools : true, // if MooTools globals should be predefined newcap : true, // if constructor names must be capitalized noarg : true, // if arguments.caller and arguments.callee should be disallowed node : true, // if the Node.js environment globals should be predefined noempty : true, // if empty blocks should be disallowed nonew : true, // if using `new` for side-effects should be disallowed nomen : true, // if names should be checked onevar : true, // if only one var statement per function should be allowed passfail : true, // if the scan should stop on first error plusplus : true, // if increment/decrement should not be allowed proto : true, // if the `__proto__` property should be disallowed prototypejs : true, // if Prototype and Scriptaculous globals should be predefined regexdash : true, // if unescaped last dash (-) inside brackets should be tolerated regexp : true, // if the . should not be allowed in regexp literals rhino : true, // if the Rhino environment globals should be predefined undef : true, // if variables should be declared before used scripturl : true, // if script-targeted URLs should be tolerated shadow : true, // if variable shadowing should be tolerated strict : true, // require the "use strict"; pragma sub : true, // if all forms of subscript notation are tolerated supernew : true, // if `new function () { ... };` and `new Object;` // should be tolerated trailing : true, // if trailing whitespace rules apply white : true, // if strict whitespace rules apply wsh : true // if the Windows Scripting Host environment globals should // be predefined }, // browser contains a set of global names which are commonly provided by a // web browser environment. browser = { ArrayBuffer : false, ArrayBufferView : false, addEventListener: false, applicationCache: false, blur : false, clearInterval : false, clearTimeout : false, close : false, closed : false, DataView : false, defaultStatus : false, document : false, event : false, FileReader : false, Float32Array : false, Float64Array : false, focus : false, frames : false, getComputedStyle: false, HTMLElement : false, history : false, Int16Array : false, Int32Array : false, Int8Array : false, Image : false, length : false, localStorage : false, location : false, moveBy : false, moveTo : false, name : false, navigator : false, onbeforeunload : true, onblur : true, onerror : true, onfocus : true, onload : true, onresize : true, onunload : true, open : false, openDatabase : false, opener : false, Option : false, parent : false, print : false, removeEventListener: false, resizeBy : false, resizeTo : false, screen : false, scroll : false, scrollBy : false, scrollTo : false, setInterval : false, setTimeout : false, status : false, top : false, Uint16Array : false, Uint32Array : false, Uint8Array : false, WebSocket : false, window : false, Worker : false, XMLHttpRequest : false, XPathEvaluator : false, XPathException : false, XPathExpression : false, XPathNamespace : false, XPathNSResolver : false, XPathResult : false }, couch = { "require" : false, respond : false, getRow : false, emit : false, send : false, start : false, sum : false, log : false, exports : false, module : false }, devel = { alert : false, confirm : false, console : false, Debug : false, opera : false, prompt : false }, dojo = { dojo : false, dijit : false, dojox : false, define : false, "require" : false }, escapes = { '\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '/' : '\\/', '\\': '\\\\' }, funct, // The current function functionicity = [ 'closure', 'exception', 'global', 'label', 'outer', 'unused', 'var' ], functions, // All of the functions global, // The global scope implied, // Implied globals inblock, indent, jsonmode, jquery = { '$' : false, jQuery : false }, lines, lookahead, member, membersOnly, mootools = { '$' : false, '$$' : false, Assets : false, Browser : false, Chain : false, Class : false, Color : false, Cookie : false, Core : false, Document : false, DomReady : false, DOMReady : false, Drag : false, Element : false, Elements : false, Event : false, Events : false, Fx : false, Group : false, Hash : false, HtmlTable : false, Iframe : false, IframeShim : false, InputValidator : false, instanceOf : false, Keyboard : false, Locale : false, Mask : false, MooTools : false, Native : false, Options : false, OverText : false, Request : false, Scroller : false, Slick : false, Slider : false, Sortables : false, Spinner : false, Swiff : false, Tips : false, Type : false, typeOf : false, URI : false, Window : false }, nexttoken, node = { __filename : false, __dirname : false, exports : false, Buffer : false, GLOBAL : false, global : false, module : false, process : false, require : false }, noreach, option, predefined, // Global variables defined by option prereg, prevtoken, prototypejs = { '$' : false, '$$' : false, '$A' : false, '$F' : false, '$H' : false, '$R' : false, '$break' : false, '$continue' : false, '$w' : false, Abstract : false, Ajax : false, Class : false, Enumerable : false, Element : false, Event : false, Field : false, Form : false, Hash : false, Insertion : false, ObjectRange : false, PeriodicalExecuter: false, Position : false, Prototype : false, Selector : false, Template : false, Toggle : false, Try : false, Autocompleter : false, Builder : false, Control : false, Draggable : false, Draggables : false, Droppables : false, Effect : false, Sortable : false, SortableObserver : false, Sound : false, Scriptaculous : false }, rhino = { defineClass : false, deserialize : false, gc : false, help : false, load : false, loadClass : false, print : false, quit : false, readFile : false, readUrl : false, runCommand : false, seal : false, serialize : false, spawn : false, sync : false, toint32 : false, version : false }, scope, // The current scope src, stack, // standard contains the global names that are provided by the // ECMAScript standard. standard = { Array : false, Boolean : false, Date : false, decodeURI : false, decodeURIComponent : false, encodeURI : false, encodeURIComponent : false, Error : false, 'eval' : false, EvalError : false, Function : false, hasOwnProperty : false, isFinite : false, isNaN : false, JSON : false, Math : false, Number : false, Object : false, parseInt : false, parseFloat : false, RangeError : false, ReferenceError : false, RegExp : false, String : false, SyntaxError : false, TypeError : false, URIError : false }, standard_member = { E : true, LN2 : true, LN10 : true, LOG2E : true, LOG10E : true, MAX_VALUE : true, MIN_VALUE : true, NEGATIVE_INFINITY : true, PI : true, POSITIVE_INFINITY : true, SQRT1_2 : true, SQRT2 : true }, strict_mode, syntax = {}, tab, token, urls, warnings, wsh = { ActiveXObject : true, Enumerator : true, GetObject : true, ScriptEngine : true, ScriptEngineBuildVersion : true, ScriptEngineMajorVersion : true, ScriptEngineMinorVersion : true, VBArray : true, WSH : true, WScript : true }; // Regular expressions. Some of these are stupidly long. var ax, cx, tx, nx, nxg, lx, ix, jx, ft; (function () { /*jshint maxlen:300 */ // unsafe comment or string ax = /@cc|<\/?|script|\]\s*\]|<\s*!|</i; // unsafe characters that are silently deleted by one or more browsers cx = /[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/; // token tx = /^\s*([(){}\[.,:;'"~\?\]#@]|==?=?|\/(\*(jshint|jslint|members?|global)?|=|\/)?|\*[\/=]?|\+(?:=|\++)?|-(?:=|-+)?|%=?|&[&=]?|\|[|=]?|>>?>?=?|<([\/=!]|\!(\[|--)?|<=?)?|\^=?|\!=?=?|[a-zA-Z_$][a-zA-Z0-9_$]*|[0-9]+([xX][0-9a-fA-F]+|\.[0-9]*)?([eE][+\-]?[0-9]+)?)/; // characters in strings that need escapement nx = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/; nxg = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; // star slash lx = /\*\/|\/\*/; // identifier ix = /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/; // javascript url jx = /^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i; // catches /* falls through */ comments ft = /^\s*\/\*\s*falls\sthrough\s*\*\/\s*$/; }()); function F() {} // Used by Object.create function is_own(object, name) { // The object.hasOwnProperty method fails when the property under consideration // is named 'hasOwnProperty'. So we have to use this more convoluted form. return Object.prototype.hasOwnProperty.call(object, name); } // Provide critical ES5 functions to ES3. if (typeof Array.isArray !== 'function') { Array.isArray = function (o) { return Object.prototype.toString.apply(o) === '[object Array]'; }; } if (typeof Object.create !== 'function') { Object.create = function (o) { F.prototype = o; return new F(); }; } if (typeof Object.keys !== 'function') { Object.keys = function (o) { var a = [], k; for (k in o) { if (is_own(o, k)) { a.push(k); } } return a; }; } // Non standard methods if (typeof String.prototype.entityify !== 'function') { String.prototype.entityify = function () { return this .replace(/&/g, '&') .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); if (option.devel) combine(predefined, devel); if (option.dojo) combine(predefined, dojo); if (option.browser) combine(predefined, browser); if (option.jquery) combine(predefined, jquery); if (option.mootools) combine(predefined, mootools); if (option.wsh) combine(predefined, wsh); if (option.globalstrict && option.strict !== false) option.strict = true; } // Produce an error warning. function quit(message, line, chr) { var percentage = Math.floor((line / lines.length) * 100); throw { name: 'JSHintError', line: line, character: chr, message: message + " (" + percentage + "% scanned)." }; } function warning(m, t, a, b, c, d) { var ch, l, w; t = t || nexttoken; if (t.id === '(end)') { // `~ t = token; } l = t.line || 0; ch = t.from || 0; w = { id: '(error)', raw: m, evidence: lines[l - 1] || '', line: l, character: ch, a: a, b: b, c: c, d: d }; w.reason = m.supplant(w); JSHINT.errors.push(w); if (option.passfail) { quit('Stopping. ', l, ch); } warnings += 1; if (warnings >= option.maxerr) { quit("Too many errors.", l, ch); } return w; } function warningAt(m, l, ch, a, b, c, d) { return warning(m, { line: l, from: ch }, a, b, c, d); } function error(m, t, a, b, c, d) { var w = warning(m, t, a, b, c, d); quit("Stopping, unable to continue.", w.line, w.character); } function errorAt(m, l, ch, a, b, c, d) { return error(m, { line: l, from: ch }, a, b, c, d); } // lexical analysis and token construction var lex = (function lex() { var character, from, line, s; // Private lex methods function nextLine() { var at, tw; // trailing whitespace check if (line >= lines.length) return false; character = 1; s = lines[line]; line += 1; at = s.search(/ \t/); if (at >= 0) warningAt("Mixed spaces and tabs.", line, at + 1); s = s.replace(/\t/g, tab); at = s.search(cx); if (at >= 0) warningAt("Unsafe character.", line, at); if (option.maxlen && option.maxlen < s.length) warningAt("Line too long.", line, s.length); // Check for trailing whitespaces tw = s.search(/\s+$/); if (option.trailing && ~tw && !~s.search(/^\s+$/)) warningAt("Trailing whitespace.", line, tw); return true; } // Produce a token object. The token inherits from a syntax symbol. function it(type, value) { var i, t; if (type === '(color)' || type === '(range)') { t = {type: type}; } else if (type === '(punctuator)' || (type === '(identifier)' && is_own(syntax, value))) { t = syntax[value] || syntax['(error)']; } else { t = syntax[type]; } t = Object.create(t); if (type === '(string)' || type === '(range)') { if (!option.scripturl && jx.test(value)) { warningAt("Script URL.", line, from); } } if (type === '(identifier)') { t.identifier = true; if (value === '__proto__' && !option.proto) { warningAt("The '{a}' property is deprecated.", line, from, value); } else if (value === '__iterator__' && !option.iterator) { warningAt("'{a}' is only available in JavaScript 1.7.", line, from, value); } else if (option.nomen && (value.charAt(0) === '_' || value.charAt(value.length - 1) === '_')) { warningAt("Unexpected {a} in '{b}'.", line, from, "dangling '_'", value); } } t.value = value; t.line = line; t.character = character; t.from = from; i = t.id; if (i !== '(endline)') { prereg = i && (('(,=:[!&|?{};'.indexOf(i.charAt(i.length - 1)) >= 0) || i === 'return'); } return t; } // Public lex methods return { init: function (source) { if (typeof source === 'string') { lines = source .replace(/\r\n/g, '\n') .replace(/\r/g, '\n') .split('\n'); } else { lines = source; } // If the first line is a shebang (#!), make it a blank and move on. // Shebangs are used by Node scripts. if (lines[0] && lines[0].substr(0, 2) == '#!') lines[0] = ''; line = 0; nextLine(); from = 1; }, range: function (begin, end) { var c, value = ''; from = character; if (s.charAt(0) !== begin) { errorAt("Expected '{a}' and instead saw '{b}'.", line, character, begin, s.charAt(0)); } for (;;) { s = s.slice(1); character += 1; c = s.charAt(0); switch (c) { case '': errorAt("Missing '{a}'.", line, character, c); break; case end: s = s.slice(1); character += 1; return it('(range)', value); case '\\': warningAt("Unexpected '{a}'.", line, character, c); } value += c; } }, // 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; 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 = ''; 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; for (;;) { while (j >= s.length) { j = 0; if (!nextLine()) { errorAt("Unclosed string.", line, from); } } c = s.charAt(j); if (c === x) { character += 1; s = s.substr(j + 1); return it('(string)', r, x); } if (c < ' ') { if (c === '\n' || c === '\r') { break; } warningAt("Control character in string: {a}.", line, character + j, s.slice(0, j)); } else if (c === '\\') { j += 1; character += 1; c = s.charAt(j); switch (c) { case '\\': case '"': case '/': break; case '\'': if (jsonmode) { warningAt("Avoid \\'.", line, character); } break; case 'b': c = '\b'; break; case 'f': c = '\f'; break; case 'n': c = '\n'; break; case 'r': c = '\r'; break; case 't': c = '\t'; break; case 'u': esc(4); break; case 'v': if (jsonmode) { warningAt("Avoid \\v.", line, character); } c = '\v'; break; case 'x': if (jsonmode) { warningAt("Avoid \\x-.", line, character); } esc(2); break; default: warningAt("Bad escapement.", line, character); } } r += c; character += 1; j += 1; } } for (;;) { if (!s) { return it(nextLine() ? '(endline)' : '(end)', ''); } t = match(tx); if (!t) { t = ''; c = ''; while (s && s < '!') { s = s.substr(1); } if (s) { errorAt("Unexpected '{a}'.", line, character, s.substr(0, 1)); } } else { // identifier if (c.isAlpha() || c === '_' || c === '$') { return it('(identifier)', t); } // number if (c.isDigit()) { if (!isFinite(Number(t))) { warningAt("Bad number '{a}'.", line, character, t); } if (s.substr(0, 1).isAlpha()) { warningAt("Missing space after '{a}'.", line, character, t); } if (c === '0') { d = t.substr(1, 1); if (d.isDigit()) { if (token.id !== '.') { warningAt("Don't use extra leading zeros '{a}'.", line, character, t); } } else if (jsonmode && (d === 'x' || d === 'X')) { warningAt("Avoid 0x-. '{a}'.", line, character, t); } } if (t.substr(t.length - 1) === '.') { warningAt( "A trailing decimal point can be confused with a dot '{a}'.", line, character, t); } return it('(number)', t); } switch (t) { // string case '"': case "'": return string(t); // // comment case '//': if (src) { warningAt("Unexpected comment.", line, character); } s = ''; token.comment = true; break; // /* comment case '/*': if (src) { warningAt("Unexpected comment.", line, character); } for (;;) { i = s.search(lx); if (i >= 0) { break; } if (!nextLine()) { errorAt("Unclosed comment.", line, character); } } character += i + 2; if (s.substr(i, 1) === '/') { errorAt("Nested comment.", line, character); } s = s.substr(i + 2); token.comment = true; break; // /*members /*jshint /*global case '/*members': case '/*member': case '/*jshint': case '/*jslint': case '/*global': case '*/': return { value: t, type: 'special', line: line, character: character, from: from }; case '': break; // / case '/': if (token.id === '/=') { errorAt( "A regular expression literal can be confused with '/='.", line, from); } if (prereg) { depth = 0; captures = 0; l = 0; for (;;) { b = true; c = s.charAt(l); l += 1; switch (c) { case '': errorAt("Unclosed regular expression.", line, from); return; case '/': if (depth > 0) { warningAt("Unescaped '{a}'.", line, from + l, '/'); } c = s.substr(0, l - 1); q = { g: true, i: true, m: true }; while (q[s.charAt(l)] === true) { q[s.charAt(l)] = false; l += 1; } character += l; s = s.substr(l); q = s.charAt(0); if (q === '/' || q === '*') { errorAt("Confusing regular expression.", line, from); } return it('(regexp)', c); case '\\': c = s.charAt(l); if (c < ' ') { warningAt( "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, '^'); } } q = false; if (c === ']') { warningAt("Empty class.", line, from + l - 1); q = true; } klass: do { c = s.charAt(l); l += 1; switch (c) { case '[': case '^': warningAt("Unescaped '{a}'.", line, from + l, c); q = true; break; case '-': if (q) { q = false; } else { warningAt("Unescaped '{a}'.", line, from + l, '-'); q = true; } break; case ']': if (!q && !option.regexdash) { warningAt("Unescaped '{a}'.", line, from + l - 1, '-'); } break klass; case '\\': c = s.charAt(l); if (c < ' ') { warningAt( "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; q = true; break; case '/': warningAt("Unescaped '{a}'.", line, from + l - 1, '/'); q = true; break; case '<': q = true; break; default: q = true; } } while (c); break; case '.': if (option.regexp) { warningAt("Insecure '{a}'.", line, from + l, c); } break; case ']': case '?': case '{': case '}': case '+': case '*': warningAt("Unescaped '{a}'.", line, from + l, c); } if (b) { switch (s.charAt(l)) { case '?': case '+': case '*': l += 1; if (s.charAt(l) === '?') { l += 1; } break; case '{': l += 1; c = s.charAt(l); if (c < '0' || c > '9') { warningAt( "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) warning("'{a}' is already defined.", nexttoken, t); } } funct[t] = type; if (funct['(global)']) { global[t] = funct; if (is_own(implied, t)) { if (option.latedef) warning("'{a}' was used before it was defined.", nexttoken, t); delete implied[t]; } } else { scope[t] = funct; } } function doOption() { var b, obj, filter, o = nexttoken.value, t, v; switch (o) { case '*/': error("Unbegun comment."); break; case '/*members': case '/*member': o = '/*members'; if (!membersOnly) { membersOnly = {}; } obj = membersOnly; break; case '/*jshint': case '/*jslint': obj = option; filter = boolOptions; break; case '/*global': obj = predefined; break; default: error("What?"); } t = lex.token(); loop: for (;;) { for (;;) { if (t.type === 'special' && t.value === '*/') { break loop; } if (t.id !== '(endline)' && t.id !== ',') { break; } t = lex.token(); } if (t.type !== '(string)' && t.type !== '(identifier)' && o !== '/*members') { error("Bad option.", t); } v = lex.token(); if (v.id === ':') { v = lex.token(); if (obj === membersOnly) { error("Expected '{a}' and instead saw '{b}'.", t, '*/', ':'); } if (t.value === 'indent' && (o === '/*jshint' || o === '/*jslint')) { b = +v.value; if (typeof b !== 'number' || !isFinite(b) || b <= 0 || Math.floor(b) !== b) { error("Expected a small integer and instead saw '{a}'.", v, v.value); } obj.white = true; obj.indent = b; } else if (t.value === 'maxerr' && (o === '/*jshint' || o === '/*jslint')) { b = +v.value; if (typeof b !== 'number' || !isFinite(b) || b <= 0 || Math.floor(b) !== b) { error("Expected a small integer and instead saw '{a}'.", v, v.value); } obj.maxerr = b; } else if (t.value === 'maxlen' && (o === '/*jshint' || o === '/*jslint')) { b = +v.value; if (typeof b !== 'number' || !isFinite(b) || b <= 0 || Math.floor(b) !== b) { error("Expected a small integer and instead saw '{a}'.", v, v.value); } obj.maxlen = b; } else if (v.value === 'true') { obj[t.value] = true; } else if (v.value === 'false') { obj[t.value] = false; } else { error("Bad option value.", v); } t = lex.token(); } else { if (o === '/*jshint' || o === '/*jslint') { error("Missing option value.", t); } obj[t.value] = false; t = v; } } if (filter) { assume(); } } // We need a peek function. If it has an argument, it peeks that much farther // ahead. It is used to distinguish // for ( var i in ... // from // for ( var i = ... function peek(p) { var i = p || 0, j = 0, t; while (j <= i) { t = lookahead[j]; if (!t) { t = lookahead[j] = lex.token(); } j += 1; } return t; } // Produce the next token. It looks for programming errors. function advance(id, t) { switch (token.id) { case '(number)': if (nexttoken.id === '.') { warning("A dot following a number can be confused with a decimal point.", token); } break; case '-': if (nexttoken.id === '-' || nexttoken.id === '--') { warning("Confusing minusses."); } break; case '+': if (nexttoken.id === '+' || nexttoken.id === '++') { warning("Confusing plusses."); } break; } if (token.type === '(string)' || token.identifier) { anonname = token.value; } if (id && nexttoken.id !== id) { if (t) { if (nexttoken.id === '(end)') { warning("Unmatched '{a}'.", t, t.id); } else { warning("Expected '{a}' to match '{b}' from line {c} and instead saw '{d}'.", nexttoken, id, t.id, t.line, nexttoken.value); } } else if (nexttoken.type !== '(identifier)' || nexttoken.value !== id) { warning("Expected '{a}' and instead saw '{b}'.", nexttoken, id, nexttoken.value); } } prevtoken = token; token = nexttoken; for (;;) { nexttoken = lookahead.shift() || lex.token(); if (nexttoken.id === '(end)' || nexttoken.id === '(error)') { return; } if (nexttoken.type === 'special') { doOption(); } else { if (nexttoken.id !== '(endline)') { break; } } } } // This is the heart of JSHINT, the Pratt parser. In addition to parsing, it // is looking for ad hoc lint patterns. We add .fud to Pratt's model, which is // like .nud except that it is only used on the first token of a statement. // Having .fud makes it much easier to define statement-oriented languages like // JavaScript. I retained Pratt's nomenclature. // .nud Null denotation // .fud First null denotation // .led Left denotation // lbp Left binding power // rbp Right binding power // They are elements of the parsing method called Top Down Operator Precedence. function expression(rbp, initial) { var left, isArray = false; if (nexttoken.id === '(end)') error("Unexpected early end of program.", token); advance(); if (initial) { anonname = 'anonymous'; funct['(verb)'] = token.value; } if (initial === true && token.fud) { left = token.fud(); } else { if (token.nud) { left = token.nud(); } else { if (nexttoken.type === '(number)' && token.id === '.') { warning("A leading decimal point can be confused with a dot: '.{a}'.", token, nexttoken.value); advance(); return token; } else { error("Expected an identifier and instead saw '{a}'.", token, token.id); } } while (rbp < nexttoken.lbp) { isArray = token.value == 'Array'; advance(); if (isArray && token.id == '(' && nexttoken.id == ')') warning("Use the array literal notation [].", token); if (token.led) { left = token.led(left); } else { error("Expected an operator and instead saw '{a}'.", token, token.id); } } } return left; } // Functions for conformance of style. function adjacent(left, right) { left = left || token; right = right || nexttoken; if (option.white) { if (left.character !== right.from && left.line === right.line) { warning("Unexpected space after '{a}'.", right, left.value); } } } function nobreak(left, right) { left = left || token; right = right || nexttoken; if (option.white && (left.character !== right.from || left.line !== right.line)) { warning("Unexpected space before '{a}'.", right, right.value); } } function nospace(left, right) { left = left || token; right = right || nexttoken; if (option.white && !left.comment) { if (left.line === right.line) { adjacent(left, right); } } } function nonadjacent(left, right) { if (option.white) { left = left || token; right = right || nexttoken; if (left.line === right.line && left.character === right.from) { warning("Missing space after '{a}'.", nexttoken, left.value); } } } function nobreaknonadjacent(left, right) { left = left || token; right = right || nexttoken; if (!option.laxbreak && left.line !== right.line) { warning("Bad line breaking before '{a}'.", right, right.id); } else if (option.white) { left = left || token; right = right || nexttoken; if (left.character === right.from) { warning("Missing space after '{a}'.", nexttoken, left.value); } } } function indentation(bias) { var i; if (option.white && nexttoken.id !== '(end)') { i = indent + (bias || 0); if (nexttoken.from !== i) { warning( "Expected '{a}' to have an indentation at {b} instead at {c}.", nexttoken, nexttoken.value, i, nexttoken.from); } } } function nolinebreak(t) { t = t || token; if (t.line !== nexttoken.line) { warning("Line breaking error '{a}'.", t, t.value); } } function comma() { if (token.line !== nexttoken.line) { if (!option.laxbreak) { warning("Bad line breaking before '{a}'.", token, nexttoken.id); } } else if (token.character !== nexttoken.from && option.white) { warning("Unexpected space after '{a}'.", nexttoken, token.value); } advance(','); nonadjacent(token, nexttoken); } // Functional constructors for making the symbols that will be inherited by // tokens. function symbol(s, p) { var x = syntax[s]; if (!x || typeof x !== 'object') { syntax[s] = x = { id: s, lbp: p, value: s }; } return x; } function delim(s) { return symbol(s, 0); } function stmt(s, f) { var x = delim(s); x.identifier = x.reserved = true; x.fud = f; return x; } function blockstmt(s, f) { var x = stmt(s, f); x.block = true; return x; } function reserveName(x) { var c = x.id.charAt(0); if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { x.identifier = x.reserved = true; } return x; } function prefix(s, f) { var x = symbol(s, 150); reserveName(x); x.nud = (typeof f === 'function') ? f : function () { this.right = expression(150); this.arity = 'unary'; if (this.id === '++' || this.id === '--') { if (option.plusplus) { warning("Unexpected use of '{a}'.", this, this.id); } else if ((!this.right.identifier || this.right.reserved) && this.right.id !== '.' && this.right.id !== '[') { warning("Bad operand.", this); } } return this; }; return x; } function type(s, f) { var x = delim(s); x.type = s; x.nud = f; return x; } function reserve(s, f) { var x = type(s, f); x.identifier = x.reserved = true; return x; } function reservevar(s, v) { return reserve(s, function () { if (typeof v === 'function') { v(this); } return this; }); } function infix(s, f, p, w) { var x = symbol(s, p); reserveName(x); x.led = function (left) { if (!w) { nobreaknonadjacent(prevtoken, token); nonadjacent(token, nexttoken); } if (typeof f === 'function') { return f(left, this); } else { this.left = left; this.right = expression(p); return this; } }; return x; } function relation(s, f) { var x = symbol(s, 100); x.led = function (left) { nobreaknonadjacent(prevtoken, token); nonadjacent(token, nexttoken); var right = expression(100); if ((left && left.id === 'NaN') || (right && right.id === 'NaN')) { warning("Use the isNaN function to compare with NaN.", this); } else if (f) { f.apply(this, [left, right]); } if (left.id === '!') { warning("Confusing use of '{a}'.", left, '!'); } if (right.id === '!') { warning("Confusing use of '{a}'.", left, '!'); } this.left = left; this.right = right; return this; }; return x; } function isPoorRelation(node) { return node && ((node.type === '(number)' && +node.value === 0) || (node.type === '(string)' && node.value === '') || (node.type === 'null' && !option.eqnull) || node.type === 'true' || node.type === 'false' || node.type === 'undefined'); } function assignop(s, f) { symbol(s, 20).exps = true; return infix(s, function (left, that) { var l; that.left = left; if (predefined[left.value] === false && scope[left.value]['(global)'] === true) { warning("Read only.", left); } else if (left['function']) { warning("'{a}' is a function.", left, left.value); } if (left) { if (left.id === '.' || left.id === '[') { if (!left.left || left.left.value === 'arguments') { warning('Bad assignment.', that); } that.right = expression(19); return that; } else if (left.identifier && !left.reserved) { if (funct[left.value] === 'exception') { warning("Do not assign to the exception parameter.", left); } that.right = expression(19); return that; } if (left === syntax['function']) { warning( "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') { warning( "Inner functions should be listed at the top of the outer function.", t); break; } warning("Unreachable '{a}' after '{b}'.", t, t.value, s); break; } i += 1; } } function statement(noindent) { var i = indent, r, s = scope, t = nexttoken; // We don't like the empty statement. if (t.id === ';') { warning("Unnecessary semicolon.", t); advance(';'); return; } // Is this a labelled statement? if (t.identifier && !t.reserved && peek().id === ':') { advance(); advance(':'); scope = Object.create(s); addlabel(t.value, 'label'); if (!nexttoken.labelled) { warning("Label '{a}' on {b} statement.", nexttoken, t.value, nexttoken.value); } if (jx.test(t.value + ':')) { warning("Label '{a}' looks like a javascript url.", t, t.value); } nexttoken.label = t.value; t = nexttoken; } // Parse the statement. if (!noindent) { indentation(); } r = expression(0, true); // Look for the final semicolon. if (!t.block) { if (!option.expr && (!r || !r.exps)) { warning("Expected an assignment or function call and instead saw an expression.", token); } else if (option.nonew && r.id === '(' && r.left.id === 'new') { warning("Do not use 'new' for side effects."); } if (nexttoken.id !== ';') { if (!option.asi && !(option.lastsemic && nexttoken.id == '}' && nexttoken.line == token.line)) { warningAt("Missing semicolon.", token.line, token.from + token.value.length); } } else { adjacent(token, nexttoken); advance(';'); nonadjacent(token, nexttoken); } } // Restore the indentation. indent = i; scope = s; return r; } function use_strict() { if (nexttoken.value === 'use strict') { if (strict_mode) { warning("Unnecessary \"use strict\"."); } advance(); advance(';'); strict_mode = true; option.newcap = true; option.undef = true; return true; } else { return false; } } function statements(begin) { var a = [], f, p; while (!nexttoken.reach && nexttoken.id !== '(end)') { if (nexttoken.id === ';') { warning("Unnecessary semicolon."); advance(';'); } else { a.push(statement()); } } return a; } /* * Parses a single block. A block is a sequence of statements wrapped in * braces. * * ordinary - true for everything but function bodies and try blocks. * stmt - true if block can be a single statement (e.g. in if/for/while). */ function block(ordinary, stmt) { var a, b = inblock, old_indent = indent, m = strict_mode, s = scope, t; inblock = ordinary; scope = Object.create(scope); nonadjacent(token, nexttoken); t = nexttoken; if (nexttoken.id === '{') { advance('{'); if (nexttoken.id !== '}' || token.line !== nexttoken.line) { indent += option.indent; while (!ordinary && nexttoken.from > indent) { indent += option.indent; } if (!ordinary && !use_strict() && !m && option.strict && funct['(context)']['(global)']) { warning("Missing \"use strict\" statement."); } a = statements(); strict_mode = m; indent -= option.indent; indentation(); } advance('}', t); indent = old_indent; } else if (!ordinary) { error("Expected '{a}' and instead saw '{b}'.", nexttoken, '{', nexttoken.value); } else { if (!stmt || option.curly) warning("Expected '{a}' and instead saw '{b}'.", nexttoken, '{', nexttoken.value); noreach = true; a = [statement()]; noreach = false; } funct['(verb)'] = null; scope = s; inblock = b; if (ordinary && option.noempty && (!a || a.length === 0)) { warning("Empty block."); } return a; } function countMember(m) { if (membersOnly && typeof membersOnly[m] !== 'boolean') { warning("Unexpected /*member '{a}'.", token, m); } if (typeof member[m] === 'number') { member[m] += 1; } else { member[m] = 1; } } function note_implied(token) { var name = token.value, line = token.line, a = implied[name]; if (typeof a === 'function') { a = false; } if (!a) { a = [line]; implied[name] = a; } else if (a[a.length - 1] !== line) { a.push(line); } } // Build the syntax table by declaring the syntactic elements of the language. type('(number)', function () { return this; }); type('(string)', function () { return this; }); syntax['(identifier)'] = { type: '(identifier)', lbp: 0, identifier: true, nud: function () { var v = this.value, s = scope[v], f; if (typeof s === 'function') { // Protection against accidental inheritance. s = undefined; } else if (typeof s === 'boolean') { f = funct; funct = functions[0]; addlabel(v, 'var'); s = funct; funct = f; } // The name is in scope and defined in the current function. if (funct === s) { // Change 'unused' to 'var', and reject labels. switch (funct[v]) { case 'unused': funct[v] = 'var'; break; case 'unction': funct[v] = 'function'; this['function'] = true; break; case 'function': this['function'] = true; break; case 'label': warning("'{a}' is a statement label.", token, v); break; } // The name is not defined in the function. If we are in the global scope, // then we have an undefined variable. // // Operators typeof and delete do not raise runtime errors even if the base // object of a reference is null so no need to display warning if we're // inside of typeof or delete. } else if (funct['(global)']) { if (anonname != 'typeof' && anonname != 'delete' && option.undef && typeof predefined[v] !== 'boolean') { warning("'{a}' is not defined.", token, v); } note_implied(token); // If the name is already defined in the current // function, but not as outer, then there is a scope error. } else { switch (funct[v]) { case 'closure': case 'function': case 'var': case 'unused': warning("'{a}' used out of scope.", token, v); break; case 'label': warning("'{a}' is a statement label.", token, v); break; case 'outer': case 'global': break; default: // If the name is defined in an outer function, make an outer entry, and if // it was unused, make it var. if (s === true) { funct[v] = true; } else if (s === null) { warning("'{a}' is not allowed.", token, v); note_implied(token); } else if (typeof s !== 'object') { // Operators typeof and delete do not raise runtime errors even if the base object of // a reference is null so no need to display warning if we're inside of typeof or delete. if (anonname != 'typeof' && anonname != 'delete' && option.undef) { warning("'{a}' is not defined.", token, v); } else { funct[v] = true; } note_implied(token); } else { switch (s[v]) { case 'function': case 'unction': this['function'] = true; s[v] = 'closure'; funct[v] = s['(global)'] ? 'global' : 'outer'; break; case 'var': case 'unused': s[v] = 'closure'; funct[v] = s['(global)'] ? 'global' : 'outer'; break; case 'closure': case 'parameter': funct[v] = s['(global)'] ? 'global' : 'outer'; break; case 'label': warning("'{a}' is a statement label.", token, v); } } } } return this; }, led: function () { error("Expected an operator and instead saw '{a}'.", nexttoken, nexttoken.value); } }; type('(regexp)', function () { return this; }); // ECMAScript parser delim('(endline)'); delim('(begin)'); delim('(end)').reach = true; delim(''); delim('(error)').reach = true; delim('}').reach = true; delim(')'); delim(']'); delim('"').reach = true; delim("'").reach = true; delim(';'); delim(':').reach = true; delim(','); delim('#'); delim('@'); reserve('else'); reserve('case').reach = true; reserve('catch'); reserve('default').reach = true; reserve('finally'); reservevar('arguments', function (x) { if (strict_mode && funct['(global)']) { warning("Strict violation.", x); } }); reservevar('eval'); reservevar('false'); reservevar('Infinity'); reservevar('NaN'); reservevar('null'); reservevar('this', function (x) { if (strict_mode && ((funct['(statement)'] && funct['(name)'].charAt(0) > 'Z') || funct['(global)'])) { warning("Strict violation.", x); } }); reservevar('true'); reservevar('undefined'); assignop('=', 'assign', 20); assignop('+=', 'assignadd', 20); assignop('-=', 'assignsub', 20); assignop('*=', 'assignmult', 20); assignop('/=', 'assigndiv', 20).nud = function () { error("A regular expression literal can be confused with '/='."); }; assignop('%=', 'assignmod', 20); bitwiseassignop('&=', 'assignbitand', 20); bitwiseassignop('|=', 'assignbitor', 20); bitwiseassignop('^=', 'assignbitxor', 20); bitwiseassignop('<<=', 'assignshiftleft', 20); bitwiseassignop('>>=', 'assignshiftright', 20); bitwiseassignop('>>>=', 'assignshiftrightunsigned', 20); infix('?', function (left, that) { that.left = left; that.right = expression(10); advance(':'); that['else'] = expression(10); return that; }, 30); infix('||', 'or', 40); infix('&&', 'and', 50); bitwise('|', 'bitor', 70); bitwise('^', 'bitxor', 80); bitwise('&', 'bitand', 90); relation('==', function (left, right) { var eqnull = option.eqnull && (left.value == 'null' || right.value == 'null'); if (!eqnull && option.eqeqeq) { warning("Expected '{a}' and instead saw '{b}'.", this, '===', '=='); } else if (isPoorRelation(left)) { warning("Use '{a}' to compare with '{b}'.", this, '===', left.value); } else if (isPoorRelation(right)) { warning("Use '{a}' to compare with '{b}'.", this, '===', right.value); } return this; }); relation('==='); relation('!=', function (left, right) { var eqnull = option.eqnull && (left.value == 'null' || right.value == 'null'); if (!eqnull && option.eqeqeq) { warning("Expected '{a}' and instead saw '{b}'.", this, '!==', '!='); } else if (isPoorRelation(left)) { warning("Use '{a}' to compare with '{b}'.", this, '!==', left.value); } else if (isPoorRelation(right)) { warning("Use '{a}' to compare with '{b}'.", this, '!==', right.value); } return this; }); relation('!=='); relation('<'); relation('>'); relation('<='); relation('>='); bitwise('<<', 'shiftleft', 120); bitwise('>>', 'shiftright', 120); bitwise('>>>', 'shiftrightunsigned', 120); infix('in', 'in', 120); infix('instanceof', 'instanceof', 120); infix('+', function (left, that) { var right = expression(130); if (left && right && left.id === '(string)' && right.id === '(string)') { left.value += right.value; left.character = right.character; if (!option.scripturl && jx.test(left.value)) { warning("JavaScript URL.", left); } return left; } that.left = left; that.right = right; return that; }, 130); prefix('+', 'num'); prefix('+++', function () { warning("Confusing pluses."); this.right = expression(150); this.arity = 'unary'; return this; }); infix('+++', function (left) { warning("Confusing pluses."); this.left = left; this.right = expression(130); return this; }, 130); infix('-', 'sub', 130); prefix('-', 'neg'); prefix('---', function () { warning("Confusing minuses."); this.right = expression(150); this.arity = 'unary'; return this; }); infix('---', function (left) { warning("Confusing minuses."); this.left = left; this.right = expression(130); return this; }, 130); infix('*', 'mult', 140); infix('/', 'div', 140); infix('%', 'mod', 140); suffix('++', 'postinc'); prefix('++', 'preinc'); syntax['++'].exps = true; suffix('--', 'postdec'); prefix('--', 'predec'); syntax['--'].exps = true; prefix('delete', function () { var p = expression(0); if (!p || (p.id !== '.' && p.id !== '[')) { warning("Variables should not be deleted."); } this.first = p; return this; }).exps = true; prefix('~', function () { if (option.bitwise) { warning("Unexpected '{a}'.", this, '~'); } expression(150); return this; }); prefix('!', function () { this.right = expression(150); this.arity = 'unary'; if (bang[this.right.id] === true) { warning("Confusing use of '{a}'.", this, '!'); } return this; }); prefix('typeof', 'typeof'); prefix('new', function () { var c = expression(155), i; if (c && c.id !== 'function') { if (c.identifier) { c['new'] = true; switch (c.value) { case 'Object': warning("Use the object literal notation {}.", token); break; case 'Number': case 'String': case 'Boolean': case 'Math': case 'JSON': warning("Do not use {a} as a constructor.", token, c.value); break; case 'Function': if (!option.evil) { warning("The Function constructor is eval."); } break; case 'Date': case 'RegExp': break; default: if (c.id !== 'function') { i = c.value.substr(0, 1); if (option.newcap && (i < 'A' || i > 'Z')) { warning("A constructor name should start with "+ "an uppercase letter.", token); } } } } else { if (c.id !== '.' && c.id !== '[' && c.id !== '(') { warning("Bad constructor.", token); } } } else { if (!option.supernew) warning("Weird construction. Delete 'new'.", this); } adjacent(token, nexttoken); if (nexttoken.id !== '(' && !option.supernew) { warning("Missing '()' invoking a constructor."); } this.first = c; return this; }); syntax['new'].exps = true; prefix('void').exps = true; infix('.', function (left, that) { adjacent(prevtoken, token); nobreak(); var m = identifier(); if (typeof m === 'string') { countMember(m); } that.left = left; that.right = m; if (option.noarg && left && left.value === 'arguments' && (m === 'callee' || m === 'caller')) { warning("Avoid arguments.{a}.", left, m); } else if (!option.evil && left && left.value === 'document' && (m === 'write' || m === 'writeln')) { warning("document.write can be a form of eval.", left); } if (!option.evil && (m === 'eval' || m === 'execScript')) { warning('eval is evil.'); } return that; }, 160, true); infix('(', function (left, that) { if (prevtoken.id !== '}' && prevtoken.id !== ')') { nobreak(prevtoken, token); } nospace(); if (option.immed && !left.immed && left.id === 'function') { warning("Wrap an immediate function invocation in parentheses " + "to assist the reader in understanding that the expression " + "is the result of a function, and not the function itself."); } var n = 0, p = []; if (left) { if (left.type === '(identifier)') { if (left.value.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)) { if (left.value !== 'Number' && left.value !== 'String' && left.value !== 'Boolean' && left.value !== 'Date') { if (left.value === 'Math') { warning("Math is not a function.", left); } else if (option.newcap) { warning( "Missing 'new' prefix when invoking a constructor.", left); } } } } } if (nexttoken.id !== ')') { for (;;) { p[p.length] = expression(10); n += 1; if (nexttoken.id !== ',') { break; } comma(); } } advance(')'); nospace(prevtoken, token); if (typeof left === 'object') { if (left.value === 'parseInt' && n === 1) { warning("Missing radix parameter.", left); } if (!option.evil) { if (left.value === 'eval' || left.value === 'Function' || left.value === 'execScript') { warning("eval is evil.", left); } else if (p[0] && p[0].id === '(string)' && (left.value === 'setTimeout' || left.value === 'setInterval')) { warning( "Implied eval is evil. Pass a function instead of a string.", left); } } if (!left.identifier && left.id !== '.' && left.id !== '[' && left.id !== '(' && left.id !== '&&' && left.id !== '||' && left.id !== '?') { warning("Bad invocation.", left); } } that.left = left; return that; }, 155, true).exps = true; prefix('(', function () { nospace(); if (nexttoken.id === 'function') { nexttoken.immed = true; } var v = expression(0); advance(')', this); nospace(prevtoken, token); if (option.immed && v.id === 'function') { if (nexttoken.id === '(') { warning( "Move the invocation into the parens that contain the function.", nexttoken); } else { warning( "Do not wrap function literals in parens unless they are to be immediately invoked.", this); } } return v; }); infix('[', function (left, that) { nobreak(prevtoken, token); nospace(); var e = expression(0), s; if (e && e.type === '(string)') { if (!option.evil && (e.value === 'eval' || e.value === 'execScript')) { warning("eval is evil.", that); } countMember(e.value); if (!option.sub && ix.test(e.value)) { s = syntax[e.value]; if (!s || !s.reserved) { warning("['{a}'] is better written in dot notation.", e, e.value); } } } advance(']', that); nospace(prevtoken, token); that.left = left; that.right = e; return that; }, 160, true); prefix('[', function () { var b = token.line !== nexttoken.line; this.first = []; if (b) { indent += option.indent; if (nexttoken.from === indent + option.indent) { indent += option.indent; } } while (nexttoken.id !== '(end)') { while (nexttoken.id === ',') { warning("Extra comma."); advance(','); } if (nexttoken.id === ']') { break; } if (b && token.line !== nexttoken.line) { indentation(); } this.first.push(expression(10)); if (nexttoken.id === ',') { comma(); if (nexttoken.id === ']' && !option.es5) { warning("Extra comma.", token); break; } } else { break; } } if (b) { indent -= option.indent; indentation(); } advance(']', this); return this; }, 160); function property_name() { var id = optionalidentifier(true); if (!id) { if (nexttoken.id === '(string)') { id = nexttoken.value; advance(); } else if (nexttoken.id === '(number)') { id = nexttoken.value.toString(); advance(); } } return id; } function functionparams() { var i, t = nexttoken, p = []; advance('('); nospace(); if (nexttoken.id === ')') { advance(')'); nospace(prevtoken, token); return; } for (;;) { i = identifier(true); p.push(i); addlabel(i, 'parameter'); if (nexttoken.id === ',') { comma(); } else { advance(')', t); nospace(prevtoken, token); return p; } } } function doFunction(i, statement) { var f, oldOption = option, oldScope = scope; option = Object.create(option); scope = Object.create(scope); funct = { '(name)' : i || '"' + anonname + '"', '(line)' : nexttoken.line, '(context)' : funct, '(breakage)' : 0, '(loopage)' : 0, '(scope)' : scope, '(statement)': statement }; f = funct; token.funct = funct; functions.push(funct); if (i) { addlabel(i, 'function'); } funct['(params)'] = functionparams(); block(false); scope = oldScope; option = oldOption; funct['(last)'] = token.line; funct = funct['(context)']; return f; } (function (x) { x.nud = function () { var b, f, i, j, p, seen = {}, t; b = token.line !== nexttoken.line; if (b) { indent += option.indent; if (nexttoken.from === indent + option.indent) { indent += option.indent; } } for (;;) { if (nexttoken.id === '}') { break; } if (b) { indentation(); } if (nexttoken.value === 'get' && peek().id !== ':') { advance('get'); if (!option.es5) { error("get/set are ES5 features."); } i = property_name(); if (!i) { error("Missing property name."); } t = nexttoken; adjacent(token, nexttoken); f = doFunction(); if (!option.loopfunc && funct['(loopage)']) { warning("Don't make functions within a loop.", t); } p = f['(params)']; if (p) { warning("Unexpected parameter '{a}' in get {b} function.", t, p[0], i); } adjacent(token, nexttoken); advance(','); indentation(); advance('set'); j = property_name(); if (i !== j) { error("Expected {a} and instead saw {b}.", token, i, j); } t = nexttoken; adjacent(token, nexttoken); f = doFunction(); p = f['(params)']; if (!p || p.length !== 1 || p[0] !== 'value') { warning("Expected (value) in set {a} function.", t, i); } } else { i = property_name(); if (typeof i !== 'string') { break; } advance(':'); nonadjacent(token, nexttoken); expression(10); } if (seen[i] === true) { warning("Duplicate member '{a}'.", nexttoken, i); } seen[i] = true; countMember(i); if (nexttoken.id === ',') { comma(); if (nexttoken.id === ',') { warning("Extra comma.", token); } else if (nexttoken.id === '}' && !option.es5) { warning("Extra comma.", token); } } else { break; } } if (b) { indent -= option.indent; indentation(); } advance('}', this); return this; }; x.fud = function () { error("Expected to see a statement and instead saw a block.", token); }; }(delim('{'))); var varstatement = stmt('var', function (prefix) { // JavaScript does not have block scope. It only has function scope. So, // declaring a variable in a block can have unexpected consequences. var id, name, value; if (funct['(onevar)'] && option.onevar) { warning("Too many var statements."); } else if (!funct['(global)']) { funct['(onevar)'] = true; } this.first = []; for (;;) { nonadjacent(token, nexttoken); id = identifier(); if (funct['(global)'] && predefined[id] === false) { warning("Redefinition of '{a}'.", token, id); } addlabel(id, 'unused'); if (prefix) { break; } name = token; this.first.push(token); if (nexttoken.id === '=') { nonadjacent(token, nexttoken); advance('='); nonadjacent(token, nexttoken); if (nexttoken.id === 'undefined') { warning("It is not necessary to initialize '{a}' to 'undefined'.", token, id); } if (peek(0).id === '=' && nexttoken.identifier) { error("Variable {a} was not declared correctly.", nexttoken, nexttoken.value); } value = expression(0); name.first = value; } if (nexttoken.id !== ',') { break; } comma(); } return this; }); varstatement.exps = true; blockstmt('function', function () { if (inblock) { warning("Function declarations should not be placed in blocks. " + "Use a function expression or move the statement to the top of " + "the outer function.", token); } var i = identifier(); adjacent(token, nexttoken); addlabel(i, 'unction'); doFunction(i, true); if (nexttoken.id === '(' && nexttoken.line === token.line) { error( "Function declarations are not invocable. Wrap the whole function invocation in parens."); } return this; }); prefix('function', function () { var i = optionalidentifier(); if (i) { adjacent(token, nexttoken); } else { nonadjacent(token, nexttoken); } doFunction(i); if (!option.loopfunc && funct['(loopage)']) { warning("Don't make functions within a loop."); } return this; }); blockstmt('if', function () { var t = nexttoken; advance('('); nonadjacent(this, t); nospace(); expression(20); if (nexttoken.id === '=') { if (!option.boss) warning("Expected a conditional expression and instead saw an assignment."); advance('='); expression(20); } advance(')', t); nospace(prevtoken, token); block(true, true); if (nexttoken.id === 'else') { nonadjacent(token, nexttoken); advance('else'); if (nexttoken.id === 'if' || nexttoken.id === 'switch') { statement(true); } else { block(true, true); } } return this; }); blockstmt('try', function () { var b, e, s; block(false); if (nexttoken.id === 'catch') { advance('catch'); nonadjacent(token, nexttoken); advance('('); s = scope; scope = Object.create(s); e = nexttoken.value; if (nexttoken.type !== '(identifier)') { warning("Expected an identifier and instead saw '{a}'.", nexttoken, e); } else { addlabel(e, 'exception'); } advance(); advance(')'); block(false); b = true; scope = s; } if (nexttoken.id === 'finally') { advance('finally'); block(false); return; } else if (!b) { error("Expected '{a}' and instead saw '{b}'.", nexttoken, 'catch', nexttoken.value); } return this; }); blockstmt('while', function () { var t = nexttoken; funct['(breakage)'] += 1; funct['(loopage)'] += 1; advance('('); nonadjacent(this, t); nospace(); expression(20); if (nexttoken.id === '=') { if (!option.boss) warning("Expected a conditional expression and instead saw an assignment."); advance('='); expression(20); } advance(')', t); nospace(prevtoken, token); block(true, true); funct['(breakage)'] -= 1; funct['(loopage)'] -= 1; return this; }).labelled = true; reserve('with'); blockstmt('switch', function () { var t = nexttoken, g = false; funct['(breakage)'] += 1; advance('('); nonadjacent(this, t); nospace(); this.condition = expression(20); advance(')', t); nospace(prevtoken, token); nonadjacent(token, nexttoken); t = nexttoken; advance('{'); nonadjacent(token, nexttoken); indent += option.indent; this.cases = []; for (;;) { switch (nexttoken.id) { case 'case': switch (funct['(verb)']) { case 'break': case 'case': case 'continue': case 'return': case 'switch': case 'throw': break; default: // You can tell JSHint that you don't use break intentionally by // adding a comment /* falls through */ on a line just before // the next `case`. if (!ft.test(lines[nexttoken.line - 2])) { warning( "Expected a 'break' statement before 'case'.", token); } } indentation(-option.indent); advance('case'); this.cases.push(expression(20)); g = true; advance(':'); funct['(verb)'] = 'case'; break; case 'default': switch (funct['(verb)']) { case 'break': case 'continue': case 'return': case 'throw': break; default: if (!ft.test(lines[nexttoken.line - 2])) { warning( "Expected a 'break' statement before 'default'.", token); } } indentation(-option.indent); advance('default'); g = true; advance(':'); break; case '}': indent -= option.indent; indentation(); advance('}', t); if (this.cases.length === 1 || this.condition.id === 'true' || this.condition.id === 'false') { warning("This 'switch' should be an 'if'.", this); } funct['(breakage)'] -= 1; funct['(verb)'] = undefined; return; case '(end)': error("Missing '{a}'.", nexttoken, '}'); return; default: if (g) { switch (token.id) { case ',': error("Each value should have its own case label."); return; case ':': statements(); break; default: error("Missing ':' on a case clause.", token); } } else { error("Expected '{a}' and instead saw '{b}'.", nexttoken, 'case', nexttoken.value); } } } }).labelled = true; stmt('debugger', function () { if (!option.debug) { warning("All 'debugger' statements should be removed."); } return this; }).exps = true; (function () { var x = stmt('do', function () { funct['(breakage)'] += 1; funct['(loopage)'] += 1; this.first = block(true); advance('while'); var t = nexttoken; nonadjacent(token, t); advance('('); nospace(); expression(20); if (nexttoken.id === '=') { if (!option.boss) warning("Expected a conditional expression and instead saw an assignment."); advance('='); expression(20); } advance(')', t); nospace(prevtoken, token); funct['(breakage)'] -= 1; funct['(loopage)'] -= 1; return this; }); x.labelled = true; x.exps = true; }()); blockstmt('for', function () { var s, t = nexttoken; funct['(breakage)'] += 1; funct['(loopage)'] += 1; advance('('); nonadjacent(this, t); nospace(); if (peek(nexttoken.id === 'var' ? 1 : 0).id === 'in') { if (nexttoken.id === 'var') { advance('var'); varstatement.fud.call(varstatement, true); } else { switch (funct[nexttoken.value]) { case 'unused': funct[nexttoken.value] = 'var'; break; case 'var': break; default: warning("Bad for in variable '{a}'.", nexttoken, nexttoken.value); } advance(); } advance('in'); expression(20); advance(')', t); s = block(true, true); if (option.forin && (s.length > 1 || typeof s[0] !== 'object' || s[0].value !== 'if')) { warning("The body of a for in should be wrapped in an if statement to filter " + "unwanted properties from the prototype.", this); } funct['(breakage)'] -= 1; funct['(loopage)'] -= 1; return this; } else { if (nexttoken.id !== ';') { if (nexttoken.id === 'var') { advance('var'); varstatement.fud.call(varstatement); } else { for (;;) { expression(0, 'for'); if (nexttoken.id !== ',') { break; } comma(); } } } nolinebreak(token); advance(';'); if (nexttoken.id !== ';') { expression(20); if (nexttoken.id === '=') { if (!option.boss) warning("Expected a conditional expression and instead saw an assignment."); advance('='); expression(20); } } nolinebreak(token); advance(';'); if (nexttoken.id === ';') { error("Expected '{a}' and instead saw '{b}'.", nexttoken, ')', ';'); } if (nexttoken.id !== ')') { for (;;) { expression(0, 'for'); if (nexttoken.id !== ',') { break; } comma(); } } advance(')', t); nospace(prevtoken, token); block(true, true); funct['(breakage)'] -= 1; funct['(loopage)'] -= 1; return this; } }).labelled = true; stmt('break', function () { var v = nexttoken.value; if (funct['(breakage)'] === 0) { warning("Unexpected '{a}'.", nexttoken, this.value); } nolinebreak(this); if (nexttoken.id !== ';') { if (token.line === nexttoken.line) { if (funct[v] !== 'label') { warning("'{a}' is not a statement label.", nexttoken, v); } else if (scope[v] !== funct) { warning("'{a}' is out of scope.", nexttoken, v); } this.first = nexttoken; advance(); } } reachable('break'); return this; }).exps = true; stmt('continue', function () { var v = nexttoken.value; if (funct['(breakage)'] === 0) { warning("Unexpected '{a}'.", nexttoken, this.value); } nolinebreak(this); if (nexttoken.id !== ';') { if (token.line === nexttoken.line) { if (funct[v] !== 'label') { warning("'{a}' is not a statement label.", nexttoken, v); } else if (scope[v] !== funct) { warning("'{a}' is out of scope.", nexttoken, v); } this.first = nexttoken; advance(); } } else if (!funct['(loopage)']) { warning("Unexpected '{a}'.", nexttoken, this.value); } reachable('continue'); return this; }).exps = true; stmt('return', function () { nolinebreak(this); if (nexttoken.id === '(regexp)') { warning("Wrap the /regexp/ literal in parens to disambiguate the slash operator."); } if (nexttoken.id !== ';' && !nexttoken.reach) { nonadjacent(token, nexttoken); this.first = expression(20); } reachable('return'); return this; }).exps = true; stmt('throw', function () { nolinebreak(this); nonadjacent(token, nexttoken); this.first = expression(20); reachable('throw'); return this; }).exps = true; // Superfluous reserved words reserve('class'); reserve('const'); reserve('enum'); reserve('export'); reserve('extends'); reserve('import'); reserve('super'); reserve('let'); reserve('yield'); reserve('implements'); reserve('interface'); reserve('package'); reserve('private'); reserve('protected'); reserve('public'); reserve('static'); // Parse JSON function jsonValue() { function jsonObject() { var o = {}, t = nexttoken; advance('{'); if (nexttoken.id !== '}') { for (;;) { if (nexttoken.id === '(end)') { error("Missing '}' to match '{' from line {a}.", nexttoken, t.line); } else if (nexttoken.id === '}') { warning("Unexpected comma.", token); break; } else if (nexttoken.id === ',') { error("Unexpected comma.", nexttoken); } else if (nexttoken.id !== '(string)') { warning("Expected a string and instead saw {a}.", nexttoken, nexttoken.value); } if (o[nexttoken.value] === true) { warning("Duplicate key '{a}'.", nexttoken, nexttoken.value); } else if ((nexttoken.value === '__proto__' && !option.proto) || (nexttoken.value === '__iterator__' && !option.iterator)) { warning("The '{a}' key may produce unexpected results.", nexttoken, nexttoken.value); } else { o[nexttoken.value] = true; } advance(); advance(':'); jsonValue(); if (nexttoken.id !== ',') { break; } advance(','); } } advance('}'); } function jsonArray() { var t = nexttoken; advance('['); if (nexttoken.id !== ']') { for (;;) { if (nexttoken.id === '(end)') { error("Missing ']' to match '[' from line {a}.", nexttoken, t.line); } else if (nexttoken.id === ']') { warning("Unexpected comma.", token); break; } else if (nexttoken.id === ',') { error("Unexpected comma.", nexttoken); } jsonValue(); if (nexttoken.id !== ',') { break; } advance(','); } } advance(']'); } switch (nexttoken.id) { case '{': jsonObject(); break; case '[': jsonArray(); break; case 'true': case 'false': case 'null': case '(number)': case '(string)': advance(); break; case '-': advance('-'); if (token.character !== nexttoken.from) { warning("Unexpected space after '-'.", token); } adjacent(token, nexttoken); advance('(number)'); break; default: error("Expected a JSON value.", nexttoken); } } // The actual JSHINT function itself. var itself = function (s, o, g) { var a, i, k; JSHINT.errors = []; predefined = Object.create(standard); combine(predefined, g || {}); if (o) { a = o.predef; if (a) { if (Array.isArray(a)) { for (i = 0; i < a.length; i += 1) { predefined[a[i]] = true; } } else if (typeof a === 'object') { k = Object.keys(a); for (i = 0; i < k.length; i += 1) { predefined[k[i]] = !!a[k[i]]; } } } option = o; } else { option = {}; } option.indent = option.indent || 4; option.maxerr = option.maxerr || 50; tab = ''; for (i = 0; i < option.indent; i += 1) { tab += ' '; } indent = 1; global = Object.create(predefined); scope = global; funct = { '(global)': true, '(name)': '(global)', '(scope)': scope, '(breakage)': 0, '(loopage)': 0 }; functions = [funct]; urls = []; src = false; stack = null; member = {}; membersOnly = null; implied = {}; inblock = false; lookahead = []; jsonmode = false; warnings = 0; lex.init(s); prereg = true; strict_mode = false; prevtoken = token = nexttoken = syntax['(begin)']; assume(); try { advance(); switch (nexttoken.id) { case '{': case '[': option.laxbreak = true; jsonmode = true; jsonValue(); break; default: if (nexttoken.value === 'use strict') { if (!option.globalstrict) warning("Use the function form of \"use strict\"."); use_strict(); } statements('lib'); } advance('(end)'); } catch (e) { if (e) { JSHINT.errors.push({ reason : e.message, line : e.line || nexttoken.line, character : e.character || nexttoken.from }, null); } } return JSHINT.errors.length === 0; }; // Data summary. itself.data = function () { var data = {functions: []}, fu, globals, implieds = [], f, i, j, members = [], n, unused = [], v; if (itself.errors.length) { data.errors = itself.errors; } if (jsonmode) { data.json = true; } for (n in implied) { if (is_own(implied, n)) { implieds.push({ name: n, line: implied[n] }); } } if (implieds.length > 0) { data.implieds = implieds; } if (urls.length > 0) { data.urls = urls; } globals = Object.keys(scope); if (globals.length > 0) { data.globals = globals; } for (i = 1; i < functions.length; i += 1) { f = functions[i]; fu = {}; for (j = 0; j < functionicity.length; j += 1) { fu[functionicity[j]] = []; } for (n in f) { if (is_own(f, n) && n.charAt(0) !== '(') { v = f[n]; if (v === 'unction') { v = 'unused'; } if (Array.isArray(fu[v])) { fu[v].push(n); if (v === 'unused') { unused.push({ name: n, line: f['(line)'], 'function': f['(name)'] }); } } } } for (j = 0; j < functionicity.length; j += 1) { if (fu[functionicity[j]].length === 0) { delete fu[functionicity[j]]; } } fu.name = f['(name)']; fu.param = f['(params)']; fu.line = f['(line)']; fu.last = f['(last)']; data.functions.push(fu); } if (unused.length > 0) { data.unused = unused; } members = []; for (n in member) { if (typeof member[n] === 'number') { data.member = member; break; } } return data; }; itself.report = function (option) { var data = itself.data(); var a = [], c, e, err, f, i, k, l, m = '', n, o = [], s; function detail(h, array) { var b, i, singularity; if (array) { o.push('
' + h + ' '); 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('
'); } } if (data.errors || data.implieds || data.unused) { err = true; o.push('
Error:'); if (data.errors) { for (i = 0; i < data.errors.length; i += 1) { c = data.errors[i]; if (c) { e = c.evidence || ''; o.push('

Problem' + (isFinite(c.line) ? ' at line ' + c.line + ' character ' + c.character : '') + ': ' + c.reason.entityify() + '

' + (e && (e.length > 80 ? e.slice(0, 77) + '...' : e).entityify()) + '

'); } } } if (data.implieds) { s = []; for (i = 0; i < data.implieds.length; i += 1) { s[i] = '' + data.implieds[i].name + ' ' + data.implieds[i].line + ''; } o.push('

Implied global: ' + s.join(', ') + '

'); } if (data.unused) { s = []; for (i = 0; i < data.unused.length; i += 1) { s[i] = '' + data.unused[i].name + ' ' + data.unused[i].line + ' ' + data.unused[i]['function'] + ''; } o.push('

Unused variable: ' + s.join(', ') + '

'); } if (data.json) { o.push('

JSON: bad.

'); } o.push('
'); } if (!option) { o.push('
'); if (data.urls) { detail("URLs
", data.urls, '
'); } if (data.json && !err) { o.push('

JSON: good.

'); } else if (data.globals) { o.push('
Global ' + data.globals.sort().join(', ') + '
'); } else { o.push('
No new global variables introduced.
'); } for (i = 0; i < data.functions.length; i += 1) { f = data.functions[i]; o.push('
' + f.line + '-' + f.last + ' ' + (f.name || '') + '(' + (f.param ? f.param.join(', ') : '') + ')
'); detail('Unused', 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 = '
/*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 + '
'); m = ' '; l = 1; } l += n.length + 2; if (data.member[k] === 1) { n = '' + n + ''; } if (i < a.length - 1) { n += ', '; } m += n; } o.push(m + '
*/
'); } o.push('
'); } } return o.join(''); }; itself.jshint = itself; itself.edition = '2011-04-16'; return itself; }()); // Make JSHINT a Node module, if possible. if (typeof exports == 'object' && exports) exports.JSHINT = JSHINT; });/* -*- Mode: JS; tab-width: 4; indent-tabs-mode: nil; -*- * vim: set sw=4 ts=4 et tw=78: * ***** BEGIN LICENSE BLOCK ***** * * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Narcissus JavaScript engine. * * The Initial Developer of the Original Code is * Brendan Eich . * Portions created by the Initial Developer are Copyright (C) 2004 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Tom Austin * Brendan Eich * Shu-Yu Guo * Dave Herman * Dimitris Vardoulakis * Patrick Walton * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* * Narcissus - JS implemented in JS. * * Parser. */ define('ace/narcissus/jsparse', ['require', 'exports', 'module' , 'ace/narcissus/jslex', 'ace/narcissus/jsdefs'], function(require, exports, module) { var lexer = require("./jslex"); var definitions = require("./jsdefs"); const StringMap = definitions.StringMap; const Stack = definitions.Stack; // Set constants in the local scope. eval(definitions.consts); // Banned statement types by language version. const blackLists = { 160: {}, 185: {}, harmony: {} }; blackLists[160][IMPORT] = true; blackLists[160][EXPORT] = true; blackLists[160][LET] = true; blackLists[160][MODULE] = true; blackLists[160][YIELD] = true; blackLists[185][IMPORT] = true; blackLists[185][EXPORT] = true; blackLists[185][MODULE] = true; blackLists.harmony[WITH] = true; /* * pushDestructuringVarDecls :: (node, hoisting node) -> void * * Recursively add all destructured declarations to varDecls. */ function pushDestructuringVarDecls(n, s) { for (var i in n) { var sub = n[i]; if (sub.type === IDENTIFIER) { s.varDecls.push(sub); } else { pushDestructuringVarDecls(sub, s); } } } function StaticContext(parentScript, parentBlock, inModule, inFunction) { this.parentScript = parentScript; this.parentBlock = parentBlock || parentScript; this.inModule = inModule || false; this.inFunction = inFunction || false; this.inForLoopInit = false; this.topLevel = true; this.allLabels = new Stack(); this.currentLabels = new Stack(); this.labeledTargets = new Stack(); this.defaultLoopTarget = null; this.defaultTarget = null; this.blackList = blackLists[Narcissus.options.version]; Narcissus.options.ecma3OnlyMode && (this.ecma3OnlyMode = true); Narcissus.options.parenFreeMode && (this.parenFreeMode = true); } StaticContext.prototype = { ecma3OnlyMode: false, parenFreeMode: false, // non-destructive update via prototype extension update: function(ext) { var desc = {}; for (var key in ext) { desc[key] = { value: ext[key], writable: true, enumerable: true, configurable: true } } return Object.create(this, desc); }, pushLabel: function(label) { return this.update({ currentLabels: this.currentLabels.push(label), allLabels: this.allLabels.push(label) }); }, pushTarget: function(target) { var isDefaultLoopTarget = target.isLoop; var isDefaultTarget = isDefaultLoopTarget || target.type === SWITCH; if (this.currentLabels.isEmpty()) { if (isDefaultLoopTarget) this.update({ defaultLoopTarget: target }); if (isDefaultTarget) this.update({ defaultTarget: target }); return this; } target.labels = new StringMap(); this.currentLabels.forEach(function(label) { target.labels.set(label, true); }); return this.update({ currentLabels: new Stack(), labeledTargets: this.labeledTargets.push(target), defaultLoopTarget: isDefaultLoopTarget ? target : this.defaultLoopTarget, defaultTarget: isDefaultTarget ? target : this.defaultTarget }); }, nest: function() { return this.topLevel ? this.update({ topLevel: false }) : this; }, allow: function(type) { switch (type) { case EXPORT: if (!this.inModule || this.inFunction || !this.topLevel) return false; // FALL THROUGH case IMPORT: return !this.inFunction && this.topLevel; case MODULE: return !this.inFunction && this.topLevel; default: return true; } } }; /* * Script :: (tokenizer, boolean, boolean) -> node * * Parses the toplevel and module/function bodies. */ function Script(t, inModule, inFunction) { var n = new Node(t, scriptInit()); Statements(t, new StaticContext(n, n, inModule, inFunction), n); return n; } // We extend Array slightly with a top-of-stack method. definitions.defineProperty(Array.prototype, "top", function() { return this.length && this[this.length-1]; }, false, false, true); /* * Node :: (tokenizer, optional init object) -> node */ function Node(t, init) { var token = t.token; if (token) { // If init.type exists it will override token.type. this.type = token.type; this.value = token.value; this.lineno = token.lineno; // Start and end are file positions for error handling. this.start = token.start; this.end = token.end; } else { this.lineno = t.lineno; } // Node uses a tokenizer for debugging (getSource, filename getter). this.tokenizer = t; this.children = []; for (var prop in init) this[prop] = init[prop]; } /* * SyntheticNode :: (tokenizer, optional init object) -> node */ function SyntheticNode(t, init) { // print("SYNTHETIC NODE"); // if (init.type === COMMA) { // print("SYNTHETIC COMMA"); // print(init); // } this.tokenizer = t; this.children = []; for (var prop in init) this[prop] = init[prop]; this.synthetic = true; } var Np = Node.prototype = SyntheticNode.prototype = {}; Np.constructor = Node; const TO_SOURCE_SKIP = { type: true, value: true, lineno: true, start: true, end: true, tokenizer: true, assignOp: true }; function unevalableConst(code) { var token = definitions.tokens[code]; var constName = definitions.opTypeNames.hasOwnProperty(token) ? definitions.opTypeNames[token] : token in definitions.keywords ? token.toUpperCase() : token; return { toSource: function() { return constName } }; } Np.toSource = function toSource() { var mock = {}; var self = this; mock.type = unevalableConst(this.type); if ("value" in this) mock.value = this.value; if ("lineno" in this) mock.lineno = this.lineno; if ("start" in this) mock.start = this.start; if ("end" in this) mock.end = this.end; if (this.assignOp) mock.assignOp = unevalableConst(this.assignOp); for (var key in this) { if (this.hasOwnProperty(key) && !(key in TO_SOURCE_SKIP)) mock[key] = this[key]; } return mock.toSource(); }; // Always use push to add operands to an expression, to update start and end. Np.push = function (kid) { // kid can be null e.g. [1, , 2]. if (kid !== null) { if (kid.start < this.start) this.start = kid.start; if (this.end < kid.end) this.end = kid.end; } return this.children.push(kid); } Node.indentLevel = 0; function tokenString(tt) { var t = definitions.tokens[tt]; return /^\W/.test(t) ? definitions.opTypeNames[t] : t.toUpperCase(); } Np.toString = function () { var a = []; for (var i in this) { if (this.hasOwnProperty(i) && i !== 'type' && i !== 'target') a.push({id: i, value: this[i]}); } a.sort(function (a,b) { return (a.id < b.id) ? -1 : 1; }); const INDENTATION = " "; var n = ++Node.indentLevel; var s = "{\n" + INDENTATION.repeat(n) + "type: " + tokenString(this.type); for (i = 0; i < a.length; i++) s += ",\n" + INDENTATION.repeat(n) + a[i].id + ": " + a[i].value; n = --Node.indentLevel; s += "\n" + INDENTATION.repeat(n) + "}"; return s; } Np.getSource = function () { return this.tokenizer.source.slice(this.start, this.end); }; /* * Helper init objects for common nodes. */ const LOOP_INIT = { isLoop: true }; function blockInit() { return { type: BLOCK, varDecls: [] }; } function scriptInit() { return { type: SCRIPT, funDecls: [], varDecls: [], modDefns: new StringMap(), modAssns: new StringMap(), modDecls: new StringMap(), modLoads: new StringMap(), impDecls: [], expDecls: [], exports: new StringMap(), hasEmptyReturn: false, hasReturnWithValue: false, isGenerator: false }; } definitions.defineGetter(Np, "filename", function() { return this.tokenizer.filename; }); definitions.defineGetter(Np, "length", function() { throw new Error("Node.prototype.length is gone; " + "use n.children.length instead"); }); definitions.defineProperty(String.prototype, "repeat", function(n) { var s = "", t = this + s; while (--n >= 0) s += t; return s; }, false, false, true); function MaybeLeftParen(t, x) { if (x.parenFreeMode) return t.match(LEFT_PAREN) ? LEFT_PAREN : END; return t.mustMatch(LEFT_PAREN).type; } function MaybeRightParen(t, p) { if (p === LEFT_PAREN) t.mustMatch(RIGHT_PAREN); } /* * Statements :: (tokenizer, compiler context, node) -> void * * Parses a sequence of Statements. */ function Statements(t, x, n) { try { while (!t.done && t.peek(true) !== RIGHT_CURLY) n.push(Statement(t, x)); } catch (e) { if (t.done) t.unexpectedEOF = true; throw e; } } function Block(t, x) { t.mustMatch(LEFT_CURLY); var n = new Node(t, blockInit()); Statements(t, x.update({ parentBlock: n }).pushTarget(n), n); t.mustMatch(RIGHT_CURLY); return n; } const DECLARED_FORM = 0, EXPRESSED_FORM = 1, STATEMENT_FORM = 2; /* * Export :: (binding node, boolean) -> Export * * Static semantic representation of a module export. */ function Export(node, isDefinition) { this.node = node; // the AST node declaring this individual export this.isDefinition = isDefinition; // is the node an 'export'-annotated definition? this.resolved = null; // resolved pointer to the target of this export } /* * registerExport :: (StringMap, EXPORT node) -> void */ function registerExport(exports, decl) { function register(name, exp) { if (exports.has(name)) throw new SyntaxError("multiple exports of " + name); exports.set(name, exp); } switch (decl.type) { case MODULE: case FUNCTION: register(decl.name, new Export(decl, true)); break; case VAR: for (var i = 0; i < decl.children.length; i++) register(decl.children[i].name, new Export(decl.children[i], true)); break; case LET: case CONST: throw new Error("NYI: " + definitions.tokens[decl.type]); case EXPORT: for (var i = 0; i < decl.pathList.length; i++) { var path = decl.pathList[i]; switch (path.type) { case OBJECT_INIT: for (var j = 0; j < path.children.length; j++) { // init :: IDENTIFIER | PROPERTY_INIT var init = path.children[j]; if (init.type === IDENTIFIER) register(init.value, new Export(init, false)); else register(init.children[0].value, new Export(init.children[1], false)); } break; case DOT: register(path.children[1].value, new Export(path, false)); break; case IDENTIFIER: register(path.value, new Export(path, false)); break; default: throw new Error("unexpected export path: " + definitions.tokens[path.type]); } } break; default: throw new Error("unexpected export decl: " + definitions.tokens[exp.type]); } } /* * Module :: (node) -> Module * * Static semantic representation of a module. */ function Module(node) { var exports = node.body.exports; var modDefns = node.body.modDefns; var exportedModules = new StringMap(); exports.forEach(function(name, exp) { var node = exp.node; if (node.type === MODULE) { exportedModules.set(name, node); } else if (!exp.isDefinition && node.type === IDENTIFIER && modDefns.has(node.value)) { var mod = modDefns.get(node.value); exportedModules.set(name, mod); } }); this.node = node; this.exports = exports; this.exportedModules = exportedModules; } /* * Statement :: (tokenizer, compiler context) -> node * * Parses a Statement. */ function Statement(t, x) { var i, label, n, n2, p, c, ss, tt = t.get(true), tt2, x2, x3; var comments = t.blockComments; if (x.blackList[tt]) throw t.newSyntaxError(definitions.tokens[tt] + " statements only allowed in Harmony"); if (!x.allow(tt)) throw t.newSyntaxError(definitions.tokens[tt] + " statement in illegal context"); // Cases for statements ending in a right curly return early, avoiding the // common semicolon insertion magic after this switch. switch (tt) { case IMPORT: n = new Node(t); n.pathList = ImportPathList(t, x); x.parentScript.impDecls.push(n); break; case EXPORT: switch (t.peek()) { case MODULE: case FUNCTION: case LET: case VAR: case CONST: n = Statement(t, x); n.blockComments = comments; n.exported = true; x.parentScript.expDecls.push(n); registerExport(x.parentScript.exports, n); return n; default: n = new Node(t); n.pathList = ExportPathList(t, x); break; } x.parentScript.expDecls.push(n); registerExport(x.parentScript.exports, n); break; case MODULE: n = new Node(t); n.blockComments = comments; t.mustMatch(IDENTIFIER); label = t.token.value; if (t.match(LEFT_CURLY)) { n.name = label; n.body = Script(t, true, false); n.module = new Module(n); t.mustMatch(RIGHT_CURLY); x.parentScript.modDefns.set(n.name, n); return n; } t.unget(); ModuleVariables(t, x, n); return n; case FUNCTION: // DECLARED_FORM extends funDecls of x, STATEMENT_FORM doesn't. return FunctionDefinition(t, x, true, x.topLevel ? DECLARED_FORM : STATEMENT_FORM, comments); case LEFT_CURLY: n = new Node(t, blockInit()); Statements(t, x.update({ parentBlock: n }).pushTarget(n).nest(), n); t.mustMatch(RIGHT_CURLY); return n; case IF: n = new Node(t); n.condition = HeadExpression(t, x); x2 = x.pushTarget(n).nest(); n.thenPart = Statement(t, x2); n.elsePart = t.match(ELSE, true) ? Statement(t, x2) : null; return n; case SWITCH: // This allows CASEs after a DEFAULT, which is in the standard. n = new Node(t, { cases: [], defaultIndex: -1 }); n.discriminant = HeadExpression(t, x); x2 = x.pushTarget(n).nest(); t.mustMatch(LEFT_CURLY); while ((tt = t.get()) !== RIGHT_CURLY) { switch (tt) { case DEFAULT: if (n.defaultIndex >= 0) throw t.newSyntaxError("More than one switch default"); // FALL THROUGH case CASE: n2 = new Node(t); if (tt === DEFAULT) n.defaultIndex = n.cases.length; else n2.caseLabel = Expression(t, x2, COLON); break; default: throw t.newSyntaxError("Invalid switch case"); } t.mustMatch(COLON); n2.statements = new Node(t, blockInit()); while ((tt=t.peek(true)) !== CASE && tt !== DEFAULT && tt !== RIGHT_CURLY) n2.statements.push(Statement(t, x2)); n.cases.push(n2); } return n; case FOR: n = new Node(t, LOOP_INIT); n.blockComments = comments; if (t.match(IDENTIFIER)) { if (t.token.value === "each") n.isEach = true; else t.unget(); } if (!x.parenFreeMode) t.mustMatch(LEFT_PAREN); x2 = x.pushTarget(n).nest(); x3 = x.update({ inForLoopInit: true }); n2 = null; if ((tt = t.peek(true)) !== SEMICOLON) { if (tt === VAR || tt === CONST) { t.get(); n2 = Variables(t, x3); } else if (tt === LET) { t.get(); if (t.peek() === LEFT_PAREN) { n2 = LetBlock(t, x3, false); } else { // Let in for head, we need to add an implicit block // around the rest of the for. x3.parentBlock = n; n.varDecls = []; n2 = Variables(t, x3); } } else { n2 = Expression(t, x3); } } if (n2 && t.match(IN)) { n.type = FOR_IN; n.object = Expression(t, x3); if (n2.type === VAR || n2.type === LET) { c = n2.children; // Destructuring turns one decl into multiples, so either // there must be only one destructuring or only one // decl. if (c.length !== 1 && n2.destructurings.length !== 1) { throw new SyntaxError("Invalid for..in left-hand side", t.filename, n2.lineno); } if (n2.destructurings.length > 0) { n.iterator = n2.destructurings[0]; } else { n.iterator = c[0]; } n.varDecl = n2; } else { if (n2.type === ARRAY_INIT || n2.type === OBJECT_INIT) { n2.destructuredNames = checkDestructuring(t, x3, n2); } n.iterator = n2; } } else { x3.inForLoopInit = false; n.setup = n2; t.mustMatch(SEMICOLON); if (n.isEach) throw t.newSyntaxError("Invalid for each..in loop"); n.condition = (t.peek(true) === SEMICOLON) ? null : Expression(t, x3); t.mustMatch(SEMICOLON); tt2 = t.peek(true); n.update = (x.parenFreeMode ? tt2 === LEFT_CURLY || definitions.isStatementStartCode[tt2] : tt2 === RIGHT_PAREN) ? null : Expression(t, x3); } if (!x.parenFreeMode) t.mustMatch(RIGHT_PAREN); n.body = Statement(t, x2); return n; case WHILE: n = new Node(t, { isLoop: true }); n.blockComments = comments; n.condition = HeadExpression(t, x); n.body = Statement(t, x.pushTarget(n).nest()); return n; case DO: n = new Node(t, { isLoop: true }); n.blockComments = comments; n.body = Statement(t, x.pushTarget(n).nest()); t.mustMatch(WHILE); n.condition = HeadExpression(t, x); if (!x.ecmaStrictMode) { //