PluginProbe
WPIDE – File Manager & Code Editor / 2.0.2
WPIDE – File Manager & Code Editor v2.0.2
3.5.8 3.5.7 2.0.14 2.0.15 2.0.16 2.0.2 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1 2.2 2.3 2.3.1 2.3.2 2.4.0 2.5 2.6 3.0 3.1 3.2 3.3 3.4 All 54 releases
wpide / ace-0.2.0 / src / worker-javascript.js

worker-javascript.js in WPIDE – File Manager & Code Editor 2.0.2, at ace-0.2.0/src/worker-javascript.js

10,594 lines 347.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 "no use strict";
2
3 var console = {
4 log: function(msg) {
5 postMessage({type: "log", data: msg});
6 }
7 };
8 var window = {
9 console: console
10 };
11
12 var normalizeModule = function(parentId, moduleName) {
13 // normalize plugin requires
14 if (moduleName.indexOf("!") !== -1) {
15 var chunks = moduleName.split("!");
16 return normalizeModule(parentId, chunks[0]) + "!" + normalizeModule(parentId, chunks[1]);
17 }
18 // normalize relative requires
19 if (moduleName.charAt(0) == ".") {
20 var base = parentId.split("/").slice(0, -1).join("/");
21 var moduleName = base + "/" + moduleName;
22
23 while(moduleName.indexOf(".") !== -1 && previous != moduleName) {
24 var previous = moduleName;
25 var moduleName = moduleName.replace(/\/\.\//, "/").replace(/[^\/]+\/\.\.\//, "");
26 }
27 }
28
29 return moduleName;
30 };
31
32 var require = function(parentId, id) {
33 var id = normalizeModule(parentId, id);
34
35 var module = require.modules[id];
36 if (module) {
37 if (!module.initialized) {
38 module.exports = module.factory().exports;
39 module.initialized = true;
40 }
41 return module.exports;
42 }
43
44 var chunks = id.split("/");
45 chunks[0] = require.tlns[chunks[0]] || chunks[0];
46 var path = chunks.join("/") + ".js";
47
48 require.id = id;
49 importScripts(path);
50 return require(parentId, id);
51 };
52
53 require.modules = {};
54 require.tlns = {};
55
56 var define = function(id, deps, factory) {
57 if (arguments.length == 2) {
58 factory = deps;
59 } else if (arguments.length == 1) {
60 factory = id;
61 id = require.id;
62 }
63
64 if (id.indexOf("text!") === 0)
65 return;
66
67 var req = function(deps, factory) {
68 return require(id, deps, factory);
69 };
70
71 require.modules[id] = {
72 factory: function() {
73 var module = {
74 exports: {}
75 };
76 var returnExports = factory(req, module.exports, module);
77 if (returnExports)
78 module.exports = returnExports;
79 return module;
80 }
81 };
82 };
83
84 function initBaseUrls(topLevelNamespaces) {
85 require.tlns = topLevelNamespaces;
86 }
87
88 function initSender() {
89
90 var EventEmitter = require(null, "ace/lib/event_emitter").EventEmitter;
91 var oop = require(null, "ace/lib/oop");
92
93 var Sender = function() {};
94
95 (function() {
96
97 oop.implement(this, EventEmitter);
98
99 this.callback = function(data, callbackId) {
100 postMessage({
101 type: "call",
102 id: callbackId,
103 data: data
104 });
105 };
106
107 this.emit = function(name, data) {
108 postMessage({
109 type: "event",
110 name: name,
111 data: data
112 });
113 };
114
115 }).call(Sender.prototype);
116
117 return new Sender();
118 }
119
120 var main;
121 var sender;
122
123 onmessage = function(e) {
124 var msg = e.data;
125 if (msg.command) {
126 main[msg.command].apply(main, msg.args);
127 }
128 else if (msg.init) {
129 initBaseUrls(msg.tlns);
130 require(null, "ace/lib/fixoldbrowsers");
131 sender = initSender();
132 var clazz = require(null, msg.module)[msg.classname];
133 main = new clazz(sender);
134 }
135 else if (msg.event && sender) {
136 sender._emit(msg.event, msg.data);
137 }
138 };
139 // vim:set ts=4 sts=4 sw=4 st:
140 // -- kriskowal Kris Kowal Copyright (C) 2009-2010 MIT License
141 // -- tlrobinson Tom Robinson Copyright (C) 2009-2010 MIT License (Narwhal Project)
142 // -- dantman Daniel Friesen Copyright(C) 2010 XXX No License Specified
143 // -- fschaefer Florian Schäfer Copyright (C) 2010 MIT License
144 // -- Irakli Gozalishvili Copyright (C) 2010 MIT License
145
146 /*!
147 Copyright (c) 2009, 280 North Inc. http://280north.com/
148 MIT License. http://github.com/280north/narwhal/blob/master/README.md
149 */
150
151 define('ace/lib/fixoldbrowsers', ['require', 'exports', 'module' , 'ace/lib/regexp', 'ace/lib/es5-shim'], function(require, exports, module) {
152 "use strict";
153
154 require("./regexp");
155 require("./es5-shim");
156
157 });/**
158 * Based on code from:
159 *
160 * XRegExp 1.5.0
161 * (c) 2007-2010 Steven Levithan
162 * MIT License
163 * <http://xregexp.com>
164 * Provides an augmented, extensible, cross-browser implementation of regular expressions,
165 * including support for additional syntax, flags, and methods
166 */
167
168 define('ace/lib/regexp', ['require', 'exports', 'module' ], function(require, exports, module) {
169 "use strict";
170
171 //---------------------------------
172 // Private variables
173 //---------------------------------
174
175 var real = {
176 exec: RegExp.prototype.exec,
177 test: RegExp.prototype.test,
178 match: String.prototype.match,
179 replace: String.prototype.replace,
180 split: String.prototype.split
181 },
182 compliantExecNpcg = real.exec.call(/()??/, "")[1] === undefined, // check `exec` handling of nonparticipating capturing groups
183 compliantLastIndexIncrement = function () {
184 var x = /^/g;
185 real.test.call(x, "");
186 return !x.lastIndex;
187 }();
188
189 //---------------------------------
190 // Overriden native methods
191 //---------------------------------
192
193 // Adds named capture support (with backreferences returned as `result.name`), and fixes two
194 // cross-browser issues per ES3:
195 // - Captured values for nonparticipating capturing groups should be returned as `undefined`,
196 // rather than the empty string.
197 // - `lastIndex` should not be incremented after zero-length matches.
198 RegExp.prototype.exec = function (str) {
199 var match = real.exec.apply(this, arguments),
200 name, r2;
201 if ( typeof(str) == 'string' && match) {
202 // Fix browsers whose `exec` methods don't consistently return `undefined` for
203 // nonparticipating capturing groups
204 if (!compliantExecNpcg && match.length > 1 && indexOf(match, "") > -1) {
205 r2 = RegExp(this.source, real.replace.call(getNativeFlags(this), "g", ""));
206 // Using `str.slice(match.index)` rather than `match[0]` in case lookahead allowed
207 // matching due to characters outside the match
208 real.replace.call(str.slice(match.index), r2, function () {
209 for (var i = 1; i < arguments.length - 2; i++) {
210 if (arguments[i] === undefined)
211 match[i] = undefined;
212 }
213 });
214 }
215 // Attach named capture properties
216 if (this._xregexp && this._xregexp.captureNames) {
217 for (var i = 1; i < match.length; i++) {
218 name = this._xregexp.captureNames[i - 1];
219 if (name)
220 match[name] = match[i];
221 }
222 }
223 // Fix browsers that increment `lastIndex` after zero-length matches
224 if (!compliantLastIndexIncrement && this.global && !match[0].length && (this.lastIndex > match.index))
225 this.lastIndex--;
226 }
227 return match;
228 };
229
230 // Don't override `test` if it won't change anything
231 if (!compliantLastIndexIncrement) {
232 // Fix browser bug in native method
233 RegExp.prototype.test = function (str) {
234 // Use the native `exec` to skip some processing overhead, even though the overriden
235 // `exec` would take care of the `lastIndex` fix
236 var match = real.exec.call(this, str);
237 // Fix browsers that increment `lastIndex` after zero-length matches
238 if (match && this.global && !match[0].length && (this.lastIndex > match.index))
239 this.lastIndex--;
240 return !!match;
241 };
242 }
243
244 //---------------------------------
245 // Private helper functions
246 //---------------------------------
247
248 function getNativeFlags (regex) {
249 return (regex.global ? "g" : "") +
250 (regex.ignoreCase ? "i" : "") +
251 (regex.multiline ? "m" : "") +
252 (regex.extended ? "x" : "") + // Proposed for ES4; included in AS3
253 (regex.sticky ? "y" : "");
254 };
255
256 function indexOf (array, item, from) {
257 if (Array.prototype.indexOf) // Use the native array method if available
258 return array.indexOf(item, from);
259 for (var i = from || 0; i < array.length; i++) {
260 if (array[i] === item)
261 return i;
262 }
263 return -1;
264 };
265
266 });
267 // vim: ts=4 sts=4 sw=4 expandtab
268 // -- kriskowal Kris Kowal Copyright (C) 2009-2011 MIT License
269 // -- tlrobinson Tom Robinson Copyright (C) 2009-2010 MIT License (Narwhal Project)
270 // -- dantman Daniel Friesen Copyright (C) 2010 XXX TODO License or CLA
271 // -- fschaefer Florian Schäfer Copyright (C) 2010 MIT License
272 // -- Gozala Irakli Gozalishvili Copyright (C) 2010 MIT License
273 // -- kitcambridge Kit Cambridge Copyright (C) 2011 MIT License
274 // -- kossnocorp Sasha Koss XXX TODO License or CLA
275 // -- bryanforbes Bryan Forbes XXX TODO License or CLA
276 // -- killdream Quildreen Motta Copyright (C) 2011 MIT Licence
277 // -- michaelficarra Michael Ficarra Copyright (C) 2011 3-clause BSD License
278 // -- sharkbrainguy Gerard Paapu Copyright (C) 2011 MIT License
279 // -- bbqsrc Brendan Molloy (C) 2011 Creative Commons Zero (public domain)
280 // -- iwyg XXX TODO License or CLA
281 // -- DomenicDenicola Domenic Denicola Copyright (C) 2011 MIT License
282 // -- xavierm02 Montillet Xavier XXX TODO License or CLA
283 // -- Raynos Raynos XXX TODO License or CLA
284 // -- samsonjs Sami Samhuri Copyright (C) 2010 MIT License
285 // -- rwldrn Rick Waldron Copyright (C) 2011 MIT License
286 // -- lexer Alexey Zakharov XXX TODO License or CLA
287
288 /*!
289 Copyright (c) 2009, 280 North Inc. http://280north.com/
290 MIT License. http://github.com/280north/narwhal/blob/master/README.md
291 */
292
293 define('ace/lib/es5-shim', ['require', 'exports', 'module' ], function(require, exports, module) {
294
295 /**
296 * Brings an environment as close to ECMAScript 5 compliance
297 * as is possible with the facilities of erstwhile engines.
298 *
299 * Annotated ES5: http://es5.github.com/ (specific links below)
300 * ES5 Spec: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
301 *
302 * @module
303 */
304
305 /*whatsupdoc*/
306
307 //
308 // Function
309 // ========
310 //
311
312 // ES-5 15.3.4.5
313 // http://es5.github.com/#x15.3.4.5
314
315 if (!Function.prototype.bind) {
316 Function.prototype.bind = function bind(that) { // .length is 1
317 // 1. Let Target be the this value.
318 var target = this;
319 // 2. If IsCallable(Target) is false, throw a TypeError exception.
320 if (typeof target != "function")
321 throw new TypeError(); // TODO message
322 // 3. Let A be a new (possibly empty) internal list of all of the
323 // argument values provided after thisArg (arg1, arg2 etc), in order.
324 // XXX slicedArgs will stand in for "A" if used
325 var args = slice.call(arguments, 1); // for normal call
326 // 4. Let F be a new native ECMAScript object.
327 // 11. Set the [[Prototype]] internal property of F to the standard
328 // built-in Function prototype object as specified in 15.3.3.1.
329 // 12. Set the [[Call]] internal property of F as described in
330 // 15.3.4.5.1.
331 // 13. Set the [[Construct]] internal property of F as described in
332 // 15.3.4.5.2.
333 // 14. Set the [[HasInstance]] internal property of F as described in
334 // 15.3.4.5.3.
335 var bound = function () {
336
337 if (this instanceof bound) {
338 // 15.3.4.5.2 [[Construct]]
339 // When the [[Construct]] internal method of a function object,
340 // F that was created using the bind function is called with a
341 // list of arguments ExtraArgs, the following steps are taken:
342 // 1. Let target be the value of F's [[TargetFunction]]
343 // internal property.
344 // 2. If target has no [[Construct]] internal method, a
345 // TypeError exception is thrown.
346 // 3. Let boundArgs be the value of F's [[BoundArgs]] internal
347 // property.
348 // 4. Let args be a new list containing the same values as the
349 // list boundArgs in the same order followed by the same
350 // values as the list ExtraArgs in the same order.
351 // 5. Return the result of calling the [[Construct]] internal
352 // method of target providing args as the arguments.
353
354 var F = function(){};
355 F.prototype = target.prototype;
356 var self = new F;
357
358 var result = target.apply(
359 self,
360 args.concat(slice.call(arguments))
361 );
362 if (result !== null && Object(result) === result)
363 return result;
364 return self;
365
366 } else {
367 // 15.3.4.5.1 [[Call]]
368 // When the [[Call]] internal method of a function object, F,
369 // which was created using the bind function is called with a
370 // this value and a list of arguments ExtraArgs, the following
371 // steps are taken:
372 // 1. Let boundArgs be the value of F's [[BoundArgs]] internal
373 // property.
374 // 2. Let boundThis be the value of F's [[BoundThis]] internal
375 // property.
376 // 3. Let target be the value of F's [[TargetFunction]] internal
377 // property.
378 // 4. Let args be a new list containing the same values as the
379 // list boundArgs in the same order followed by the same
380 // values as the list ExtraArgs in the same order.
381 // 5. Return the result of calling the [[Call]] internal method
382 // of target providing boundThis as the this value and
383 // providing args as the arguments.
384
385 // equiv: target.call(this, ...boundArgs, ...args)
386 return target.apply(
387 that,
388 args.concat(slice.call(arguments))
389 );
390
391 }
392
393 };
394 // XXX bound.length is never writable, so don't even try
395 //
396 // 15. If the [[Class]] internal property of Target is "Function", then
397 // a. Let L be the length property of Target minus the length of A.
398 // b. Set the length own property of F to either 0 or L, whichever is
399 // larger.
400 // 16. Else set the length own property of F to 0.
401 // 17. Set the attributes of the length own property of F to the values
402 // specified in 15.3.5.1.
403
404 // TODO
405 // 18. Set the [[Extensible]] internal property of F to true.
406
407 // TODO
408 // 19. Let thrower be the [[ThrowTypeError]] function Object (13.2.3).
409 // 20. Call the [[DefineOwnProperty]] internal method of F with
410 // arguments "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]:
411 // thrower, [[Enumerable]]: false, [[Configurable]]: false}, and
412 // false.
413 // 21. Call the [[DefineOwnProperty]] internal method of F with
414 // arguments "arguments", PropertyDescriptor {[[Get]]: thrower,
415 // [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false},
416 // and false.
417
418 // TODO
419 // NOTE Function objects created using Function.prototype.bind do not
420 // have a prototype property or the [[Code]], [[FormalParameters]], and
421 // [[Scope]] internal properties.
422 // XXX can't delete prototype in pure-js.
423
424 // 22. Return F.
425 return bound;
426 };
427 }
428
429 // Shortcut to an often accessed properties, in order to avoid multiple
430 // dereference that costs universally.
431 // _Please note: Shortcuts are defined after `Function.prototype.bind` as we
432 // us it in defining shortcuts.
433 var call = Function.prototype.call;
434 var prototypeOfArray = Array.prototype;
435 var prototypeOfObject = Object.prototype;
436 var slice = prototypeOfArray.slice;
437 var toString = call.bind(prototypeOfObject.toString);
438 var owns = call.bind(prototypeOfObject.hasOwnProperty);
439
440 // If JS engine supports accessors creating shortcuts.
441 var defineGetter;
442 var defineSetter;
443 var lookupGetter;
444 var lookupSetter;
445 var supportsAccessors;
446 if ((supportsAccessors = owns(prototypeOfObject, "__defineGetter__"))) {
447 defineGetter = call.bind(prototypeOfObject.__defineGetter__);
448 defineSetter = call.bind(prototypeOfObject.__defineSetter__);
449 lookupGetter = call.bind(prototypeOfObject.__lookupGetter__);
450 lookupSetter = call.bind(prototypeOfObject.__lookupSetter__);
451 }
452
453 //
454 // Array
455 // =====
456 //
457
458 // ES5 15.4.3.2
459 // http://es5.github.com/#x15.4.3.2
460 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/isArray
461 if (!Array.isArray) {
462 Array.isArray = function isArray(obj) {
463 return toString(obj) == "[object Array]";
464 };
465 }
466
467 // The IsCallable() check in the Array functions
468 // has been replaced with a strict check on the
469 // internal class of the object to trap cases where
470 // the provided function was actually a regular
471 // expression literal, which in V8 and
472 // JavaScriptCore is a typeof "function". Only in
473 // V8 are regular expression literals permitted as
474 // reduce parameters, so it is desirable in the
475 // general case for the shim to match the more
476 // strict and common behavior of rejecting regular
477 // expressions.
478
479 // ES5 15.4.4.18
480 // http://es5.github.com/#x15.4.4.18
481 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/forEach
482 if (!Array.prototype.forEach) {
483 Array.prototype.forEach = function forEach(fun /*, thisp*/) {
484 var self = toObject(this),
485 thisp = arguments[1],
486 i = 0,
487 length = self.length >>> 0;
488
489 // If no callback function or if callback is not a callable function
490 if (toString(fun) != "[object Function]") {
491 throw new TypeError(); // TODO message
492 }
493
494 while (i < length) {
495 if (i in self) {
496 // Invoke the callback function with call, passing arguments:
497 // context, property value, property key, thisArg object context
498 fun.call(thisp, self[i], i, self);
499 }
500 i++;
501 }
502 };
503 }
504
505 // ES5 15.4.4.19
506 // http://es5.github.com/#x15.4.4.19
507 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map
508 if (!Array.prototype.map) {
509 Array.prototype.map = function map(fun /*, thisp*/) {
510 var self = toObject(this),
511 length = self.length >>> 0,
512 result = Array(length),
513 thisp = arguments[1];
514
515 // If no callback function or if callback is not a callable function
516 if (toString(fun) != "[object Function]") {
517 throw new TypeError(); // TODO message
518 }
519
520 for (var i = 0; i < length; i++) {
521 if (i in self)
522 result[i] = fun.call(thisp, self[i], i, self);
523 }
524 return result;
525 };
526 }
527
528 // ES5 15.4.4.20
529 // http://es5.github.com/#x15.4.4.20
530 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/filter
531 if (!Array.prototype.filter) {
532 Array.prototype.filter = function filter(fun /*, thisp */) {
533 var self = toObject(this),
534 length = self.length >>> 0,
535 result = [],
536 thisp = arguments[1];
537
538 // If no callback function or if callback is not a callable function
539 if (toString(fun) != "[object Function]") {
540 throw new TypeError(); // TODO message
541 }
542
543 for (var i = 0; i < length; i++) {
544 if (i in self && fun.call(thisp, self[i], i, self))
545 result.push(self[i]);
546 }
547 return result;
548 };
549 }
550
551 // ES5 15.4.4.16
552 // http://es5.github.com/#x15.4.4.16
553 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/every
554 if (!Array.prototype.every) {
555 Array.prototype.every = function every(fun /*, thisp */) {
556 var self = toObject(this),
557 length = self.length >>> 0,
558 thisp = arguments[1];
559
560 // If no callback function or if callback is not a callable function
561 if (toString(fun) != "[object Function]") {
562 throw new TypeError(); // TODO message
563 }
564
565 for (var i = 0; i < length; i++) {
566 if (i in self && !fun.call(thisp, self[i], i, self))
567 return false;
568 }
569 return true;
570 };
571 }
572
573 // ES5 15.4.4.17
574 // http://es5.github.com/#x15.4.4.17
575 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some
576 if (!Array.prototype.some) {
577 Array.prototype.some = function some(fun /*, thisp */) {
578 var self = toObject(this),
579 length = self.length >>> 0,
580 thisp = arguments[1];
581
582 // If no callback function or if callback is not a callable function
583 if (toString(fun) != "[object Function]") {
584 throw new TypeError(); // TODO message
585 }
586
587 for (var i = 0; i < length; i++) {
588 if (i in self && fun.call(thisp, self[i], i, self))
589 return true;
590 }
591 return false;
592 };
593 }
594
595 // ES5 15.4.4.21
596 // http://es5.github.com/#x15.4.4.21
597 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduce
598 if (!Array.prototype.reduce) {
599 Array.prototype.reduce = function reduce(fun /*, initial*/) {
600 var self = toObject(this),
601 length = self.length >>> 0;
602
603 // If no callback function or if callback is not a callable function
604 if (toString(fun) != "[object Function]") {
605 throw new TypeError(); // TODO message
606 }
607
608 // no value to return if no initial value and an empty array
609 if (!length && arguments.length == 1)
610 throw new TypeError(); // TODO message
611
612 var i = 0;
613 var result;
614 if (arguments.length >= 2) {
615 result = arguments[1];
616 } else {
617 do {
618 if (i in self) {
619 result = self[i++];
620 break;
621 }
622
623 // if array contains no values, no initial value to return
624 if (++i >= length)
625 throw new TypeError(); // TODO message
626 } while (true);
627 }
628
629 for (; i < length; i++) {
630 if (i in self)
631 result = fun.call(void 0, result, self[i], i, self);
632 }
633
634 return result;
635 };
636 }
637
638 // ES5 15.4.4.22
639 // http://es5.github.com/#x15.4.4.22
640 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduceRight
641 if (!Array.prototype.reduceRight) {
642 Array.prototype.reduceRight = function reduceRight(fun /*, initial*/) {
643 var self = toObject(this),
644 length = self.length >>> 0;
645
646 // If no callback function or if callback is not a callable function
647 if (toString(fun) != "[object Function]") {
648 throw new TypeError(); // TODO message
649 }
650
651 // no value to return if no initial value, empty array
652 if (!length && arguments.length == 1)
653 throw new TypeError(); // TODO message
654
655 var result, i = length - 1;
656 if (arguments.length >= 2) {
657 result = arguments[1];
658 } else {
659 do {
660 if (i in self) {
661 result = self[i--];
662 break;
663 }
664
665 // if array contains no values, no initial value to return
666 if (--i < 0)
667 throw new TypeError(); // TODO message
668 } while (true);
669 }
670
671 do {
672 if (i in this)
673 result = fun.call(void 0, result, self[i], i, self);
674 } while (i--);
675
676 return result;
677 };
678 }
679
680 // ES5 15.4.4.14
681 // http://es5.github.com/#x15.4.4.14
682 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf
683 if (!Array.prototype.indexOf) {
684 Array.prototype.indexOf = function indexOf(sought /*, fromIndex */ ) {
685 var self = toObject(this),
686 length = self.length >>> 0;
687
688 if (!length)
689 return -1;
690
691 var i = 0;
692 if (arguments.length > 1)
693 i = toInteger(arguments[1]);
694
695 // handle negative indices
696 i = i >= 0 ? i : Math.max(0, length + i);
697 for (; i < length; i++) {
698 if (i in self && self[i] === sought) {
699 return i;
700 }
701 }
702 return -1;
703 };
704 }
705
706 // ES5 15.4.4.15
707 // http://es5.github.com/#x15.4.4.15
708 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/lastIndexOf
709 if (!Array.prototype.lastIndexOf) {
710 Array.prototype.lastIndexOf = function lastIndexOf(sought /*, fromIndex */) {
711 var self = toObject(this),
712 length = self.length >>> 0;
713
714 if (!length)
715 return -1;
716 var i = length - 1;
717 if (arguments.length > 1)
718 i = Math.min(i, toInteger(arguments[1]));
719 // handle negative indices
720 i = i >= 0 ? i : length - Math.abs(i);
721 for (; i >= 0; i--) {
722 if (i in self && sought === self[i])
723 return i;
724 }
725 return -1;
726 };
727 }
728
729 //
730 // Object
731 // ======
732 //
733
734 // ES5 15.2.3.2
735 // http://es5.github.com/#x15.2.3.2
736 if (!Object.getPrototypeOf) {
737 // https://github.com/kriskowal/es5-shim/issues#issue/2
738 // http://ejohn.org/blog/objectgetprototypeof/
739 // recommended by fschaefer on github
740 Object.getPrototypeOf = function getPrototypeOf(object) {
741 return object.__proto__ || (
742 object.constructor ?
743 object.constructor.prototype :
744 prototypeOfObject
745 );
746 };
747 }
748
749 // ES5 15.2.3.3
750 // http://es5.github.com/#x15.2.3.3
751 if (!Object.getOwnPropertyDescriptor) {
752 var ERR_NON_OBJECT = "Object.getOwnPropertyDescriptor called on a " +
753 "non-object: ";
754 Object.getOwnPropertyDescriptor = function getOwnPropertyDescriptor(object, property) {
755 if ((typeof object != "object" && typeof object != "function") || object === null)
756 throw new TypeError(ERR_NON_OBJECT + object);
757 // If object does not owns property return undefined immediately.
758 if (!owns(object, property))
759 return;
760
761 var descriptor, getter, setter;
762
763 // If object has a property then it's for sure both `enumerable` and
764 // `configurable`.
765 descriptor = { enumerable: true, configurable: true };
766
767 // If JS engine supports accessor properties then property may be a
768 // getter or setter.
769 if (supportsAccessors) {
770 // Unfortunately `__lookupGetter__` will return a getter even
771 // if object has own non getter property along with a same named
772 // inherited getter. To avoid misbehavior we temporary remove
773 // `__proto__` so that `__lookupGetter__` will return getter only
774 // if it's owned by an object.
775 var prototype = object.__proto__;
776 object.__proto__ = prototypeOfObject;
777
778 var getter = lookupGetter(object, property);
779 var setter = lookupSetter(object, property);
780
781 // Once we have getter and setter we can put values back.
782 object.__proto__ = prototype;
783
784 if (getter || setter) {
785 if (getter) descriptor.get = getter;
786 if (setter) descriptor.set = setter;
787
788 // If it was accessor property we're done and return here
789 // in order to avoid adding `value` to the descriptor.
790 return descriptor;
791 }
792 }
793
794 // If we got this far we know that object has an own property that is
795 // not an accessor so we set it as a value and return descriptor.
796 descriptor.value = object[property];
797 return descriptor;
798 };
799 }
800
801 // ES5 15.2.3.4
802 // http://es5.github.com/#x15.2.3.4
803 if (!Object.getOwnPropertyNames) {
804 Object.getOwnPropertyNames = function getOwnPropertyNames(object) {
805 return Object.keys(object);
806 };
807 }
808
809 // ES5 15.2.3.5
810 // http://es5.github.com/#x15.2.3.5
811 if (!Object.create) {
812 Object.create = function create(prototype, properties) {
813 var object;
814 if (prototype === null) {
815 object = { "__proto__": null };
816 } else {
817 if (typeof prototype != "object")
818 throw new TypeError("typeof prototype["+(typeof prototype)+"] != 'object'");
819 var Type = function () {};
820 Type.prototype = prototype;
821 object = new Type();
822 // IE has no built-in implementation of `Object.getPrototypeOf`
823 // neither `__proto__`, but this manually setting `__proto__` will
824 // guarantee that `Object.getPrototypeOf` will work as expected with
825 // objects created using `Object.create`
826 object.__proto__ = prototype;
827 }
828 if (properties !== void 0)
829 Object.defineProperties(object, properties);
830 return object;
831 };
832 }
833
834 // ES5 15.2.3.6
835 // http://es5.github.com/#x15.2.3.6
836
837 // Patch for WebKit and IE8 standard mode
838 // Designed by hax <hax.github.com>
839 // related issue: https://github.com/kriskowal/es5-shim/issues#issue/5
840 // IE8 Reference:
841 // http://msdn.microsoft.com/en-us/library/dd282900.aspx
842 // http://msdn.microsoft.com/en-us/library/dd229916.aspx
843 // WebKit Bugs:
844 // https://bugs.webkit.org/show_bug.cgi?id=36423
845
846 function doesDefinePropertyWork(object) {
847 try {
848 Object.defineProperty(object, "sentinel", {});
849 return "sentinel" in object;
850 } catch (exception) {
851 // returns falsy
852 }
853 }
854
855 // check whether defineProperty works if it's given. Otherwise,
856 // shim partially.
857 if (Object.defineProperty) {
858 var definePropertyWorksOnObject = doesDefinePropertyWork({});
859 var definePropertyWorksOnDom = typeof document == "undefined" ||
860 doesDefinePropertyWork(document.createElement("div"));
861 if (!definePropertyWorksOnObject || !definePropertyWorksOnDom) {
862 var definePropertyFallback = Object.defineProperty;
863 }
864 }
865
866 if (!Object.defineProperty || definePropertyFallback) {
867 var ERR_NON_OBJECT_DESCRIPTOR = "Property description must be an object: ";
868 var ERR_NON_OBJECT_TARGET = "Object.defineProperty called on non-object: "
869 var ERR_ACCESSORS_NOT_SUPPORTED = "getters & setters can not be defined " +
870 "on this javascript engine";
871
872 Object.defineProperty = function defineProperty(object, property, descriptor) {
873 if ((typeof object != "object" && typeof object != "function") || object === null)
874 throw new TypeError(ERR_NON_OBJECT_TARGET + object);
875 if ((typeof descriptor != "object" && typeof descriptor != "function") || descriptor === null)
876 throw new TypeError(ERR_NON_OBJECT_DESCRIPTOR + descriptor);
877
878 // make a valiant attempt to use the real defineProperty
879 // for I8's DOM elements.
880 if (definePropertyFallback) {
881 try {
882 return definePropertyFallback.call(Object, object, property, descriptor);
883 } catch (exception) {
884 // try the shim if the real one doesn't work
885 }
886 }
887
888 // If it's a data property.
889 if (owns(descriptor, "value")) {
890 // fail silently if "writable", "enumerable", or "configurable"
891 // are requested but not supported
892 /*
893 // alternate approach:
894 if ( // can't implement these features; allow false but not true
895 !(owns(descriptor, "writable") ? descriptor.writable : true) ||
896 !(owns(descriptor, "enumerable") ? descriptor.enumerable : true) ||
897 !(owns(descriptor, "configurable") ? descriptor.configurable : true)
898 )
899 throw new RangeError(
900 "This implementation of Object.defineProperty does not " +
901 "support configurable, enumerable, or writable."
902 );
903 */
904
905 if (supportsAccessors && (lookupGetter(object, property) ||
906 lookupSetter(object, property)))
907 {
908 // As accessors are supported only on engines implementing
909 // `__proto__` we can safely override `__proto__` while defining
910 // a property to make sure that we don't hit an inherited
911 // accessor.
912 var prototype = object.__proto__;
913 object.__proto__ = prototypeOfObject;
914 // Deleting a property anyway since getter / setter may be
915 // defined on object itself.
916 delete object[property];
917 object[property] = descriptor.value;
918 // Setting original `__proto__` back now.
919 object.__proto__ = prototype;
920 } else {
921 object[property] = descriptor.value;
922 }
923 } else {
924 if (!supportsAccessors)
925 throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED);
926 // If we got that far then getters and setters can be defined !!
927 if (owns(descriptor, "get"))
928 defineGetter(object, property, descriptor.get);
929 if (owns(descriptor, "set"))
930 defineSetter(object, property, descriptor.set);
931 }
932
933 return object;
934 };
935 }
936
937 // ES5 15.2.3.7
938 // http://es5.github.com/#x15.2.3.7
939 if (!Object.defineProperties) {
940 Object.defineProperties = function defineProperties(object, properties) {
941 for (var property in properties) {
942 if (owns(properties, property))
943 Object.defineProperty(object, property, properties[property]);
944 }
945 return object;
946 };
947 }
948
949 // ES5 15.2.3.8
950 // http://es5.github.com/#x15.2.3.8
951 if (!Object.seal) {
952 Object.seal = function seal(object) {
953 // this is misleading and breaks feature-detection, but
954 // allows "securable" code to "gracefully" degrade to working
955 // but insecure code.
956 return object;
957 };
958 }
959
960 // ES5 15.2.3.9
961 // http://es5.github.com/#x15.2.3.9
962 if (!Object.freeze) {
963 Object.freeze = function freeze(object) {
964 // this is misleading and breaks feature-detection, but
965 // allows "securable" code to "gracefully" degrade to working
966 // but insecure code.
967 return object;
968 };
969 }
970
971 // detect a Rhino bug and patch it
972 try {
973 Object.freeze(function () {});
974 } catch (exception) {
975 Object.freeze = (function freeze(freezeObject) {
976 return function freeze(object) {
977 if (typeof object == "function") {
978 return object;
979 } else {
980 return freezeObject(object);
981 }
982 };
983 })(Object.freeze);
984 }
985
986 // ES5 15.2.3.10
987 // http://es5.github.com/#x15.2.3.10
988 if (!Object.preventExtensions) {
989 Object.preventExtensions = function preventExtensions(object) {
990 // this is misleading and breaks feature-detection, but
991 // allows "securable" code to "gracefully" degrade to working
992 // but insecure code.
993 return object;
994 };
995 }
996
997 // ES5 15.2.3.11
998 // http://es5.github.com/#x15.2.3.11
999 if (!Object.isSealed) {
1000 Object.isSealed = function isSealed(object) {
1001 return false;
1002 };
1003 }
1004
1005 // ES5 15.2.3.12
1006 // http://es5.github.com/#x15.2.3.12
1007 if (!Object.isFrozen) {
1008 Object.isFrozen = function isFrozen(object) {
1009 return false;
1010 };
1011 }
1012
1013 // ES5 15.2.3.13
1014 // http://es5.github.com/#x15.2.3.13
1015 if (!Object.isExtensible) {
1016 Object.isExtensible = function isExtensible(object) {
1017 // 1. If Type(O) is not Object throw a TypeError exception.
1018 if (Object(object) === object) {
1019 throw new TypeError(); // TODO message
1020 }
1021 // 2. Return the Boolean value of the [[Extensible]] internal property of O.
1022 var name = '';
1023 while (owns(object, name)) {
1024 name += '?';
1025 }
1026 object[name] = true;
1027 var returnValue = owns(object, name);
1028 delete object[name];
1029 return returnValue;
1030 };
1031 }
1032
1033 // ES5 15.2.3.14
1034 // http://es5.github.com/#x15.2.3.14
1035 if (!Object.keys) {
1036 // http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation
1037 var hasDontEnumBug = true,
1038 dontEnums = [
1039 "toString",
1040 "toLocaleString",
1041 "valueOf",
1042 "hasOwnProperty",
1043 "isPrototypeOf",
1044 "propertyIsEnumerable",
1045 "constructor"
1046 ],
1047 dontEnumsLength = dontEnums.length;
1048
1049 for (var key in {"toString": null})
1050 hasDontEnumBug = false;
1051
1052 Object.keys = function keys(object) {
1053
1054 if ((typeof object != "object" && typeof object != "function") || object === null)
1055 throw new TypeError("Object.keys called on a non-object");
1056
1057 var keys = [];
1058 for (var name in object) {
1059 if (owns(object, name)) {
1060 keys.push(name);
1061 }
1062 }
1063
1064 if (hasDontEnumBug) {
1065 for (var i = 0, ii = dontEnumsLength; i < ii; i++) {
1066 var dontEnum = dontEnums[i];
1067 if (owns(object, dontEnum)) {
1068 keys.push(dontEnum);
1069 }
1070 }
1071 }
1072
1073 return keys;
1074 };
1075
1076 }
1077
1078 //
1079 // Date
1080 // ====
1081 //
1082
1083 // ES5 15.9.5.43
1084 // http://es5.github.com/#x15.9.5.43
1085 // This function returns a String value represent the instance in time
1086 // represented by this Date object. The format of the String is the Date Time
1087 // string format defined in 15.9.1.15. All fields are present in the String.
1088 // The time zone is always UTC, denoted by the suffix Z. If the time value of
1089 // this object is not a finite Number a RangeError exception is thrown.
1090 if (!Date.prototype.toISOString || (new Date(-62198755200000).toISOString().indexOf('-000001') === -1)) {
1091 Date.prototype.toISOString = function toISOString() {
1092 var result, length, value, year;
1093 if (!isFinite(this))
1094 throw new RangeError;
1095
1096 // the date time string format is specified in 15.9.1.15.
1097 result = [this.getUTCMonth() + 1, this.getUTCDate(),
1098 this.getUTCHours(), this.getUTCMinutes(), this.getUTCSeconds()];
1099 year = this.getUTCFullYear();
1100 year = (year < 0 ? '-' : (year > 9999 ? '+' : '')) + ('00000' + Math.abs(year)).slice(0 <= year && year <= 9999 ? -4 : -6);
1101
1102 length = result.length;
1103 while (length--) {
1104 value = result[length];
1105 // pad months, days, hours, minutes, and seconds to have two digits.
1106 if (value < 10)
1107 result[length] = "0" + value;
1108 }
1109 // pad milliseconds to have three digits.
1110 return year + "-" + result.slice(0, 2).join("-") + "T" + result.slice(2).join(":") + "." +
1111 ("000" + this.getUTCMilliseconds()).slice(-3) + "Z";
1112 }
1113 }
1114
1115 // ES5 15.9.4.4
1116 // http://es5.github.com/#x15.9.4.4
1117 if (!Date.now) {
1118 Date.now = function now() {
1119 return new Date().getTime();
1120 };
1121 }
1122
1123 // ES5 15.9.5.44
1124 // http://es5.github.com/#x15.9.5.44
1125 // This function provides a String representation of a Date object for use by
1126 // JSON.stringify (15.12.3).
1127 if (!Date.prototype.toJSON) {
1128 Date.prototype.toJSON = function toJSON(key) {
1129 // When the toJSON method is called with argument key, the following
1130 // steps are taken:
1131
1132 // 1. Let O be the result of calling ToObject, giving it the this
1133 // value as its argument.
1134 // 2. Let tv be ToPrimitive(O, hint Number).
1135 // 3. If tv is a Number and is not finite, return null.
1136 // XXX
1137 // 4. Let toISO be the result of calling the [[Get]] internal method of
1138 // O with argument "toISOString".
1139 // 5. If IsCallable(toISO) is false, throw a TypeError exception.
1140 if (typeof this.toISOString != "function")
1141 throw new TypeError(); // TODO message
1142 // 6. Return the result of calling the [[Call]] internal method of
1143 // toISO with O as the this value and an empty argument list.
1144 return this.toISOString();
1145
1146 // NOTE 1 The argument is ignored.
1147
1148 // NOTE 2 The toJSON function is intentionally generic; it does not
1149 // require that its this value be a Date object. Therefore, it can be
1150 // transferred to other kinds of objects for use as a method. However,
1151 // it does require that any such object have a toISOString method. An
1152 // object is free to use the argument key to filter its
1153 // stringification.
1154 };
1155 }
1156
1157 // ES5 15.9.4.2
1158 // http://es5.github.com/#x15.9.4.2
1159 // based on work shared by Daniel Friesen (dantman)
1160 // http://gist.github.com/303249
1161 if (Date.parse("+275760-09-13T00:00:00.000Z") !== 8.64e15) {
1162 // XXX global assignment won't work in embeddings that use
1163 // an alternate object for the context.
1164 Date = (function(NativeDate) {
1165
1166 // Date.length === 7
1167 var Date = function Date(Y, M, D, h, m, s, ms) {
1168 var length = arguments.length;
1169 if (this instanceof NativeDate) {
1170 var date = length == 1 && String(Y) === Y ? // isString(Y)
1171 // We explicitly pass it through parse:
1172 new NativeDate(Date.parse(Y)) :
1173 // We have to manually make calls depending on argument
1174 // length here
1175 length >= 7 ? new NativeDate(Y, M, D, h, m, s, ms) :
1176 length >= 6 ? new NativeDate(Y, M, D, h, m, s) :
1177 length >= 5 ? new NativeDate(Y, M, D, h, m) :
1178 length >= 4 ? new NativeDate(Y, M, D, h) :
1179 length >= 3 ? new NativeDate(Y, M, D) :
1180 length >= 2 ? new NativeDate(Y, M) :
1181 length >= 1 ? new NativeDate(Y) :
1182 new NativeDate();
1183 // Prevent mixups with unfixed Date object
1184 date.constructor = Date;
1185 return date;
1186 }
1187 return NativeDate.apply(this, arguments);
1188 };
1189
1190 // 15.9.1.15 Date Time String Format.
1191 var isoDateExpression = new RegExp("^" +
1192 "(\\d{4}|[\+\-]\\d{6})" + // four-digit year capture or sign + 6-digit extended year
1193 "(?:-(\\d{2})" + // optional month capture
1194 "(?:-(\\d{2})" + // optional day capture
1195 "(?:" + // capture hours:minutes:seconds.milliseconds
1196 "T(\\d{2})" + // hours capture
1197 ":(\\d{2})" + // minutes capture
1198 "(?:" + // optional :seconds.milliseconds
1199 ":(\\d{2})" + // seconds capture
1200 "(?:\\.(\\d{3}))?" + // milliseconds capture
1201 ")?" +
1202 "(?:" + // capture UTC offset component
1203 "Z|" + // UTC capture
1204 "(?:" + // offset specifier +/-hours:minutes
1205 "([-+])" + // sign capture
1206 "(\\d{2})" + // hours offset capture
1207 ":(\\d{2})" + // minutes offset capture
1208 ")" +
1209 ")?)?)?)?" +
1210 "$");
1211
1212 // Copy any custom methods a 3rd party library may have added
1213 for (var key in NativeDate)
1214 Date[key] = NativeDate[key];
1215
1216 // Copy "native" methods explicitly; they may be non-enumerable
1217 Date.now = NativeDate.now;
1218 Date.UTC = NativeDate.UTC;
1219 Date.prototype = NativeDate.prototype;
1220 Date.prototype.constructor = Date;
1221
1222 // Upgrade Date.parse to handle simplified ISO 8601 strings
1223 Date.parse = function parse(string) {
1224 var match = isoDateExpression.exec(string);
1225 if (match) {
1226 match.shift(); // kill match[0], the full match
1227 // parse months, days, hours, minutes, seconds, and milliseconds
1228 for (var i = 1; i < 7; i++) {
1229 // provide default values if necessary
1230 match[i] = +(match[i] || (i < 3 ? 1 : 0));
1231 // match[1] is the month. Months are 0-11 in JavaScript
1232 // `Date` objects, but 1-12 in ISO notation, so we
1233 // decrement.
1234 if (i == 1)
1235 match[i]--;
1236 }
1237
1238 // parse the UTC offset component
1239 var minuteOffset = +match.pop(), hourOffset = +match.pop(), sign = match.pop();
1240
1241 // compute the explicit time zone offset if specified
1242 var offset = 0;
1243 if (sign) {
1244 // detect invalid offsets and return early
1245 if (hourOffset > 23 || minuteOffset > 59)
1246 return NaN;
1247
1248 // express the provided time zone offset in minutes. The offset is
1249 // negative for time zones west of UTC; positive otherwise.
1250 offset = (hourOffset * 60 + minuteOffset) * 6e4 * (sign == "+" ? -1 : 1);
1251 }
1252
1253 // Date.UTC for years between 0 and 99 converts year to 1900 + year
1254 // The Gregorian calendar has a 400-year cycle, so
1255 // to Date.UTC(year + 400, .... ) - 12622780800000 == Date.UTC(year, ...),
1256 // where 12622780800000 - number of milliseconds in Gregorian calendar 400 years
1257 var year = +match[0];
1258 if (0 <= year && year <= 99) {
1259 match[0] = year + 400;
1260 return NativeDate.UTC.apply(this, match) + offset - 12622780800000;
1261 }
1262
1263 // compute a new UTC date value, accounting for the optional offset
1264 return NativeDate.UTC.apply(this, match) + offset;
1265 }
1266 return NativeDate.parse.apply(this, arguments);
1267 };
1268
1269 return Date;
1270 })(Date);
1271 }
1272
1273 //
1274 // String
1275 // ======
1276 //
1277
1278 // ES5 15.5.4.20
1279 // http://es5.github.com/#x15.5.4.20
1280 var ws = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003" +
1281 "\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028" +
1282 "\u2029\uFEFF";
1283 if (!String.prototype.trim || ws.trim()) {
1284 // http://blog.stevenlevithan.com/archives/faster-trim-javascript
1285 // http://perfectionkills.com/whitespace-deviations/
1286 ws = "[" + ws + "]";
1287 var trimBeginRegexp = new RegExp("^" + ws + ws + "*"),
1288 trimEndRegexp = new RegExp(ws + ws + "*$");
1289 String.prototype.trim = function trim() {
1290 return String(this).replace(trimBeginRegexp, "").replace(trimEndRegexp, "");
1291 };
1292 }
1293
1294 //
1295 // Util
1296 // ======
1297 //
1298
1299 // ES5 9.4
1300 // http://es5.github.com/#x9.4
1301 // http://jsperf.com/to-integer
1302 var toInteger = function (n) {
1303 n = +n;
1304 if (n !== n) // isNaN
1305 n = 0;
1306 else if (n !== 0 && n !== (1/0) && n !== -(1/0))
1307 n = (n > 0 || -1) * Math.floor(Math.abs(n));
1308 return n;
1309 };
1310
1311 var prepareString = "a"[0] != "a",
1312 // ES5 9.9
1313 // http://es5.github.com/#x9.9
1314 toObject = function (o) {
1315 if (o == null) { // this matches both null and undefined
1316 throw new TypeError(); // TODO message
1317 }
1318 // If the implementation doesn't support by-index access of
1319 // string characters (ex. IE < 7), split the string
1320 if (prepareString && typeof o == "string" && o) {
1321 return o.split("");
1322 }
1323 return Object(o);
1324 };
1325 });/* vim:ts=4:sts=4:sw=4:
1326 * ***** BEGIN LICENSE BLOCK *****
1327 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
1328 *
1329 * The contents of this file are subject to the Mozilla Public License Version
1330 * 1.1 (the "License"); you may not use this file except in compliance with
1331 * the License. You may obtain a copy of the License at
1332 * http://www.mozilla.org/MPL/
1333 *
1334 * Software distributed under the License is distributed on an "AS IS" basis,
1335 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
1336 * for the specific language governing rights and limitations under the
1337 * License.
1338 *
1339 * The Original Code is Ajax.org Code Editor (ACE).
1340 *
1341 * The Initial Developer of the Original Code is
1342 * Ajax.org B.V.
1343 * Portions created by the Initial Developer are Copyright (C) 2010
1344 * the Initial Developer. All Rights Reserved.
1345 *
1346 * Contributor(s):
1347 * Fabian Jakobs <fabian AT ajax DOT org>
1348 * Irakli Gozalishvili <rfobic@gmail.com> (http://jeditoolkit.com)
1349 * Mike de Boer <mike AT ajax DOT org>
1350 *
1351 * Alternatively, the contents of this file may be used under the terms of
1352 * either the GNU General Public License Version 2 or later (the "GPL"), or
1353 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
1354 * in which case the provisions of the GPL or the LGPL are applicable instead
1355 * of those above. If you wish to allow use of your version of this file only
1356 * under the terms of either the GPL or the LGPL, and not to allow others to
1357 * use your version of this file under the terms of the MPL, indicate your
1358 * decision by deleting the provisions above and replace them with the notice
1359 * and other provisions required by the GPL or the LGPL. If you do not delete
1360 * the provisions above, a recipient may use your version of this file under
1361 * the terms of any one of the MPL, the GPL or the LGPL.
1362 *
1363 * ***** END LICENSE BLOCK ***** */
1364
1365 define('ace/lib/event_emitter', ['require', 'exports', 'module' ], function(require, exports, module) {
1366 "use strict";
1367
1368 var EventEmitter = {};
1369
1370 EventEmitter._emit =
1371 EventEmitter._dispatchEvent = function(eventName, e) {
1372 this._eventRegistry = this._eventRegistry || {};
1373 this._defaultHandlers = this._defaultHandlers || {};
1374
1375 var listeners = this._eventRegistry[eventName] || [];
1376 var defaultHandler = this._defaultHandlers[eventName];
1377 if (!listeners.length && !defaultHandler)
1378 return;
1379
1380 e = e || {};
1381 e.type = eventName;
1382
1383 if (!e.stopPropagation) {
1384 e.stopPropagation = function() {
1385 this.propagationStopped = true;
1386 };
1387 }
1388
1389 if (!e.preventDefault) {
1390 e.preventDefault = function() {
1391 this.defaultPrevented = true;
1392 };
1393 }
1394
1395 for (var i=0; i<listeners.length; i++) {
1396 listeners[i](e);
1397 if (e.propagationStopped)
1398 break;
1399 }
1400
1401 if (defaultHandler && !e.defaultPrevented)
1402 defaultHandler(e);
1403 };
1404
1405 EventEmitter.setDefaultHandler = function(eventName, callback) {
1406 this._defaultHandlers = this._defaultHandlers || {};
1407
1408 if (this._defaultHandlers[eventName])
1409 throw new Error("The default handler for '" + eventName + "' is already set");
1410
1411 this._defaultHandlers[eventName] = callback;
1412 };
1413
1414 EventEmitter.on =
1415 EventEmitter.addEventListener = function(eventName, callback) {
1416 this._eventRegistry = this._eventRegistry || {};
1417
1418 var listeners = this._eventRegistry[eventName];
1419 if (!listeners)
1420 var listeners = this._eventRegistry[eventName] = [];
1421
1422 if (listeners.indexOf(callback) == -1)
1423 listeners.push(callback);
1424 };
1425
1426 EventEmitter.removeListener =
1427 EventEmitter.removeEventListener = function(eventName, callback) {
1428 this._eventRegistry = this._eventRegistry || {};
1429
1430 var listeners = this._eventRegistry[eventName];
1431 if (!listeners)
1432 return;
1433
1434 var index = listeners.indexOf(callback);
1435 if (index !== -1)
1436 listeners.splice(index, 1);
1437 };
1438
1439 EventEmitter.removeAllListeners = function(eventName) {
1440 if (this._eventRegistry) this._eventRegistry[eventName] = [];
1441 };
1442
1443 exports.EventEmitter = EventEmitter;
1444
1445 });/* ***** BEGIN LICENSE BLOCK *****
1446 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
1447 *
1448 * The contents of this file are subject to the Mozilla Public License Version
1449 * 1.1 (the "License"); you may not use this file except in compliance with
1450 * the License. You may obtain a copy of the License at
1451 * http://www.mozilla.org/MPL/
1452 *
1453 * Software distributed under the License is distributed on an "AS IS" basis,
1454 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
1455 * for the specific language governing rights and limitations under the
1456 * License.
1457 *
1458 * The Original Code is Ajax.org Code Editor (ACE).
1459 *
1460 * The Initial Developer of the Original Code is
1461 * Ajax.org B.V.
1462 * Portions created by the Initial Developer are Copyright (C) 2010
1463 * the Initial Developer. All Rights Reserved.
1464 *
1465 * Contributor(s):
1466 * Fabian Jakobs <fabian AT ajax DOT org>
1467 *
1468 * Alternatively, the contents of this file may be used under the terms of
1469 * either the GNU General Public License Version 2 or later (the "GPL"), or
1470 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
1471 * in which case the provisions of the GPL or the LGPL are applicable instead
1472 * of those above. If you wish to allow use of your version of this file only
1473 * under the terms of either the GPL or the LGPL, and not to allow others to
1474 * use your version of this file under the terms of the MPL, indicate your
1475 * decision by deleting the provisions above and replace them with the notice
1476 * and other provisions required by the GPL or the LGPL. If you do not delete
1477 * the provisions above, a recipient may use your version of this file under
1478 * the terms of any one of the MPL, the GPL or the LGPL.
1479 *
1480 * ***** END LICENSE BLOCK ***** */
1481
1482 define('ace/lib/oop', ['require', 'exports', 'module' ], function(require, exports, module) {
1483 "use strict";
1484
1485 exports.inherits = (function() {
1486 var tempCtor = function() {};
1487 return function(ctor, superCtor) {
1488 tempCtor.prototype = superCtor.prototype;
1489 ctor.super_ = superCtor.prototype;
1490 ctor.prototype = new tempCtor();
1491 ctor.prototype.constructor = ctor;
1492 };
1493 }());
1494
1495 exports.mixin = function(obj, mixin) {
1496 for (var key in mixin) {
1497 obj[key] = mixin[key];
1498 }
1499 };
1500
1501 exports.implement = function(proto, mixin) {
1502 exports.mixin(proto, mixin);
1503 };
1504
1505 });
1506 /* ***** BEGIN LICENSE BLOCK *****
1507 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
1508 *
1509 * The contents of this file are subject to the Mozilla Public License Version
1510 * 1.1 (the "License"); you may not use this file except in compliance with
1511 * the License. You may obtain a copy of the License at
1512 * http://www.mozilla.org/MPL/
1513 *
1514 * Software distributed under the License is distributed on an "AS IS" basis,
1515 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
1516 * for the specific language governing rights and limitations under the
1517 * License.
1518 *
1519 * The Original Code is Ajax.org Code Editor (ACE).
1520 *
1521 * The Initial Developer of the Original Code is
1522 * Ajax.org B.V.
1523 * Portions created by the Initial Developer are Copyright (C) 2010
1524 * the Initial Developer. All Rights Reserved.
1525 *
1526 * Contributor(s):
1527 * Fabian Jakobs <fabian AT ajax DOT org>
1528 *
1529 * Alternatively, the contents of this file may be used under the terms of
1530 * either the GNU General Public License Version 2 or later (the "GPL"), or
1531 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
1532 * in which case the provisions of the GPL or the LGPL are applicable instead
1533 * of those above. If you wish to allow use of your version of this file only
1534 * under the terms of either the GPL or the LGPL, and not to allow others to
1535 * use your version of this file under the terms of the MPL, indicate your
1536 * decision by deleting the provisions above and replace them with the notice
1537 * and other provisions required by the GPL or the LGPL. If you do not delete
1538 * the provisions above, a recipient may use your version of this file under
1539 * the terms of any one of the MPL, the GPL or the LGPL.
1540 *
1541 * ***** END LICENSE BLOCK ***** */
1542
1543 define('ace/mode/javascript_worker', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/worker/mirror', 'ace/worker/jshint', 'ace/narcissus/parser'], function(require, exports, module) {
1544 "use strict";
1545
1546 var oop = require("../lib/oop");
1547 var Mirror = require("../worker/mirror").Mirror;
1548 var lint = require("../worker/jshint").JSHINT;
1549 var parser = require("../narcissus/parser");
1550
1551 var JavaScriptWorker = exports.JavaScriptWorker = function(sender) {
1552 Mirror.call(this, sender);
1553 this.setTimeout(500);
1554 };
1555
1556 oop.inherits(JavaScriptWorker, Mirror);
1557
1558 (function() {
1559
1560 this.onUpdate = function() {
1561 var value = this.doc.getValue();
1562 value = value.replace(/^#!.*\n/, "\n");
1563
1564 // var start = new Date();
1565 try {
1566 parser.parse(value);
1567 } catch(e) {
1568 // console.log("narcissus")
1569 // console.log(e);
1570 var chunks = e.message.split(":")
1571 var message = chunks.pop().trim();
1572 var lineNumber = parseInt(chunks.pop().trim()) - 1;
1573 this.sender.emit("narcissus", {
1574 row: lineNumber,
1575 column: null, // TODO convert e.cursor
1576 text: message,
1577 type: "error"
1578 });
1579 return;
1580 } finally {
1581 // console.log("parse time: " + (new Date() - start));
1582 }
1583
1584 // var start = new Date();
1585 // console.log("jslint")
1586 lint(value, {undef: false, onevar: false, passfail: false});
1587 this.sender.emit("jslint", lint.errors);
1588 // console.log("lint time: " + (new Date() - start));
1589 }
1590
1591 }).call(JavaScriptWorker.prototype);
1592
1593 });define('ace/worker/mirror', ['require', 'exports', 'module' , 'ace/document', 'ace/lib/lang'], function(require, exports, module) {
1594 "use strict";
1595
1596 var Document = require("../document").Document;
1597 var lang = require("../lib/lang");
1598
1599 var Mirror = exports.Mirror = function(sender) {
1600 this.sender = sender;
1601 var doc = this.doc = new Document("");
1602
1603 var deferredUpdate = this.deferredUpdate = lang.deferredCall(this.onUpdate.bind(this));
1604
1605 var _self = this;
1606 sender.on("change", function(e) {
1607 doc.applyDeltas([e.data]);
1608 deferredUpdate.schedule(_self.$timeout);
1609 });
1610 };
1611
1612 (function() {
1613
1614 this.$timeout = 500;
1615
1616 this.setTimeout = function(timeout) {
1617 this.$timeout = timeout;
1618 };
1619
1620 this.setValue = function(value) {
1621 this.doc.setValue(value);
1622 this.deferredUpdate.schedule(this.$timeout);
1623 };
1624
1625 this.getValue = function(callbackId) {
1626 this.sender.callback(this.doc.getValue(), callbackId);
1627 };
1628
1629 this.onUpdate = function() {
1630 // abstract method
1631 };
1632
1633 }).call(Mirror.prototype);
1634
1635 });/* ***** BEGIN LICENSE BLOCK *****
1636 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
1637 *
1638 * The contents of this file are subject to the Mozilla Public License Version
1639 * 1.1 (the "License"); you may not use this file except in compliance with
1640 * the License. You may obtain a copy of the License at
1641 * http://www.mozilla.org/MPL/
1642 *
1643 * Software distributed under the License is distributed on an "AS IS" basis,
1644 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
1645 * for the specific language governing rights and limitations under the
1646 * License.
1647 *
1648 * The Original Code is Ajax.org Code Editor (ACE).
1649 *
1650 * The Initial Developer of the Original Code is
1651 * Ajax.org B.V.
1652 * Portions created by the Initial Developer are Copyright (C) 2010
1653 * the Initial Developer. All Rights Reserved.
1654 *
1655 * Contributor(s):
1656 * Fabian Jakobs <fabian AT ajax DOT org>
1657 *
1658 * Alternatively, the contents of this file may be used under the terms of
1659 * either the GNU General Public License Version 2 or later (the "GPL"), or
1660 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
1661 * in which case the provisions of the GPL or the LGPL are applicable instead
1662 * of those above. If you wish to allow use of your version of this file only
1663 * under the terms of either the GPL or the LGPL, and not to allow others to
1664 * use your version of this file under the terms of the MPL, indicate your
1665 * decision by deleting the provisions above and replace them with the notice
1666 * and other provisions required by the GPL or the LGPL. If you do not delete
1667 * the provisions above, a recipient may use your version of this file under
1668 * the terms of any one of the MPL, the GPL or the LGPL.
1669 *
1670 * ***** END LICENSE BLOCK ***** */
1671
1672 define('ace/document', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/event_emitter', 'ace/range', 'ace/anchor'], function(require, exports, module) {
1673 "use strict";
1674
1675 var oop = require("./lib/oop");
1676 var EventEmitter = require("./lib/event_emitter").EventEmitter;
1677 var Range = require("./range").Range;
1678 var Anchor = require("./anchor").Anchor;
1679
1680 var Document = function(text) {
1681 this.$lines = [];
1682
1683 if (Array.isArray(text)) {
1684 this.insertLines(0, text);
1685 }
1686 // There has to be one line at least in the document. If you pass an empty
1687 // string to the insert function, nothing will happen. Workaround.
1688 else if (text.length == 0) {
1689 this.$lines = [""];
1690 } else {
1691 this.insert({row: 0, column:0}, text);
1692 }
1693 };
1694
1695 (function() {
1696
1697 oop.implement(this, EventEmitter);
1698
1699 this.setValue = function(text) {
1700 var len = this.getLength();
1701 this.remove(new Range(0, 0, len, this.getLine(len-1).length));
1702 this.insert({row: 0, column:0}, text);
1703 };
1704
1705 this.getValue = function() {
1706 return this.getAllLines().join(this.getNewLineCharacter());
1707 };
1708
1709 this.createAnchor = function(row, column) {
1710 return new Anchor(this, row, column);
1711 };
1712
1713 // check for IE split bug
1714 if ("aaa".split(/a/).length == 0)
1715 this.$split = function(text) {
1716 return text.replace(/\r\n|\r/g, "\n").split("\n");
1717 }
1718 else
1719 this.$split = function(text) {
1720 return text.split(/\r\n|\r|\n/);
1721 };
1722
1723
1724 this.$detectNewLine = function(text) {
1725 var match = text.match(/^.*?(\r\n|\r|\n)/m);
1726 if (match) {
1727 this.$autoNewLine = match[1];
1728 } else {
1729 this.$autoNewLine = "\n";
1730 }
1731 };
1732
1733 this.getNewLineCharacter = function() {
1734 switch (this.$newLineMode) {
1735 case "windows":
1736 return "\r\n";
1737
1738 case "unix":
1739 return "\n";
1740
1741 case "auto":
1742 return this.$autoNewLine;
1743 }
1744 };
1745
1746 this.$autoNewLine = "\n";
1747 this.$newLineMode = "auto";
1748 this.setNewLineMode = function(newLineMode) {
1749 if (this.$newLineMode === newLineMode)
1750 return;
1751
1752 this.$newLineMode = newLineMode;
1753 };
1754
1755 this.getNewLineMode = function() {
1756 return this.$newLineMode;
1757 };
1758
1759 this.isNewLine = function(text) {
1760 return (text == "\r\n" || text == "\r" || text == "\n");
1761 };
1762
1763 /**
1764 * Get a verbatim copy of the given line as it is in the document
1765 */
1766 this.getLine = function(row) {
1767 return this.$lines[row] || "";
1768 };
1769
1770 this.getLines = function(firstRow, lastRow) {
1771 return this.$lines.slice(firstRow, lastRow + 1);
1772 };
1773
1774 /**
1775 * Returns all lines in the document as string array. Warning: The caller
1776 * should not modify this array!
1777 */
1778 this.getAllLines = function() {
1779 return this.getLines(0, this.getLength());
1780 };
1781
1782 this.getLength = function() {
1783 return this.$lines.length;
1784 };
1785
1786 this.getTextRange = function(range) {
1787 if (range.start.row == range.end.row) {
1788 return this.$lines[range.start.row].substring(range.start.column,
1789 range.end.column);
1790 }
1791 else {
1792 var lines = [];
1793 lines.push(this.$lines[range.start.row].substring(range.start.column));
1794 lines.push.apply(lines, this.getLines(range.start.row+1, range.end.row-1));
1795 lines.push(this.$lines[range.end.row].substring(0, range.end.column));
1796 return lines.join(this.getNewLineCharacter());
1797 }
1798 };
1799
1800 this.$clipPosition = function(position) {
1801 var length = this.getLength();
1802 if (position.row >= length) {
1803 position.row = Math.max(0, length - 1);
1804 position.column = this.getLine(length-1).length;
1805 }
1806 return position;
1807 };
1808
1809 this.insert = function(position, text) {
1810 if (!text || text.length === 0)
1811 return position;
1812
1813 position = this.$clipPosition(position);
1814
1815 // only detect new lines if the document has no line break yet
1816 if (this.getLength() <= 1)
1817 this.$detectNewLine(text);
1818
1819 var lines = this.$split(text);
1820 var firstLine = lines.splice(0, 1)[0];
1821 var lastLine = lines.length == 0 ? null : lines.splice(lines.length - 1, 1)[0];
1822
1823 position = this.insertInLine(position, firstLine);
1824 if (lastLine !== null) {
1825 position = this.insertNewLine(position); // terminate first line
1826 position = this.insertLines(position.row, lines);
1827 position = this.insertInLine(position, lastLine || "");
1828 }
1829 return position;
1830 };
1831
1832 this.insertLines = function(row, lines) {
1833 if (lines.length == 0)
1834 return {row: row, column: 0};
1835
1836 var args = [row, 0];
1837 args.push.apply(args, lines);
1838 this.$lines.splice.apply(this.$lines, args);
1839
1840 var range = new Range(row, 0, row + lines.length, 0);
1841 var delta = {
1842 action: "insertLines",
1843 range: range,
1844 lines: lines
1845 };
1846 this._emit("change", { data: delta });
1847 return range.end;
1848 };
1849
1850 this.insertNewLine = function(position) {
1851 position = this.$clipPosition(position);
1852 var line = this.$lines[position.row] || "";
1853
1854 this.$lines[position.row] = line.substring(0, position.column);
1855 this.$lines.splice(position.row + 1, 0, line.substring(position.column, line.length));
1856
1857 var end = {
1858 row : position.row + 1,
1859 column : 0
1860 };
1861
1862 var delta = {
1863 action: "insertText",
1864 range: Range.fromPoints(position, end),
1865 text: this.getNewLineCharacter()
1866 };
1867 this._emit("change", { data: delta });
1868
1869 return end;
1870 };
1871
1872 this.insertInLine = function(position, text) {
1873 if (text.length == 0)
1874 return position;
1875
1876 var line = this.$lines[position.row] || "";
1877
1878 this.$lines[position.row] = line.substring(0, position.column) + text
1879 + line.substring(position.column);
1880
1881 var end = {
1882 row : position.row,
1883 column : position.column + text.length
1884 };
1885
1886 var delta = {
1887 action: "insertText",
1888 range: Range.fromPoints(position, end),
1889 text: text
1890 };
1891 this._emit("change", { data: delta });
1892
1893 return end;
1894 };
1895
1896 this.remove = function(range) {
1897 // clip to document
1898 range.start = this.$clipPosition(range.start);
1899 range.end = this.$clipPosition(range.end);
1900
1901 if (range.isEmpty())
1902 return range.start;
1903
1904 var firstRow = range.start.row;
1905 var lastRow = range.end.row;
1906
1907 if (range.isMultiLine()) {
1908 var firstFullRow = range.start.column == 0 ? firstRow : firstRow + 1;
1909 var lastFullRow = lastRow - 1;
1910
1911 if (range.end.column > 0)
1912 this.removeInLine(lastRow, 0, range.end.column);
1913
1914 if (lastFullRow >= firstFullRow)
1915 this.removeLines(firstFullRow, lastFullRow);
1916
1917 if (firstFullRow != firstRow) {
1918 this.removeInLine(firstRow, range.start.column, this.getLine(firstRow).length);
1919 this.removeNewLine(range.start.row);
1920 }
1921 }
1922 else {
1923 this.removeInLine(firstRow, range.start.column, range.end.column);
1924 }
1925 return range.start;
1926 };
1927
1928 this.removeInLine = function(row, startColumn, endColumn) {
1929 if (startColumn == endColumn)
1930 return;
1931
1932 var range = new Range(row, startColumn, row, endColumn);
1933 var line = this.getLine(row);
1934 var removed = line.substring(startColumn, endColumn);
1935 var newLine = line.substring(0, startColumn) + line.substring(endColumn, line.length);
1936 this.$lines.splice(row, 1, newLine);
1937
1938 var delta = {
1939 action: "removeText",
1940 range: range,
1941 text: removed
1942 };
1943 this._emit("change", { data: delta });
1944 return range.start;
1945 };
1946
1947 /**
1948 * Removes a range of full lines
1949 *
1950 * @param firstRow {Integer} The first row to be removed
1951 * @param lastRow {Integer} The last row to be removed
1952 * @return {String[]} The removed lines
1953 */
1954 this.removeLines = function(firstRow, lastRow) {
1955 var range = new Range(firstRow, 0, lastRow + 1, 0);
1956 var removed = this.$lines.splice(firstRow, lastRow - firstRow + 1);
1957
1958 var delta = {
1959 action: "removeLines",
1960 range: range,
1961 nl: this.getNewLineCharacter(),
1962 lines: removed
1963 };
1964 this._emit("change", { data: delta });
1965 return removed;
1966 };
1967
1968 this.removeNewLine = function(row) {
1969 var firstLine = this.getLine(row);
1970 var secondLine = this.getLine(row+1);
1971
1972 var range = new Range(row, firstLine.length, row+1, 0);
1973 var line = firstLine + secondLine;
1974
1975 this.$lines.splice(row, 2, line);
1976
1977 var delta = {
1978 action: "removeText",
1979 range: range,
1980 text: this.getNewLineCharacter()
1981 };
1982 this._emit("change", { data: delta });
1983 };
1984
1985 this.replace = function(range, text) {
1986 if (text.length == 0 && range.isEmpty())
1987 return range.start;
1988
1989 // Shortcut: If the text we want to insert is the same as it is already
1990 // in the document, we don't have to replace anything.
1991 if (text == this.getTextRange(range))
1992 return range.end;
1993
1994 this.remove(range);
1995 if (text) {
1996 var end = this.insert(range.start, text);
1997 }
1998 else {
1999 end = range.start;
2000 }
2001
2002 return end;
2003 };
2004
2005 this.applyDeltas = function(deltas) {
2006 for (var i=0; i<deltas.length; i++) {
2007 var delta = deltas[i];
2008 var range = Range.fromPoints(delta.range.start, delta.range.end);
2009
2010 if (delta.action == "insertLines")
2011 this.insertLines(range.start.row, delta.lines);
2012 else if (delta.action == "insertText")
2013 this.insert(range.start, delta.text);
2014 else if (delta.action == "removeLines")
2015 this.removeLines(range.start.row, range.end.row - 1);
2016 else if (delta.action == "removeText")
2017 this.remove(range);
2018 }
2019 };
2020
2021 this.revertDeltas = function(deltas) {
2022 for (var i=deltas.length-1; i>=0; i--) {
2023 var delta = deltas[i];
2024
2025 var range = Range.fromPoints(delta.range.start, delta.range.end);
2026
2027 if (delta.action == "insertLines")
2028 this.removeLines(range.start.row, range.end.row - 1);
2029 else if (delta.action == "insertText")
2030 this.remove(range);
2031 else if (delta.action == "removeLines")
2032 this.insertLines(range.start.row, delta.lines);
2033 else if (delta.action == "removeText")
2034 this.insert(range.start, delta.text);
2035 }
2036 };
2037
2038 }).call(Document.prototype);
2039
2040 exports.Document = Document;
2041 });
2042 /* ***** BEGIN LICENSE BLOCK *****
2043 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
2044 *
2045 * The contents of this file are subject to the Mozilla Public License Version
2046 * 1.1 (the "License"); you may not use this file except in compliance with
2047 * the License. You may obtain a copy of the License at
2048 * http://www.mozilla.org/MPL/
2049 *
2050 * Software distributed under the License is distributed on an "AS IS" basis,
2051 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
2052 * for the specific language governing rights and limitations under the
2053 * License.
2054 *
2055 * The Original Code is Ajax.org Code Editor (ACE).
2056 *
2057 * The Initial Developer of the Original Code is
2058 * Ajax.org B.V.
2059 * Portions created by the Initial Developer are Copyright (C) 2010
2060 * the Initial Developer. All Rights Reserved.
2061 *
2062 * Contributor(s):
2063 * Fabian Jakobs <fabian AT ajax DOT org>
2064 *
2065 * Alternatively, the contents of this file may be used under the terms of
2066 * either the GNU General Public License Version 2 or later (the "GPL"), or
2067 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
2068 * in which case the provisions of the GPL or the LGPL are applicable instead
2069 * of those above. If you wish to allow use of your version of this file only
2070 * under the terms of either the GPL or the LGPL, and not to allow others to
2071 * use your version of this file under the terms of the MPL, indicate your
2072 * decision by deleting the provisions above and replace them with the notice
2073 * and other provisions required by the GPL or the LGPL. If you do not delete
2074 * the provisions above, a recipient may use your version of this file under
2075 * the terms of any one of the MPL, the GPL or the LGPL.
2076 *
2077 * ***** END LICENSE BLOCK ***** */
2078
2079 define('ace/range', ['require', 'exports', 'module' ], function(require, exports, module) {
2080 "use strict";
2081
2082 var Range = function(startRow, startColumn, endRow, endColumn) {
2083 this.start = {
2084 row: startRow,
2085 column: startColumn
2086 };
2087
2088 this.end = {
2089 row: endRow,
2090 column: endColumn
2091 };
2092 };
2093
2094 (function() {
2095 this.isEequal = function(range) {
2096 return this.start.row == range.start.row &&
2097 this.end.row == range.end.row &&
2098 this.start.column == range.start.column &&
2099 this.end.column == range.end.column
2100 };
2101
2102 this.toString = function() {
2103 return ("Range: [" + this.start.row + "/" + this.start.column +
2104 "] -> [" + this.end.row + "/" + this.end.column + "]");
2105 };
2106
2107 this.contains = function(row, column) {
2108 return this.compare(row, column) == 0;
2109 };
2110
2111 /**
2112 * Compares this range (A) with another range (B), where B is the passed in
2113 * range.
2114 *
2115 * Return values:
2116 * -2: (B) is infront of (A) and doesn't intersect with (A)
2117 * -1: (B) begins before (A) but ends inside of (A)
2118 * 0: (B) is completly inside of (A) OR (A) is complety inside of (B)
2119 * +1: (B) begins inside of (A) but ends outside of (A)
2120 * +2: (B) is after (A) and doesn't intersect with (A)
2121 *
2122 * 42: FTW state: (B) ends in (A) but starts outside of (A)
2123 */
2124 this.compareRange = function(range) {
2125 var cmp,
2126 end = range.end,
2127 start = range.start;
2128
2129 cmp = this.compare(end.row, end.column);
2130 if (cmp == 1) {
2131 cmp = this.compare(start.row, start.column);
2132 if (cmp == 1) {
2133 return 2;
2134 } else if (cmp == 0) {
2135 return 1;
2136 } else {
2137 return 0;
2138 }
2139 } else if (cmp == -1) {
2140 return -2;
2141 } else {
2142 cmp = this.compare(start.row, start.column);
2143 if (cmp == -1) {
2144 return -1;
2145 } else if (cmp == 1) {
2146 return 42;
2147 } else {
2148 return 0;
2149 }
2150 }
2151 }
2152
2153 this.comparePoint = function(p) {
2154 return this.compare(p.row, p.column);
2155 }
2156
2157 this.containsRange = function(range) {
2158 return this.comparePoint(range.start) == 0 && this.comparePoint(range.end) == 0;
2159 }
2160
2161 this.isEnd = function(row, column) {
2162 return this.end.row == row && this.end.column == column;
2163 }
2164
2165 this.isStart = function(row, column) {
2166 return this.start.row == row && this.start.column == column;
2167 }
2168
2169 this.setStart = function(row, column) {
2170 if (typeof row == "object") {
2171 this.start.column = row.column;
2172 this.start.row = row.row;
2173 } else {
2174 this.start.row = row;
2175 this.start.column = column;
2176 }
2177 }
2178
2179 this.setEnd = function(row, column) {
2180 if (typeof row == "object") {
2181 this.end.column = row.column;
2182 this.end.row = row.row;
2183 } else {
2184 this.end.row = row;
2185 this.end.column = column;
2186 }
2187 }
2188
2189 this.inside = function(row, column) {
2190 if (this.compare(row, column) == 0) {
2191 if (this.isEnd(row, column) || this.isStart(row, column)) {
2192 return false;
2193 } else {
2194 return true;
2195 }
2196 }
2197 return false;
2198 }
2199
2200 this.insideStart = function(row, column) {
2201 if (this.compare(row, column) == 0) {
2202 if (this.isEnd(row, column)) {
2203 return false;
2204 } else {
2205 return true;
2206 }
2207 }
2208 return false;
2209 }
2210
2211 this.insideEnd = function(row, column) {
2212 if (this.compare(row, column) == 0) {
2213 if (this.isStart(row, column)) {
2214 return false;
2215 } else {
2216 return true;
2217 }
2218 }
2219 return false;
2220 }
2221
2222 this.compare = function(row, column) {
2223 if (!this.isMultiLine()) {
2224 if (row === this.start.row) {
2225 return column < this.start.column ? -1 : (column > this.end.column ? 1 : 0);
2226 };
2227 }
2228
2229 if (row < this.start.row)
2230 return -1;
2231
2232 if (row > this.end.row)
2233 return 1;
2234
2235 if (this.start.row === row)
2236 return column >= this.start.column ? 0 : -1;
2237
2238 if (this.end.row === row)
2239 return column <= this.end.column ? 0 : 1;
2240
2241 return 0;
2242 };
2243
2244 /**
2245 * Like .compare(), but if isStart is true, return -1;
2246 */
2247 this.compareStart = function(row, column) {
2248 if (this.start.row == row && this.start.column == column) {
2249 return -1;
2250 } else {
2251 return this.compare(row, column);
2252 }
2253 }
2254
2255 /**
2256 * Like .compare(), but if isEnd is true, return 1;
2257 */
2258 this.compareEnd = function(row, column) {
2259 if (this.end.row == row && this.end.column == column) {
2260 return 1;
2261 } else {
2262 return this.compare(row, column);
2263 }
2264 }
2265
2266 this.compareInside = function(row, column) {
2267 if (this.end.row == row && this.end.column == column) {
2268 return 1;
2269 } else if (this.start.row == row && this.start.column == column) {
2270 return -1;
2271 } else {
2272 return this.compare(row, column);
2273 }
2274 }
2275
2276 this.clipRows = function(firstRow, lastRow) {
2277 if (this.end.row > lastRow) {
2278 var end = {
2279 row: lastRow+1,
2280 column: 0
2281 };
2282 }
2283
2284 if (this.start.row > lastRow) {
2285 var start = {
2286 row: lastRow+1,
2287 column: 0
2288 };
2289 }
2290
2291 if (this.start.row < firstRow) {
2292 var start = {
2293 row: firstRow,
2294 column: 0
2295 };
2296 }
2297
2298 if (this.end.row < firstRow) {
2299 var end = {
2300 row: firstRow,
2301 column: 0
2302 };
2303 }
2304 return Range.fromPoints(start || this.start, end || this.end);
2305 };
2306
2307 this.extend = function(row, column) {
2308 var cmp = this.compare(row, column);
2309
2310 if (cmp == 0)
2311 return this;
2312 else if (cmp == -1)
2313 var start = {row: row, column: column};
2314 else
2315 var end = {row: row, column: column};
2316
2317 return Range.fromPoints(start || this.start, end || this.end);
2318 };
2319
2320 this.isEmpty = function() {
2321 return (this.start.row == this.end.row && this.start.column == this.end.column);
2322 };
2323
2324 this.isMultiLine = function() {
2325 return (this.start.row !== this.end.row);
2326 };
2327
2328 this.clone = function() {
2329 return Range.fromPoints(this.start, this.end);
2330 };
2331
2332 this.collapseRows = function() {
2333 if (this.end.column == 0)
2334 return new Range(this.start.row, 0, Math.max(this.start.row, this.end.row-1), 0)
2335 else
2336 return new Range(this.start.row, 0, this.end.row, 0)
2337 };
2338
2339 this.toScreenRange = function(session) {
2340 var screenPosStart =
2341 session.documentToScreenPosition(this.start);
2342 var screenPosEnd =
2343 session.documentToScreenPosition(this.end);
2344
2345 return new Range(
2346 screenPosStart.row, screenPosStart.column,
2347 screenPosEnd.row, screenPosEnd.column
2348 );
2349 };
2350
2351 }).call(Range.prototype);
2352
2353
2354 Range.fromPoints = function(start, end) {
2355 return new Range(start.row, start.column, end.row, end.column);
2356 };
2357
2358 exports.Range = Range;
2359 });
2360 /* ***** BEGIN LICENSE BLOCK *****
2361 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
2362 *
2363 * The contents of this file are subject to the Mozilla Public License Version
2364 * 1.1 (the "License"); you may not use this file except in compliance with
2365 * the License. You may obtain a copy of the License at
2366 * http://www.mozilla.org/MPL/
2367 *
2368 * Software distributed under the License is distributed on an "AS IS" basis,
2369 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
2370 * for the specific language governing rights and limitations under the
2371 * License.
2372 *
2373 * The Original Code is Ajax.org Code Editor (ACE).
2374 *
2375 * The Initial Developer of the Original Code is
2376 * Ajax.org B.V.
2377 * Portions created by the Initial Developer are Copyright (C) 2010
2378 * the Initial Developer. All Rights Reserved.
2379 *
2380 * Contributor(s):
2381 * Fabian Jakobs <fabian AT ajax DOT org>
2382 *
2383 * Alternatively, the contents of this file may be used under the terms of
2384 * either the GNU General Public License Version 2 or later (the "GPL"), or
2385 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
2386 * in which case the provisions of the GPL or the LGPL are applicable instead
2387 * of those above. If you wish to allow use of your version of this file only
2388 * under the terms of either the GPL or the LGPL, and not to allow others to
2389 * use your version of this file under the terms of the MPL, indicate your
2390 * decision by deleting the provisions above and replace them with the notice
2391 * and other provisions required by the GPL or the LGPL. If you do not delete
2392 * the provisions above, a recipient may use your version of this file under
2393 * the terms of any one of the MPL, the GPL or the LGPL.
2394 *
2395 * ***** END LICENSE BLOCK ***** */
2396
2397 define('ace/anchor', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/event_emitter'], function(require, exports, module) {
2398 "use strict";
2399
2400 var oop = require("./lib/oop");
2401 var EventEmitter = require("./lib/event_emitter").EventEmitter;
2402
2403 /**
2404 * An Anchor is a floating pointer in the document. Whenever text is inserted or
2405 * deleted before the cursor, the position of the cursor is updated
2406 */
2407 var Anchor = exports.Anchor = function(doc, row, column) {
2408 this.document = doc;
2409
2410 if (typeof column == "undefined")
2411 this.setPosition(row.row, row.column);
2412 else
2413 this.setPosition(row, column);
2414
2415 this.$onChange = this.onChange.bind(this);
2416 doc.on("change", this.$onChange);
2417 };
2418
2419 (function() {
2420
2421 oop.implement(this, EventEmitter);
2422
2423 this.getPosition = function() {
2424 return this.$clipPositionToDocument(this.row, this.column);
2425 };
2426
2427 this.getDocument = function() {
2428 return this.document;
2429 };
2430
2431 this.onChange = function(e) {
2432 var delta = e.data;
2433 var range = delta.range;
2434
2435 if (range.start.row == range.end.row && range.start.row != this.row)
2436 return;
2437
2438 if (range.start.row > this.row)
2439 return;
2440
2441 if (range.start.row == this.row && range.start.column > this.column)
2442 return;
2443
2444 var row = this.row;
2445 var column = this.column;
2446
2447 if (delta.action === "insertText") {
2448 if (range.start.row === row && range.start.column <= column) {
2449 if (range.start.row === range.end.row) {
2450 column += range.end.column - range.start.column;
2451 }
2452 else {
2453 column -= range.start.column;
2454 row += range.end.row - range.start.row;
2455 }
2456 }
2457 else if (range.start.row !== range.end.row && range.start.row < row) {
2458 row += range.end.row - range.start.row;
2459 }
2460 } else if (delta.action === "insertLines") {
2461 if (range.start.row <= row) {
2462 row += range.end.row - range.start.row;
2463 }
2464 }
2465 else if (delta.action == "removeText") {
2466 if (range.start.row == row && range.start.column < column) {
2467 if (range.end.column >= column)
2468 column = range.start.column;
2469 else
2470 column = Math.max(0, column - (range.end.column - range.start.column));
2471
2472 } else if (range.start.row !== range.end.row && range.start.row < row) {
2473 if (range.end.row == row) {
2474 column = Math.max(0, column - range.end.column) + range.start.column;
2475 }
2476 row -= (range.end.row - range.start.row);
2477 }
2478 else if (range.end.row == row) {
2479 row -= range.end.row - range.start.row;
2480 column = Math.max(0, column - range.end.column) + range.start.column;
2481 }
2482 } else if (delta.action == "removeLines") {
2483 if (range.start.row <= row) {
2484 if (range.end.row <= row)
2485 row -= range.end.row - range.start.row;
2486 else {
2487 row = range.start.row;
2488 column = 0;
2489 }
2490 }
2491 }
2492
2493 this.setPosition(row, column, true);
2494 };
2495
2496 this.setPosition = function(row, column, noClip) {
2497 var pos;
2498 if (noClip) {
2499 pos = {
2500 row: row,
2501 column: column
2502 };
2503 }
2504 else {
2505 pos = this.$clipPositionToDocument(row, column);
2506 }
2507
2508 if (this.row == pos.row && this.column == pos.column)
2509 return;
2510
2511 var old = {
2512 row: this.row,
2513 column: this.column
2514 };
2515
2516 this.row = pos.row;
2517 this.column = pos.column;
2518 this._emit("change", {
2519 old: old,
2520 value: pos
2521 });
2522 };
2523
2524 this.detach = function() {
2525 this.document.removeEventListener("change", this.$onChange);
2526 };
2527
2528 this.$clipPositionToDocument = function(row, column) {
2529 var pos = {};
2530
2531 if (row >= this.document.getLength()) {
2532 pos.row = Math.max(0, this.document.getLength() - 1);
2533 pos.column = this.document.getLine(pos.row).length;
2534 }
2535 else if (row < 0) {
2536 pos.row = 0;
2537 pos.column = 0;
2538 }
2539 else {
2540 pos.row = row;
2541 pos.column = Math.min(this.document.getLine(pos.row).length, Math.max(0, column));
2542 }
2543
2544 if (column < 0)
2545 pos.column = 0;
2546
2547 return pos;
2548 };
2549
2550 }).call(Anchor.prototype);
2551
2552 });
2553 /* ***** BEGIN LICENSE BLOCK *****
2554 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
2555 *
2556 * The contents of this file are subject to the Mozilla Public License Version
2557 * 1.1 (the "License"); you may not use this file except in compliance with
2558 * the License. You may obtain a copy of the License at
2559 * http://www.mozilla.org/MPL/
2560 *
2561 * Software distributed under the License is distributed on an "AS IS" basis,
2562 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
2563 * for the specific language governing rights and limitations under the
2564 * License.
2565 *
2566 * The Original Code is Ajax.org Code Editor (ACE).
2567 *
2568 * The Initial Developer of the Original Code is
2569 * Ajax.org B.V.
2570 * Portions created by the Initial Developer are Copyright (C) 2010
2571 * the Initial Developer. All Rights Reserved.
2572 *
2573 * Contributor(s):
2574 * Fabian Jakobs <fabian AT ajax DOT org>
2575 *
2576 * Alternatively, the contents of this file may be used under the terms of
2577 * either the GNU General Public License Version 2 or later (the "GPL"), or
2578 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
2579 * in which case the provisions of the GPL or the LGPL are applicable instead
2580 * of those above. If you wish to allow use of your version of this file only
2581 * under the terms of either the GPL or the LGPL, and not to allow others to
2582 * use your version of this file under the terms of the MPL, indicate your
2583 * decision by deleting the provisions above and replace them with the notice
2584 * and other provisions required by the GPL or the LGPL. If you do not delete
2585 * the provisions above, a recipient may use your version of this file under
2586 * the terms of any one of the MPL, the GPL or the LGPL.
2587 *
2588 * ***** END LICENSE BLOCK ***** */
2589
2590 define('ace/lib/lang', ['require', 'exports', 'module' ], function(require, exports, module) {
2591 "use strict";
2592
2593 exports.stringReverse = function(string) {
2594 return string.split("").reverse().join("");
2595 };
2596
2597 exports.stringRepeat = function (string, count) {
2598 return new Array(count + 1).join(string);
2599 };
2600
2601 var trimBeginRegexp = /^\s\s*/;
2602 var trimEndRegexp = /\s\s*$/;
2603
2604 exports.stringTrimLeft = function (string) {
2605 return string.replace(trimBeginRegexp, '');
2606 };
2607
2608 exports.stringTrimRight = function (string) {
2609 return string.replace(trimEndRegexp, '');
2610 };
2611
2612 exports.copyObject = function(obj) {
2613 var copy = {};
2614 for (var key in obj) {
2615 copy[key] = obj[key];
2616 }
2617 return copy;
2618 };
2619
2620 exports.copyArray = function(array){
2621 var copy = [];
2622 for (var i=0, l=array.length; i<l; i++) {
2623 if (array[i] && typeof array[i] == "object")
2624 copy[i] = this.copyObject( array[i] );
2625 else
2626 copy[i] = array[i];
2627 }
2628 return copy;
2629 };
2630
2631 exports.deepCopy = function (obj) {
2632 if (typeof obj != "object") {
2633 return obj;
2634 }
2635
2636 var copy = obj.constructor();
2637 for (var key in obj) {
2638 if (typeof obj[key] == "object") {
2639 copy[key] = this.deepCopy(obj[key]);
2640 } else {
2641 copy[key] = obj[key];
2642 }
2643 }
2644 return copy;
2645 };
2646
2647 exports.arrayToMap = function(arr) {
2648 var map = {};
2649 for (var i=0; i<arr.length; i++) {
2650 map[arr[i]] = 1;
2651 }
2652 return map;
2653
2654 };
2655
2656 /**
2657 * splice out of 'array' anything that === 'value'
2658 */
2659 exports.arrayRemove = function(array, value) {
2660 for (var i = 0; i <= array.length; i++) {
2661 if (value === array[i]) {
2662 array.splice(i, 1);
2663 }
2664 }
2665 };
2666
2667 exports.escapeRegExp = function(str) {
2668 return str.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1');
2669 };
2670
2671 exports.deferredCall = function(fcn) {
2672
2673 var timer = null;
2674 var callback = function() {
2675 timer = null;
2676 fcn();
2677 };
2678
2679 var deferred = function(timeout) {
2680 deferred.cancel();
2681 timer = setTimeout(callback, timeout || 0);
2682 return deferred;
2683 };
2684
2685 deferred.schedule = deferred;
2686
2687 deferred.call = function() {
2688 this.cancel();
2689 fcn();
2690 return deferred;
2691 };
2692
2693 deferred.cancel = function() {
2694 clearTimeout(timer);
2695 timer = null;
2696 return deferred;
2697 };
2698
2699 return deferred;
2700 };
2701
2702 });
2703 define('ace/worker/jshint', ['require', 'exports', 'module' ], function(require, exports, module) {
2704 /*!
2705 * JSHint, by JSHint Community.
2706 *
2707 * Licensed under the same slightly modified MIT license that JSLint is.
2708 * It stops evil-doers everywhere.
2709 *
2710 * JSHint is a derivative work of JSLint:
2711 *
2712 * Copyright (c) 2002 Douglas Crockford (www.JSLint.com)
2713 *
2714 * Permission is hereby granted, free of charge, to any person obtaining
2715 * a copy of this software and associated documentation files (the "Software"),
2716 * to deal in the Software without restriction, including without limitation
2717 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
2718 * and/or sell copies of the Software, and to permit persons to whom
2719 * the Software is furnished to do so, subject to the following conditions:
2720 *
2721 * The above copyright notice and this permission notice shall be included
2722 * in all copies or substantial portions of the Software.
2723 *
2724 * The Software shall be used for Good, not Evil.
2725 *
2726 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2727 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2728 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2729 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2730 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2731 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2732 * DEALINGS IN THE SOFTWARE.
2733 *
2734 * JSHint was forked from 2010-12-16 edition of JSLint.
2735 *
2736 */
2737
2738 /*
2739 JSHINT is a global function. It takes two parameters.
2740
2741 var myResult = JSHINT(source, option);
2742
2743 The first parameter is either a string or an array of strings. If it is a
2744 string, it will be split on '\n' or '\r'. If it is an array of strings, it
2745 is assumed that each string represents one line. The source can be a
2746 JavaScript text or a JSON text.
2747
2748 The second parameter is an optional object of options which control the
2749 operation of JSHINT. Most of the options are booleans: They are all
2750 optional and have a default value of false. One of the options, predef,
2751 can be an array of names, which will be used to declare global variables,
2752 or an object whose keys are used as global names, with a boolean value
2753 that determines if they are assignable.
2754
2755 If it checks out, JSHINT returns true. Otherwise, it returns false.
2756
2757 If false, you can inspect JSHINT.errors to find out the problems.
2758 JSHINT.errors is an array of objects containing these members:
2759
2760 {
2761 line : The line (relative to 0) at which the lint was found
2762 character : The character (relative to 0) at which the lint was found
2763 reason : The problem
2764 evidence : The text line in which the problem occurred
2765 raw : The raw message before the details were inserted
2766 a : The first detail
2767 b : The second detail
2768 c : The third detail
2769 d : The fourth detail
2770 }
2771
2772 If a fatal error was found, a null will be the last element of the
2773 JSHINT.errors array.
2774
2775 You can request a Function Report, which shows all of the functions
2776 and the parameters and vars that they use. This can be used to find
2777 implied global variables and other problems. The report is in HTML and
2778 can be inserted in an HTML <body>.
2779
2780 var myReport = JSHINT.report(limited);
2781
2782 If limited is true, then the report will be limited to only errors.
2783
2784 You can request a data structure which contains JSHint's results.
2785
2786 var myData = JSHINT.data();
2787
2788 It returns a structure with this form:
2789
2790 {
2791 errors: [
2792 {
2793 line: NUMBER,
2794 character: NUMBER,
2795 reason: STRING,
2796 evidence: STRING
2797 }
2798 ],
2799 functions: [
2800 name: STRING,
2801 line: NUMBER,
2802 last: NUMBER,
2803 param: [
2804 STRING
2805 ],
2806 closure: [
2807 STRING
2808 ],
2809 var: [
2810 STRING
2811 ],
2812 exception: [
2813 STRING
2814 ],
2815 outer: [
2816 STRING
2817 ],
2818 unused: [
2819 STRING
2820 ],
2821 global: [
2822 STRING
2823 ],
2824 label: [
2825 STRING
2826 ]
2827 ],
2828 globals: [
2829 STRING
2830 ],
2831 member: {
2832 STRING: NUMBER
2833 },
2834 unused: [
2835 {
2836 name: STRING,
2837 line: NUMBER
2838 }
2839 ],
2840 implieds: [
2841 {
2842 name: STRING,
2843 line: NUMBER
2844 }
2845 ],
2846 urls: [
2847 STRING
2848 ],
2849 json: BOOLEAN
2850 }
2851
2852 Empty arrays will not be included.
2853
2854 */
2855
2856 /*jshint
2857 evil: true, nomen: false, onevar: false, regexp: false, strict: true, boss: true,
2858 undef: true, maxlen: 100, indent:4
2859 */
2860
2861 /*members "\b", "\t", "\n", "\f", "\r", "!=", "!==", "\"", "%", "(begin)",
2862 "(breakage)", "(context)", "(error)", "(global)", "(identifier)", "(last)",
2863 "(line)", "(loopage)", "(name)", "(onevar)", "(params)", "(scope)",
2864 "(statement)", "(verb)", "*", "+", "++", "-", "--", "\/", "<", "<=", "==",
2865 "===", ">", ">=", $, $$, $A, $F, $H, $R, $break, $continue, $w, Abstract, Ajax,
2866 __filename, __dirname, ActiveXObject, Array, ArrayBuffer, ArrayBufferView, Audio,
2867 Autocompleter, Assets, Boolean, Builder, Buffer, Browser, COM, CScript, Canvas,
2868 CustomAnimation, Class, Control, Chain, Color, Cookie, Core, DataView, Date,
2869 Debug, Draggable, Draggables, Droppables, Document, DomReady, DOMReady, DOMParser, Drag,
2870 E, Enumerator, Enumerable, Element, Elements, Error, Effect, EvalError, Event,
2871 Events, FadeAnimation, Field, Flash, Float32Array, Float64Array, Form,
2872 FormField, Frame, FormData, Function, Fx, GetObject, Group, Hash, HotKey,
2873 HTMLElement, HTMLAnchorElement, HTMLBaseElement, HTMLBlockquoteElement,
2874 HTMLBodyElement, HTMLBRElement, HTMLButtonElement, HTMLCanvasElement, HTMLDirectoryElement,
2875 HTMLDivElement, HTMLDListElement, HTMLFieldSetElement,
2876 HTMLFontElement, HTMLFormElement, HTMLFrameElement, HTMLFrameSetElement,
2877 HTMLHeadElement, HTMLHeadingElement, HTMLHRElement, HTMLHtmlElement,
2878 HTMLIFrameElement, HTMLImageElement, HTMLInputElement, HTMLIsIndexElement,
2879 HTMLLabelElement, HTMLLayerElement, HTMLLegendElement, HTMLLIElement,
2880 HTMLLinkElement, HTMLMapElement, HTMLMenuElement, HTMLMetaElement,
2881 HTMLModElement, HTMLObjectElement, HTMLOListElement, HTMLOptGroupElement,
2882 HTMLOptionElement, HTMLParagraphElement, HTMLParamElement, HTMLPreElement,
2883 HTMLQuoteElement, HTMLScriptElement, HTMLSelectElement, HTMLStyleElement,
2884 HtmlTable, HTMLTableCaptionElement, HTMLTableCellElement, HTMLTableColElement,
2885 HTMLTableElement, HTMLTableRowElement, HTMLTableSectionElement,
2886 HTMLTextAreaElement, HTMLTitleElement, HTMLUListElement, HTMLVideoElement,
2887 Iframe, IframeShim, Image, Int16Array, Int32Array, Int8Array,
2888 Insertion, InputValidator, JSON, Keyboard, Locale, LN10, LN2, LOG10E, LOG2E,
2889 MAX_VALUE, MIN_VALUE, Mask, Math, MenuItem, MessageChannel, MessageEvent, MessagePort,
2890 MoveAnimation, MooTools, Native, NEGATIVE_INFINITY, Number, Object, ObjectRange, Option,
2891 Options, OverText, PI, POSITIVE_INFINITY, PeriodicalExecuter, Point, Position, Prototype,
2892 RangeError, Rectangle, ReferenceError, RegExp, ResizeAnimation, Request, RotateAnimation,
2893 SQRT1_2, SQRT2, ScrollBar, ScriptEngine, ScriptEngineBuildVersion,
2894 ScriptEngineMajorVersion, ScriptEngineMinorVersion, Scriptaculous, Scroller,
2895 Slick, Slider, Selector, SharedWorker, String, Style, SyntaxError, Sortable, Sortables,
2896 SortableObserver, Sound, Spinner, System, Swiff, Text, TextArea, Template,
2897 Timer, Tips, Type, TypeError, Toggle, Try, "use strict", unescape, URI, URIError, URL,
2898 VBArray, WSH, WScript, XDomainRequest, Web, Window, XMLDOM, XMLHttpRequest, XMLSerializer,
2899 XPathEvaluator, XPathException, XPathExpression, XPathNamespace, XPathNSResolver, XPathResult,
2900 "\\", a, addEventListener, address, alert, apply, applicationCache, arguments, arity, asi, atob,
2901 b, basic, basicToken, bitwise, block, blur, boolOptions, boss, browser, btoa, c, call, callee,
2902 caller, cases, charAt, charCodeAt, character, clearInterval, clearTimeout,
2903 close, closed, closure, comment, condition, confirm, console, constructor,
2904 content, couch, create, css, curly, d, data, datalist, dd, debug, decodeURI,
2905 decodeURIComponent, defaultStatus, defineClass, deserialize, devel, document,
2906 dojo, dijit, dojox, define, else, emit, encodeURI, encodeURIComponent,
2907 entityify, eqeqeq, eqnull, errors, es5, escape, esnext, eval, event, evidence, evil,
2908 ex, exception, exec, exps, expr, exports, FileReader, first, floor, focus,
2909 forin, fragment, frames, from, fromCharCode, fud, funcscope, funct, function, functions,
2910 g, gc, getComputedStyle, getRow, getter, getterToken, GLOBAL, global, globals, globalstrict,
2911 hasOwnProperty, help, history, i, id, identifier, immed, implieds, importPackage, include,
2912 indent, indexOf, init, ins, instanceOf, isAlpha, isApplicationRunning, isArray,
2913 isDigit, isFinite, isNaN, iterator, java, join, jshint,
2914 JSHINT, json, jquery, jQuery, keys, label, labelled, last, lastsemic, laxbreak, laxcomma,
2915 latedef, lbp, led, left, length, line, load, loadClass, localStorage, location,
2916 log, loopfunc, m, match, maxerr, maxlen, member,message, meta, module, moveBy,
2917 moveTo, mootools, multistr, name, navigator, new, newcap, noarg, node, noempty, nomen,
2918 nonew, nonstandard, nud, onbeforeunload, onblur, onerror, onevar, onecase, onfocus,
2919 onload, onresize, onunload, open, openDatabase, openURL, opener, opera, options, outer, param,
2920 parent, parseFloat, parseInt, passfail, plusplus, predef, print, process, prompt,
2921 proto, prototype, prototypejs, provides, push, quit, range, raw, reach, reason, regexp,
2922 readFile, readUrl, regexdash, removeEventListener, replace, report, require,
2923 reserved, resizeBy, resizeTo, resolvePath, resumeUpdates, respond, rhino, right,
2924 runCommand, scroll, screen, scripturl, scrollBy, scrollTo, scrollbar, search, seal,
2925 send, serialize, sessionStorage, setInterval, setTimeout, setter, setterToken, shift, slice,
2926 smarttabs, sort, spawn, split, stack, status, start, strict, sub, substr, supernew, shadow,
2927 supplant, sum, sync, test, toLowerCase, toString, toUpperCase, toint32, token, top, trailing,
2928 type, typeOf, Uint16Array, Uint32Array, Uint8Array, undef, undefs, unused, urls, validthis,
2929 value, valueOf, var, version, WebSocket, withstmt, white, window, Worker, wsh*/
2930
2931 /*global exports: false */
2932
2933 // We build the application inside a function so that we produce only a single
2934 // global variable. That function will be invoked immediately, and its return
2935 // value is the JSHINT function itself.
2936
2937 var JSHINT = (function () {
2938 "use strict";
2939
2940 var anonname, // The guessed name for anonymous functions.
2941
2942 // These are operators that should not be used with the ! operator.
2943
2944 bang = {
2945 '<' : true,
2946 '<=' : true,
2947 '==' : true,
2948 '===': true,
2949 '!==': true,
2950 '!=' : true,
2951 '>' : true,
2952 '>=' : true,
2953 '+' : true,
2954 '-' : true,
2955 '*' : true,
2956 '/' : true,
2957 '%' : true
2958 },
2959
2960 // These are the JSHint boolean options.
2961 boolOptions = {
2962 asi : true, // if automatic semicolon insertion should be tolerated
2963 bitwise : true, // if bitwise operators should not be allowed
2964 boss : true, // if advanced usage of assignments should be allowed
2965 browser : true, // if the standard browser globals should be predefined
2966 couch : true, // if CouchDB globals should be predefined
2967 curly : true, // if curly braces around all blocks should be required
2968 debug : true, // if debugger statements should be allowed
2969 devel : true, // if logging globals should be predefined (console,
2970 // alert, etc.)
2971 dojo : true, // if Dojo Toolkit globals should be predefined
2972 eqeqeq : true, // if === should be required
2973 eqnull : true, // if == null comparisons should be tolerated
2974 es5 : true, // if ES5 syntax should be allowed
2975 esnext : true, // if es.next specific syntax should be allowed
2976 evil : true, // if eval should be allowed
2977 expr : true, // if ExpressionStatement should be allowed as Programs
2978 forin : true, // if for in statements must filter
2979 funcscope : true, // if only function scope should be used for scope tests
2980 globalstrict: true, // if global "use strict"; should be allowed (also
2981 // enables 'strict')
2982 immed : true, // if immediate invocations must be wrapped in parens
2983 iterator : true, // if the `__iterator__` property should be allowed
2984 jquery : true, // if jQuery globals should be predefined
2985 lastsemic : true, // if semicolons may be ommitted for the trailing
2986 // statements inside of a one-line blocks.
2987 latedef : true, // if the use before definition should not be tolerated
2988 laxbreak : true, // if line breaks should not be checked
2989 laxcomma : true, // if line breaks should not be checked around commas
2990 loopfunc : true, // if functions should be allowed to be defined within
2991 // loops
2992 mootools : true, // if MooTools globals should be predefined
2993 multistr : true, // allow multiline strings
2994 newcap : true, // if constructor names must be capitalized
2995 noarg : true, // if arguments.caller and arguments.callee should be
2996 // disallowed
2997 node : true, // if the Node.js environment globals should be
2998 // predefined
2999 noempty : true, // if empty blocks should be disallowed
3000 nonew : true, // if using `new` for side-effects should be disallowed
3001 nonstandard : true, // if non-standard (but widely adopted) globals should
3002 // be predefined
3003 nomen : true, // if names should be checked
3004 onevar : true, // if only one var statement per function should be
3005 // allowed
3006 onecase : true, // if one case switch statements should be allowed
3007 passfail : true, // if the scan should stop on first error
3008 plusplus : true, // if increment/decrement should not be allowed
3009 proto : true, // if the `__proto__` property should be allowed
3010 prototypejs : true, // if Prototype and Scriptaculous globals should be
3011 // predefined
3012 regexdash : true, // if unescaped first/last dash (-) inside brackets
3013 // should be tolerated
3014 regexp : true, // if the . should not be allowed in regexp literals
3015 rhino : true, // if the Rhino environment globals should be predefined
3016 undef : true, // if variables should be declared before used
3017 scripturl : true, // if script-targeted URLs should be tolerated
3018 shadow : true, // if variable shadowing should be tolerated
3019 smarttabs : true, // if smarttabs should be tolerated
3020 // (http://www.emacswiki.org/emacs/SmartTabs)
3021 strict : true, // require the "use strict"; pragma
3022 sub : true, // if all forms of subscript notation are tolerated
3023 supernew : true, // if `new function () { ... };` and `new Object;`
3024 // should be tolerated
3025 trailing : true, // if trailing whitespace rules apply
3026 validthis : true, // if 'this' inside a non-constructor function is valid.
3027 // This is a function scoped option only.
3028 withstmt : true, // if with statements should be allowed
3029 white : true, // if strict whitespace rules apply
3030 wsh : true // if the Windows Scripting Host environment globals
3031 // should be predefined
3032 },
3033
3034 // These are the JSHint options that can take any value
3035 // (we use this object to detect invalid options)
3036 valOptions = {
3037 maxlen: false,
3038 indent: false,
3039 maxerr: false,
3040 predef: false
3041 },
3042
3043
3044 // browser contains a set of global names which are commonly provided by a
3045 // web browser environment.
3046 browser = {
3047 ArrayBuffer : false,
3048 ArrayBufferView : false,
3049 Audio : false,
3050 addEventListener : false,
3051 applicationCache : false,
3052 atob : false,
3053 blur : false,
3054 btoa : false,
3055 clearInterval : false,
3056 clearTimeout : false,
3057 close : false,
3058 closed : false,
3059 DataView : false,
3060 DOMParser : false,
3061 defaultStatus : false,
3062 document : false,
3063 event : false,
3064 FileReader : false,
3065 Float32Array : false,
3066 Float64Array : false,
3067 FormData : false,
3068 focus : false,
3069 frames : false,
3070 getComputedStyle : false,
3071 HTMLElement : false,
3072 HTMLAnchorElement : false,
3073 HTMLBaseElement : false,
3074 HTMLBlockquoteElement : false,
3075 HTMLBodyElement : false,
3076 HTMLBRElement : false,
3077 HTMLButtonElement : false,
3078 HTMLCanvasElement : false,
3079 HTMLDirectoryElement : false,
3080 HTMLDivElement : false,
3081 HTMLDListElement : false,
3082 HTMLFieldSetElement : false,
3083 HTMLFontElement : false,
3084 HTMLFormElement : false,
3085 HTMLFrameElement : false,
3086 HTMLFrameSetElement : false,
3087 HTMLHeadElement : false,
3088 HTMLHeadingElement : false,
3089 HTMLHRElement : false,
3090 HTMLHtmlElement : false,
3091 HTMLIFrameElement : false,
3092 HTMLImageElement : false,
3093 HTMLInputElement : false,
3094 HTMLIsIndexElement : false,
3095 HTMLLabelElement : false,
3096 HTMLLayerElement : false,
3097 HTMLLegendElement : false,
3098 HTMLLIElement : false,
3099 HTMLLinkElement : false,
3100 HTMLMapElement : false,
3101 HTMLMenuElement : false,
3102 HTMLMetaElement : false,
3103 HTMLModElement : false,
3104 HTMLObjectElement : false,
3105 HTMLOListElement : false,
3106 HTMLOptGroupElement : false,
3107 HTMLOptionElement : false,
3108 HTMLParagraphElement : false,
3109 HTMLParamElement : false,
3110 HTMLPreElement : false,
3111 HTMLQuoteElement : false,
3112 HTMLScriptElement : false,
3113 HTMLSelectElement : false,
3114 HTMLStyleElement : false,
3115 HTMLTableCaptionElement : false,
3116 HTMLTableCellElement : false,
3117 HTMLTableColElement : false,
3118 HTMLTableElement : false,
3119 HTMLTableRowElement : false,
3120 HTMLTableSectionElement : false,
3121 HTMLTextAreaElement : false,
3122 HTMLTitleElement : false,
3123 HTMLUListElement : false,
3124 HTMLVideoElement : false,
3125 history : false,
3126 Int16Array : false,
3127 Int32Array : false,
3128 Int8Array : false,
3129 Image : false,
3130 length : false,
3131 localStorage : false,
3132 location : false,
3133 MessageChannel : false,
3134 MessageEvent : false,
3135 MessagePort : false,
3136 moveBy : false,
3137 moveTo : false,
3138 name : false,
3139 navigator : false,
3140 onbeforeunload : true,
3141 onblur : true,
3142 onerror : true,
3143 onfocus : true,
3144 onload : true,
3145 onresize : true,
3146 onunload : true,
3147 open : false,
3148 openDatabase : false,
3149 opener : false,
3150 Option : false,
3151 parent : false,
3152 print : false,
3153 removeEventListener : false,
3154 resizeBy : false,
3155 resizeTo : false,
3156 screen : false,
3157 scroll : false,
3158 scrollBy : false,
3159 scrollTo : false,
3160 sessionStorage : false,
3161 setInterval : false,
3162 setTimeout : false,
3163 SharedWorker : false,
3164 status : false,
3165 top : false,
3166 Uint16Array : false,
3167 Uint32Array : false,
3168 Uint8Array : false,
3169 WebSocket : false,
3170 window : false,
3171 Worker : false,
3172 XMLHttpRequest : false,
3173 XMLSerializer : false,
3174 XPathEvaluator : false,
3175 XPathException : false,
3176 XPathExpression : false,
3177 XPathNamespace : false,
3178 XPathNSResolver : false,
3179 XPathResult : false
3180 },
3181
3182 couch = {
3183 "require" : false,
3184 respond : false,
3185 getRow : false,
3186 emit : false,
3187 send : false,
3188 start : false,
3189 sum : false,
3190 log : false,
3191 exports : false,
3192 module : false,
3193 provides : false
3194 },
3195
3196 devel = {
3197 alert : false,
3198 confirm : false,
3199 console : false,
3200 Debug : false,
3201 opera : false,
3202 prompt : false
3203 },
3204
3205 dojo = {
3206 dojo : false,
3207 dijit : false,
3208 dojox : false,
3209 define : false,
3210 "require" : false
3211 },
3212
3213 escapes = {
3214 '\b': '\\b',
3215 '\t': '\\t',
3216 '\n': '\\n',
3217 '\f': '\\f',
3218 '\r': '\\r',
3219 '"' : '\\"',
3220 '/' : '\\/',
3221 '\\': '\\\\'
3222 },
3223
3224 funct, // The current function
3225
3226 functionicity = [
3227 'closure', 'exception', 'global', 'label',
3228 'outer', 'unused', 'var'
3229 ],
3230
3231 functions, // All of the functions
3232
3233 global, // The global scope
3234 implied, // Implied globals
3235 inblock,
3236 indent,
3237 jsonmode,
3238
3239 jquery = {
3240 '$' : false,
3241 jQuery : false
3242 },
3243
3244 lines,
3245 lookahead,
3246 member,
3247 membersOnly,
3248
3249 mootools = {
3250 '$' : false,
3251 '$$' : false,
3252 Assets : false,
3253 Browser : false,
3254 Chain : false,
3255 Class : false,
3256 Color : false,
3257 Cookie : false,
3258 Core : false,
3259 Document : false,
3260 DomReady : false,
3261 DOMReady : false,
3262 Drag : false,
3263 Element : false,
3264 Elements : false,
3265 Event : false,
3266 Events : false,
3267 Fx : false,
3268 Group : false,
3269 Hash : false,
3270 HtmlTable : false,
3271 Iframe : false,
3272 IframeShim : false,
3273 InputValidator : false,
3274 instanceOf : false,
3275 Keyboard : false,
3276 Locale : false,
3277 Mask : false,
3278 MooTools : false,
3279 Native : false,
3280 Options : false,
3281 OverText : false,
3282 Request : false,
3283 Scroller : false,
3284 Slick : false,
3285 Slider : false,
3286 Sortables : false,
3287 Spinner : false,
3288 Swiff : false,
3289 Tips : false,
3290 Type : false,
3291 typeOf : false,
3292 URI : false,
3293 Window : false
3294 },
3295
3296 nexttoken,
3297
3298 node = {
3299 __filename : false,
3300 __dirname : false,
3301 Buffer : false,
3302 console : false,
3303 exports : false,
3304 GLOBAL : false,
3305 global : false,
3306 module : false,
3307 process : false,
3308 require : false,
3309 setTimeout : false,
3310 clearTimeout : false,
3311 setInterval : false,
3312 clearInterval : false
3313 },
3314
3315 noreach,
3316 option,
3317 predefined, // Global variables defined by option
3318 prereg,
3319 prevtoken,
3320
3321 prototypejs = {
3322 '$' : false,
3323 '$$' : false,
3324 '$A' : false,
3325 '$F' : false,
3326 '$H' : false,
3327 '$R' : false,
3328 '$break' : false,
3329 '$continue' : false,
3330 '$w' : false,
3331 Abstract : false,
3332 Ajax : false,
3333 Class : false,
3334 Enumerable : false,
3335 Element : false,
3336 Event : false,
3337 Field : false,
3338 Form : false,
3339 Hash : false,
3340 Insertion : false,
3341 ObjectRange : false,
3342 PeriodicalExecuter: false,
3343 Position : false,
3344 Prototype : false,
3345 Selector : false,
3346 Template : false,
3347 Toggle : false,
3348 Try : false,
3349 Autocompleter : false,
3350 Builder : false,
3351 Control : false,
3352 Draggable : false,
3353 Draggables : false,
3354 Droppables : false,
3355 Effect : false,
3356 Sortable : false,
3357 SortableObserver : false,
3358 Sound : false,
3359 Scriptaculous : false
3360 },
3361
3362 rhino = {
3363 defineClass : false,
3364 deserialize : false,
3365 gc : false,
3366 help : false,
3367 importPackage: false,
3368 "java" : false,
3369 load : false,
3370 loadClass : false,
3371 print : false,
3372 quit : false,
3373 readFile : false,
3374 readUrl : false,
3375 runCommand : false,
3376 seal : false,
3377 serialize : false,
3378 spawn : false,
3379 sync : false,
3380 toint32 : false,
3381 version : false
3382 },
3383
3384 scope, // The current scope
3385 stack,
3386
3387 // standard contains the global names that are provided by the
3388 // ECMAScript standard.
3389 standard = {
3390 Array : false,
3391 Boolean : false,
3392 Date : false,
3393 decodeURI : false,
3394 decodeURIComponent : false,
3395 encodeURI : false,
3396 encodeURIComponent : false,
3397 Error : false,
3398 'eval' : false,
3399 EvalError : false,
3400 Function : false,
3401 hasOwnProperty : false,
3402 isFinite : false,
3403 isNaN : false,
3404 JSON : false,
3405 Math : false,
3406 Number : false,
3407 Object : false,
3408 parseInt : false,
3409 parseFloat : false,
3410 RangeError : false,
3411 ReferenceError : false,
3412 RegExp : false,
3413 String : false,
3414 SyntaxError : false,
3415 TypeError : false,
3416 URIError : false
3417 },
3418
3419 // widely adopted global names that are not part of ECMAScript standard
3420 nonstandard = {
3421 escape : false,
3422 unescape : false
3423 },
3424
3425 standard_member = {
3426 E : true,
3427 LN2 : true,
3428 LN10 : true,
3429 LOG2E : true,
3430 LOG10E : true,
3431 MAX_VALUE : true,
3432 MIN_VALUE : true,
3433 NEGATIVE_INFINITY : true,
3434 PI : true,
3435 POSITIVE_INFINITY : true,
3436 SQRT1_2 : true,
3437 SQRT2 : true
3438 },
3439
3440 directive,
3441 syntax = {},
3442 tab,
3443 token,
3444 urls,
3445 useESNextSyntax,
3446 warnings,
3447
3448 wsh = {
3449 ActiveXObject : true,
3450 Enumerator : true,
3451 GetObject : true,
3452 ScriptEngine : true,
3453 ScriptEngineBuildVersion : true,
3454 ScriptEngineMajorVersion : true,
3455 ScriptEngineMinorVersion : true,
3456 VBArray : true,
3457 WSH : true,
3458 WScript : true,
3459 XDomainRequest : true
3460 };
3461
3462 // Regular expressions. Some of these are stupidly long.
3463 var ax, cx, tx, nx, nxg, lx, ix, jx, ft;
3464 (function () {
3465 /*jshint maxlen:300 */
3466
3467 // unsafe comment or string
3468 ax = /@cc|<\/?|script|\]\s*\]|<\s*!|&lt/i;
3469
3470 // unsafe characters that are silently deleted by one or more browsers
3471 cx = /[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/;
3472
3473 // token
3474 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]+)?)/;
3475
3476 // characters in strings that need escapement
3477 nx = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/;
3478 nxg = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
3479
3480 // star slash
3481 lx = /\*\/|\/\*/;
3482
3483 // identifier
3484 ix = /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/;
3485
3486 // javascript url
3487 jx = /^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i;
3488
3489 // catches /* falls through */ comments
3490 ft = /^\s*\/\*\s*falls\sthrough\s*\*\/\s*$/;
3491 }());
3492
3493 function F() {} // Used by Object.create
3494
3495 function is_own(object, name) {
3496
3497 // The object.hasOwnProperty method fails when the property under consideration
3498 // is named 'hasOwnProperty'. So we have to use this more convoluted form.
3499
3500 return Object.prototype.hasOwnProperty.call(object, name);
3501 }
3502
3503 function checkOption(name, t) {
3504 if (valOptions[name] === undefined && boolOptions[name] === undefined) {
3505 warning("Bad option: '" + name + "'.", t);
3506 }
3507 }
3508
3509 // Provide critical ES5 functions to ES3.
3510
3511 if (typeof Array.isArray !== 'function') {
3512 Array.isArray = function (o) {
3513 return Object.prototype.toString.apply(o) === '[object Array]';
3514 };
3515 }
3516
3517 if (typeof Object.create !== 'function') {
3518 Object.create = function (o) {
3519 F.prototype = o;
3520 return new F();
3521 };
3522 }
3523
3524 if (typeof Object.keys !== 'function') {
3525 Object.keys = function (o) {
3526 var a = [], k;
3527 for (k in o) {
3528 if (is_own(o, k)) {
3529 a.push(k);
3530 }
3531 }
3532 return a;
3533 };
3534 }
3535
3536 // Non standard methods
3537
3538 if (typeof String.prototype.entityify !== 'function') {
3539 String.prototype.entityify = function () {
3540 return this
3541 .replace(/&/g, '&amp;')
3542 .replace(/</g, '&lt;')
3543 .replace(/>/g, '&gt;');
3544 };
3545 }
3546
3547 if (typeof String.prototype.isAlpha !== 'function') {
3548 String.prototype.isAlpha = function () {
3549 return (this >= 'a' && this <= 'z\uffff') ||
3550 (this >= 'A' && this <= 'Z\uffff');
3551 };
3552 }
3553
3554 if (typeof String.prototype.isDigit !== 'function') {
3555 String.prototype.isDigit = function () {
3556 return (this >= '0' && this <= '9');
3557 };
3558 }
3559
3560 if (typeof String.prototype.supplant !== 'function') {
3561 String.prototype.supplant = function (o) {
3562 return this.replace(/\{([^{}]*)\}/g, function (a, b) {
3563 var r = o[b];
3564 return typeof r === 'string' || typeof r === 'number' ? r : a;
3565 });
3566 };
3567 }
3568
3569 if (typeof String.prototype.name !== 'function') {
3570 String.prototype.name = function () {
3571
3572 // If the string looks like an identifier, then we can return it as is.
3573 // If the string contains no control characters, no quote characters, and no
3574 // backslash characters, then we can simply slap some quotes around it.
3575 // Otherwise we must also replace the offending characters with safe
3576 // sequences.
3577
3578 if (ix.test(this)) {
3579 return this;
3580 }
3581 if (nx.test(this)) {
3582 return '"' + this.replace(nxg, function (a) {
3583 var c = escapes[a];
3584 if (c) {
3585 return c;
3586 }
3587 return '\\u' + ('0000' + a.charCodeAt().toString(16)).slice(-4);
3588 }) + '"';
3589 }
3590 return '"' + this + '"';
3591 };
3592 }
3593
3594
3595 function combine(t, o) {
3596 var n;
3597 for (n in o) {
3598 if (is_own(o, n)) {
3599 t[n] = o[n];
3600 }
3601 }
3602 }
3603
3604 function assume() {
3605 if (option.couch) {
3606 combine(predefined, couch);
3607 }
3608
3609 if (option.rhino) {
3610 combine(predefined, rhino);
3611 }
3612
3613 if (option.prototypejs) {
3614 combine(predefined, prototypejs);
3615 }
3616
3617 if (option.node) {
3618 combine(predefined, node);
3619 option.globalstrict = true;
3620 }
3621
3622 if (option.devel) {
3623 combine(predefined, devel);
3624 }
3625
3626 if (option.dojo) {
3627 combine(predefined, dojo);
3628 }
3629
3630 if (option.browser) {
3631 combine(predefined, browser);
3632 }
3633
3634 if (option.nonstandard) {
3635 combine(predefined, nonstandard);
3636 }
3637
3638 if (option.jquery) {
3639 combine(predefined, jquery);
3640 }
3641
3642 if (option.mootools) {
3643 combine(predefined, mootools);
3644 }
3645
3646 if (option.wsh) {
3647 combine(predefined, wsh);
3648 }
3649
3650 if (option.esnext) {
3651 useESNextSyntax();
3652 }
3653
3654 if (option.globalstrict && option.strict !== false) {
3655 option.strict = true;
3656 }
3657 }
3658
3659
3660 // Produce an error warning.
3661 function quit(message, line, chr) {
3662 var percentage = Math.floor((line / lines.length) * 100);
3663
3664 throw {
3665 name: 'JSHintError',
3666 line: line,
3667 character: chr,
3668 message: message + " (" + percentage + "% scanned).",
3669 raw: message
3670 };
3671 }
3672
3673 function isundef(scope, m, t, a) {
3674 return JSHINT.undefs.push([scope, m, t, a]);
3675 }
3676
3677 function warning(m, t, a, b, c, d) {
3678 var ch, l, w;
3679 t = t || nexttoken;
3680 if (t.id === '(end)') { // `~
3681 t = token;
3682 }
3683 l = t.line || 0;
3684 ch = t.from || 0;
3685 w = {
3686 id: '(error)',
3687 raw: m,
3688 evidence: lines[l - 1] || '',
3689 line: l,
3690 character: ch,
3691 a: a,
3692 b: b,
3693 c: c,
3694 d: d
3695 };
3696 w.reason = m.supplant(w);
3697 JSHINT.errors.push(w);
3698 if (option.passfail) {
3699 quit('Stopping. ', l, ch);
3700 }
3701 warnings += 1;
3702 if (warnings >= option.maxerr) {
3703 quit("Too many errors.", l, ch);
3704 }
3705 return w;
3706 }
3707
3708 function warningAt(m, l, ch, a, b, c, d) {
3709 return warning(m, {
3710 line: l,
3711 from: ch
3712 }, a, b, c, d);
3713 }
3714
3715 function error(m, t, a, b, c, d) {
3716 var w = warning(m, t, a, b, c, d);
3717 }
3718
3719 function errorAt(m, l, ch, a, b, c, d) {
3720 return error(m, {
3721 line: l,
3722 from: ch
3723 }, a, b, c, d);
3724 }
3725
3726
3727
3728 // lexical analysis and token construction
3729
3730 var lex = (function lex() {
3731 var character, from, line, s;
3732
3733 // Private lex methods
3734
3735 function nextLine() {
3736 var at,
3737 tw; // trailing whitespace check
3738
3739 if (line >= lines.length)
3740 return false;
3741
3742 character = 1;
3743 s = lines[line];
3744 line += 1;
3745
3746 // If smarttabs option is used check for spaces followed by tabs only.
3747 // Otherwise check for any occurence of mixed tabs and spaces.
3748 if (option.smarttabs)
3749 at = s.search(/ \t/);
3750 else
3751 at = s.search(/ \t|\t /);
3752
3753 if (at >= 0)
3754 warningAt("Mixed spaces and tabs.", line, at + 1);
3755
3756 s = s.replace(/\t/g, tab);
3757 at = s.search(cx);
3758
3759 if (at >= 0)
3760 warningAt("Unsafe character.", line, at);
3761
3762 if (option.maxlen && option.maxlen < s.length)
3763 warningAt("Line too long.", line, s.length);
3764
3765 // Check for trailing whitespaces
3766 tw = option.trailing && s.match(/^(.*?)\s+$/);
3767 if (tw && !/^\s+$/.test(s)) {
3768 warningAt("Trailing whitespace.", line, tw[1].length + 1);
3769 }
3770 return true;
3771 }
3772
3773 // Produce a token object. The token inherits from a syntax symbol.
3774
3775 function it(type, value) {
3776 var i, t;
3777 if (type === '(color)' || type === '(range)') {
3778 t = {type: type};
3779 } else if (type === '(punctuator)' ||
3780 (type === '(identifier)' && is_own(syntax, value))) {
3781 t = syntax[value] || syntax['(error)'];
3782 } else {
3783 t = syntax[type];
3784 }
3785 t = Object.create(t);
3786 if (type === '(string)' || type === '(range)') {
3787 if (!option.scripturl && jx.test(value)) {
3788 warningAt("Script URL.", line, from);
3789 }
3790 }
3791 if (type === '(identifier)') {
3792 t.identifier = true;
3793 if (value === '__proto__' && !option.proto) {
3794 warningAt("The '{a}' property is deprecated.",
3795 line, from, value);
3796 } else if (value === '__iterator__' && !option.iterator) {
3797 warningAt("'{a}' is only available in JavaScript 1.7.",
3798 line, from, value);
3799 } else if (option.nomen && (value.charAt(0) === '_' ||
3800 value.charAt(value.length - 1) === '_')) {
3801 if (!option.node || token.id === '.' ||
3802 (value !== '__dirname' && value !== '__filename')) {
3803 warningAt("Unexpected {a} in '{b}'.", line, from, "dangling '_'", value);
3804 }
3805 }
3806 }
3807 t.value = value;
3808 t.line = line;
3809 t.character = character;
3810 t.from = from;
3811 i = t.id;
3812 if (i !== '(endline)') {
3813 prereg = i &&
3814 (('(,=:[!&|?{};'.indexOf(i.charAt(i.length - 1)) >= 0) ||
3815 i === 'return' ||
3816 i === 'case');
3817 }
3818 return t;
3819 }
3820
3821 // Public lex methods
3822 return {
3823 init: function (source) {
3824 if (typeof source === 'string') {
3825 lines = source
3826 .replace(/\r\n/g, '\n')
3827 .replace(/\r/g, '\n')
3828 .split('\n');
3829 } else {
3830 lines = source;
3831 }
3832
3833 // If the first line is a shebang (#!), make it a blank and move on.
3834 // Shebangs are used by Node scripts.
3835 if (lines[0] && lines[0].substr(0, 2) === '#!')
3836 lines[0] = '';
3837
3838 line = 0;
3839 nextLine();
3840 from = 1;
3841 },
3842
3843 range: function (begin, end) {
3844 var c, value = '';
3845 from = character;
3846 if (s.charAt(0) !== begin) {
3847 errorAt("Expected '{a}' and instead saw '{b}'.",
3848 line, character, begin, s.charAt(0));
3849 }
3850 for (;;) {
3851 s = s.slice(1);
3852 character += 1;
3853 c = s.charAt(0);
3854 switch (c) {
3855 case '':
3856 errorAt("Missing '{a}'.", line, character, c);
3857 break;
3858 case end:
3859 s = s.slice(1);
3860 character += 1;
3861 return it('(range)', value);
3862 case '\\':
3863 warningAt("Unexpected '{a}'.", line, character, c);
3864 }
3865 value += c;
3866 }
3867
3868 },
3869
3870
3871 // token -- this is called by advance to get the next token
3872 token: function () {
3873 var b, c, captures, d, depth, high, i, l, low, q, t, isLiteral, isInRange, n;
3874
3875 function match(x) {
3876 var r = x.exec(s), r1;
3877 if (r) {
3878 l = r[0].length;
3879 r1 = r[1];
3880 c = r1.charAt(0);
3881 s = s.substr(l);
3882 from = character + l - r1.length;
3883 character += l;
3884 return r1;
3885 }
3886 }
3887
3888 function string(x) {
3889 var c, j, r = '', allowNewLine = false;
3890
3891 if (jsonmode && x !== '"') {
3892 warningAt("Strings must use doublequote.",
3893 line, character);
3894 }
3895
3896 function esc(n) {
3897 var i = parseInt(s.substr(j + 1, n), 16);
3898 j += n;
3899 if (i >= 32 && i <= 126 &&
3900 i !== 34 && i !== 92 && i !== 39) {
3901 warningAt("Unnecessary escapement.", line, character);
3902 }
3903 character += n;
3904 c = String.fromCharCode(i);
3905 }
3906 j = 0;
3907 unclosedString: for (;;) {
3908 while (j >= s.length) {
3909 j = 0;
3910
3911 var cl = line, cf = from;
3912 if (!nextLine()) {
3913 errorAt("Unclosed string.", cl, cf);
3914 break unclosedString;
3915 }
3916
3917 if (allowNewLine) {
3918 allowNewLine = false;
3919 } else {
3920 warningAt("Unclosed string.", cl, cf);
3921 }
3922 }
3923 c = s.charAt(j);
3924 if (c === x) {
3925 character += 1;
3926 s = s.substr(j + 1);
3927 return it('(string)', r, x);
3928 }
3929 if (c < ' ') {
3930 if (c === '\n' || c === '\r') {
3931 break;
3932 }
3933 warningAt("Control character in string: {a}.",
3934 line, character + j, s.slice(0, j));
3935 } else if (c === '\\') {
3936 j += 1;
3937 character += 1;
3938 c = s.charAt(j);
3939 n = s.charAt(j + 1);
3940 switch (c) {
3941 case '\\':
3942 case '"':
3943 case '/':
3944 break;
3945 case '\'':
3946 if (jsonmode) {
3947 warningAt("Avoid \\'.", line, character);
3948 }
3949 break;
3950 case 'b':
3951 c = '\b';
3952 break;
3953 case 'f':
3954 c = '\f';
3955 break;
3956 case 'n':
3957 c = '\n';
3958 break;
3959 case 'r':
3960 c = '\r';
3961 break;
3962 case 't':
3963 c = '\t';
3964 break;
3965 case '0':
3966 c = '\0';
3967 // Octal literals fail in strict mode
3968 // check if the number is between 00 and 07
3969 // where 'n' is the token next to 'c'
3970 if (n >= 0 && n <= 7 && directive["use strict"]) {
3971 warningAt(
3972 "Octal literals are not allowed in strict mode.",
3973 line, character);
3974 }
3975 break;
3976 case 'u':
3977 esc(4);
3978 break;
3979 case 'v':
3980 if (jsonmode) {
3981 warningAt("Avoid \\v.", line, character);
3982 }
3983 c = '\v';
3984 break;
3985 case 'x':
3986 if (jsonmode) {
3987 warningAt("Avoid \\x-.", line, character);
3988 }
3989 esc(2);
3990 break;
3991 case '':
3992 // last character is escape character
3993 // always allow new line if escaped, but show
3994 // warning if option is not set
3995 allowNewLine = true;
3996 if (option.multistr) {
3997 if (jsonmode) {
3998 warningAt("Avoid EOL escapement.", line, character);
3999 }
4000 c = '';
4001 character -= 1;
4002 break;
4003 }
4004 warningAt("Bad escapement of EOL. Use option multistr if needed.",
4005 line, character);
4006 break;
4007 default:
4008 warningAt("Bad escapement.", line, character);
4009 }
4010 }
4011 r += c;
4012 character += 1;
4013 j += 1;
4014 }
4015 }
4016
4017 for (;;) {
4018 if (!s) {
4019 return it(nextLine() ? '(endline)' : '(end)', '');
4020 }
4021 t = match(tx);
4022 if (!t) {
4023 t = '';
4024 c = '';
4025 while (s && s < '!') {
4026 s = s.substr(1);
4027 }
4028 if (s) {
4029 errorAt("Unexpected '{a}'.", line, character, s.substr(0, 1));
4030 s = '';
4031 }
4032 } else {
4033
4034 // identifier
4035
4036 if (c.isAlpha() || c === '_' || c === '$') {
4037 return it('(identifier)', t);
4038 }
4039
4040 // number
4041
4042 if (c.isDigit()) {
4043 if (!isFinite(Number(t))) {
4044 warningAt("Bad number '{a}'.",
4045 line, character, t);
4046 }
4047 if (s.substr(0, 1).isAlpha()) {
4048 warningAt("Missing space after '{a}'.",
4049 line, character, t);
4050 }
4051 if (c === '0') {
4052 d = t.substr(1, 1);
4053 if (d.isDigit()) {
4054 if (token.id !== '.') {
4055 warningAt("Don't use extra leading zeros '{a}'.",
4056 line, character, t);
4057 }
4058 } else if (jsonmode && (d === 'x' || d === 'X')) {
4059 warningAt("Avoid 0x-. '{a}'.",
4060 line, character, t);
4061 }
4062 }
4063 if (t.substr(t.length - 1) === '.') {
4064 warningAt(
4065 "A trailing decimal point can be confused with a dot '{a}'.", line, character, t);
4066 }
4067 return it('(number)', t);
4068 }
4069 switch (t) {
4070
4071 // string
4072
4073 case '"':
4074 case "'":
4075 return string(t);
4076
4077 // // comment
4078
4079 case '//':
4080 s = '';
4081 token.comment = true;
4082 break;
4083
4084 // /* comment
4085
4086 case '/*':
4087 for (;;) {
4088 i = s.search(lx);
4089 if (i >= 0) {
4090 break;
4091 }
4092 if (!nextLine()) {
4093 errorAt("Unclosed comment.", line, character);
4094 }
4095 }
4096 character += i + 2;
4097 if (s.substr(i, 1) === '/') {
4098 errorAt("Nested comment.", line, character);
4099 }
4100 s = s.substr(i + 2);
4101 token.comment = true;
4102 break;
4103
4104 // /*members /*jshint /*global
4105
4106 case '/*members':
4107 case '/*member':
4108 case '/*jshint':
4109 case '/*jslint':
4110 case '/*global':
4111 case '*/':
4112 return {
4113 value: t,
4114 type: 'special',
4115 line: line,
4116 character: character,
4117 from: from
4118 };
4119
4120 case '':
4121 break;
4122 // /
4123 case '/':
4124 if (token.id === '/=') {
4125 errorAt("A regular expression literal can be confused with '/='.",
4126 line, from);
4127 }
4128 if (prereg) {
4129 depth = 0;
4130 captures = 0;
4131 l = 0;
4132 for (;;) {
4133 b = true;
4134 c = s.charAt(l);
4135 l += 1;
4136 switch (c) {
4137 case '':
4138 errorAt("Unclosed regular expression.", line, from);
4139 return quit('Stopping.', line, from);
4140 case '/':
4141 if (depth > 0) {
4142 warningAt("{a} unterminated regular expression " +
4143 "group(s).", line, from + l, depth);
4144 }
4145 c = s.substr(0, l - 1);
4146 q = {
4147 g: true,
4148 i: true,
4149 m: true
4150 };
4151 while (q[s.charAt(l)] === true) {
4152 q[s.charAt(l)] = false;
4153 l += 1;
4154 }
4155 character += l;
4156 s = s.substr(l);
4157 q = s.charAt(0);
4158 if (q === '/' || q === '*') {
4159 errorAt("Confusing regular expression.",
4160 line, from);
4161 }
4162 return it('(regexp)', c);
4163 case '\\':
4164 c = s.charAt(l);
4165 if (c < ' ') {
4166 warningAt(
4167 "Unexpected control character in regular expression.", line, from + l);
4168 } else if (c === '<') {
4169 warningAt(
4170 "Unexpected escaped character '{a}' in regular expression.", line, from + l, c);
4171 }
4172 l += 1;
4173 break;
4174 case '(':
4175 depth += 1;
4176 b = false;
4177 if (s.charAt(l) === '?') {
4178 l += 1;
4179 switch (s.charAt(l)) {
4180 case ':':
4181 case '=':
4182 case '!':
4183 l += 1;
4184 break;
4185 default:
4186 warningAt(
4187 "Expected '{a}' and instead saw '{b}'.", line, from + l, ':', s.charAt(l));
4188 }
4189 } else {
4190 captures += 1;
4191 }
4192 break;
4193 case '|':
4194 b = false;
4195 break;
4196 case ')':
4197 if (depth === 0) {
4198 warningAt("Unescaped '{a}'.",
4199 line, from + l, ')');
4200 } else {
4201 depth -= 1;
4202 }
4203 break;
4204 case ' ':
4205 q = 1;
4206 while (s.charAt(l) === ' ') {
4207 l += 1;
4208 q += 1;
4209 }
4210 if (q > 1) {
4211 warningAt(
4212 "Spaces are hard to count. Use {{a}}.", line, from + l, q);
4213 }
4214 break;
4215 case '[':
4216 c = s.charAt(l);
4217 if (c === '^') {
4218 l += 1;
4219 if (option.regexp) {
4220 warningAt("Insecure '{a}'.",
4221 line, from + l, c);
4222 } else if (s.charAt(l) === ']') {
4223 errorAt("Unescaped '{a}'.",
4224 line, from + l, '^');
4225 }
4226 }
4227 if (c === ']') {
4228 warningAt("Empty class.", line,
4229 from + l - 1);
4230 }
4231 isLiteral = false;
4232 isInRange = false;
4233 klass: do {
4234 c = s.charAt(l);
4235 l += 1;
4236 switch (c) {
4237 case '[':
4238 case '^':
4239 warningAt("Unescaped '{a}'.",
4240 line, from + l, c);
4241 if (isInRange) {
4242 isInRange = false;
4243 } else {
4244 isLiteral = true;
4245 }
4246 break;
4247 case '-':
4248 if (isLiteral && !isInRange) {
4249 isLiteral = false;
4250 isInRange = true;
4251 } else if (isInRange) {
4252 isInRange = false;
4253 } else if (s.charAt(l) === ']') {
4254 isInRange = true;
4255 } else {
4256 if (option.regexdash !== (l === 2 || (l === 3 &&
4257 s.charAt(1) === '^'))) {
4258 warningAt("Unescaped '{a}'.",
4259 line, from + l - 1, '-');
4260 }
4261 isLiteral = true;
4262 }
4263 break;
4264 case ']':
4265 if (isInRange && !option.regexdash) {
4266 warningAt("Unescaped '{a}'.",
4267 line, from + l - 1, '-');
4268 }
4269 break klass;
4270 case '\\':
4271 c = s.charAt(l);
4272 if (c < ' ') {
4273 warningAt(
4274 "Unexpected control character in regular expression.", line, from + l);
4275 } else if (c === '<') {
4276 warningAt(
4277 "Unexpected escaped character '{a}' in regular expression.", line, from + l, c);
4278 }
4279 l += 1;
4280
4281 // \w, \s and \d are never part of a character range
4282 if (/[wsd]/i.test(c)) {
4283 if (isInRange) {
4284 warningAt("Unescaped '{a}'.",
4285 line, from + l, '-');
4286 isInRange = false;
4287 }
4288 isLiteral = false;
4289 } else if (isInRange) {
4290 isInRange = false;
4291 } else {
4292 isLiteral = true;
4293 }
4294 break;
4295 case '/':
4296 warningAt("Unescaped '{a}'.",
4297 line, from + l - 1, '/');
4298
4299 if (isInRange) {
4300 isInRange = false;
4301 } else {
4302 isLiteral = true;
4303 }
4304 break;
4305 case '<':
4306 if (isInRange) {
4307 isInRange = false;
4308 } else {
4309 isLiteral = true;
4310 }
4311 break;
4312 default:
4313 if (isInRange) {
4314 isInRange = false;
4315 } else {
4316 isLiteral = true;
4317 }
4318 }
4319 } while (c);
4320 break;
4321 case '.':
4322 if (option.regexp) {
4323 warningAt("Insecure '{a}'.", line,
4324 from + l, c);
4325 }
4326 break;
4327 case ']':
4328 case '?':
4329 case '{':
4330 case '}':
4331 case '+':
4332 case '*':
4333 warningAt("Unescaped '{a}'.", line,
4334 from + l, c);
4335 }
4336 if (b) {
4337 switch (s.charAt(l)) {
4338 case '?':
4339 case '+':
4340 case '*':
4341 l += 1;
4342 if (s.charAt(l) === '?') {
4343 l += 1;
4344 }
4345 break;
4346 case '{':
4347 l += 1;
4348 c = s.charAt(l);
4349 if (c < '0' || c > '9') {
4350 warningAt(
4351 "Expected a number and instead saw '{a}'.", line, from + l, c);
4352 }
4353 l += 1;
4354 low = +c;
4355 for (;;) {
4356 c = s.charAt(l);
4357 if (c < '0' || c > '9') {
4358 break;
4359 }
4360 l += 1;
4361 low = +c + (low * 10);
4362 }
4363 high = low;
4364 if (c === ',') {
4365 l += 1;
4366 high = Infinity;
4367 c = s.charAt(l);
4368 if (c >= '0' && c <= '9') {
4369 l += 1;
4370 high = +c;
4371 for (;;) {
4372 c = s.charAt(l);
4373 if (c < '0' || c > '9') {
4374 break;
4375 }
4376 l += 1;
4377 high = +c + (high * 10);
4378 }
4379 }
4380 }
4381 if (s.charAt(l) !== '}') {
4382 warningAt(
4383 "Expected '{a}' and instead saw '{b}'.", line, from + l, '}', c);
4384 } else {
4385 l += 1;
4386 }
4387 if (s.charAt(l) === '?') {
4388 l += 1;
4389 }
4390 if (low > high) {
4391 warningAt(
4392 "'{a}' should not be greater than '{b}'.", line, from + l, low, high);
4393 }
4394 }
4395 }
4396 }
4397 c = s.substr(0, l - 1);
4398 character += l;
4399 s = s.substr(l);
4400 return it('(regexp)', c);
4401 }
4402 return it('(punctuator)', t);
4403
4404 // punctuator
4405
4406 case '#':
4407 return it('(punctuator)', t);
4408 default:
4409 return it('(punctuator)', t);
4410 }
4411 }
4412 }
4413 }
4414 };
4415 }());
4416
4417
4418 function addlabel(t, type) {
4419
4420 if (t === 'hasOwnProperty') {
4421 warning("'hasOwnProperty' is a really bad name.");
4422 }
4423
4424 // Define t in the current function in the current scope.
4425 if (is_own(funct, t) && !funct['(global)']) {
4426 if (funct[t] === true) {
4427 if (option.latedef)
4428 warning("'{a}' was used before it was defined.", nexttoken, t);
4429 } else {
4430 if (!option.shadow && type !== "exception")
4431 warning("'{a}' is already defined.", nexttoken, t);
4432 }
4433 }
4434
4435 funct[t] = type;
4436 if (funct['(global)']) {
4437 global[t] = funct;
4438 if (is_own(implied, t)) {
4439 if (option.latedef)
4440 warning("'{a}' was used before it was defined.", nexttoken, t);
4441 delete implied[t];
4442 }
4443 } else {
4444 scope[t] = funct;
4445 }
4446 }
4447
4448
4449 function doOption() {
4450 var b, obj, filter, o = nexttoken.value, t, v;
4451
4452 switch (o) {
4453 case '*/':
4454 error("Unbegun comment.");
4455 break;
4456 case '/*members':
4457 case '/*member':
4458 o = '/*members';
4459 if (!membersOnly) {
4460 membersOnly = {};
4461 }
4462 obj = membersOnly;
4463 break;
4464 case '/*jshint':
4465 case '/*jslint':
4466 obj = option;
4467 filter = boolOptions;
4468 break;
4469 case '/*global':
4470 obj = predefined;
4471 break;
4472 default:
4473 error("What?");
4474 }
4475
4476 t = lex.token();
4477 loop: for (;;) {
4478 for (;;) {
4479 if (t.type === 'special' && t.value === '*/') {
4480 break loop;
4481 }
4482 if (t.id !== '(endline)' && t.id !== ',') {
4483 break;
4484 }
4485 t = lex.token();
4486 }
4487 if (t.type !== '(string)' && t.type !== '(identifier)' &&
4488 o !== '/*members') {
4489 error("Bad option.", t);
4490 }
4491
4492 v = lex.token();
4493 if (v.id === ':') {
4494 v = lex.token();
4495
4496 if (obj === membersOnly) {
4497 error("Expected '{a}' and instead saw '{b}'.",
4498 t, '*/', ':');
4499 }
4500
4501 if (o === '/*jshint') {
4502 checkOption(t.value, t);
4503 }
4504
4505 if (t.value === 'indent' && (o === '/*jshint' || o === '/*jslint')) {
4506 b = +v.value;
4507 if (typeof b !== 'number' || !isFinite(b) || b <= 0 ||
4508 Math.floor(b) !== b) {
4509 error("Expected a small integer and instead saw '{a}'.",
4510 v, v.value);
4511 }
4512 obj.white = true;
4513 obj.indent = b;
4514 } else if (t.value === 'maxerr' && (o === '/*jshint' || o === '/*jslint')) {
4515 b = +v.value;
4516 if (typeof b !== 'number' || !isFinite(b) || b <= 0 ||
4517 Math.floor(b) !== b) {
4518 error("Expected a small integer and instead saw '{a}'.",
4519 v, v.value);
4520 }
4521 obj.maxerr = b;
4522 } else if (t.value === 'maxlen' && (o === '/*jshint' || o === '/*jslint')) {
4523 b = +v.value;
4524 if (typeof b !== 'number' || !isFinite(b) || b <= 0 ||
4525 Math.floor(b) !== b) {
4526 error("Expected a small integer and instead saw '{a}'.",
4527 v, v.value);
4528 }
4529 obj.maxlen = b;
4530 } else if (t.value === 'validthis') {
4531 if (funct['(global)']) {
4532 error("Option 'validthis' can't be used in a global scope.");
4533 } else {
4534 if (v.value === 'true' || v.value === 'false')
4535 obj[t.value] = v.value === 'true';
4536 else
4537 error("Bad option value.", v);
4538 }
4539 } else if (v.value === 'true') {
4540 obj[t.value] = true;
4541 } else if (v.value === 'false') {
4542 obj[t.value] = false;
4543 } else {
4544 error("Bad option value.", v);
4545 }
4546 t = lex.token();
4547 } else {
4548 if (o === '/*jshint' || o === '/*jslint') {
4549 error("Missing option value.", t);
4550 }
4551 obj[t.value] = false;
4552 t = v;
4553 }
4554 }
4555 if (filter) {
4556 assume();
4557 }
4558 }
4559
4560
4561 // We need a peek function. If it has an argument, it peeks that much farther
4562 // ahead. It is used to distinguish
4563 // for ( var i in ...
4564 // from
4565 // for ( var i = ...
4566
4567 function peek(p) {
4568 var i = p || 0, j = 0, t;
4569
4570 while (j <= i) {
4571 t = lookahead[j];
4572 if (!t) {
4573 t = lookahead[j] = lex.token();
4574 }
4575 j += 1;
4576 }
4577 return t;
4578 }
4579
4580
4581
4582 // Produce the next token. It looks for programming errors.
4583
4584 function advance(id, t) {
4585 switch (token.id) {
4586 case '(number)':
4587 if (nexttoken.id === '.') {
4588 warning("A dot following a number can be confused with a decimal point.", token);
4589 }
4590 break;
4591 case '-':
4592 if (nexttoken.id === '-' || nexttoken.id === '--') {
4593 warning("Confusing minusses.");
4594 }
4595 break;
4596 case '+':
4597 if (nexttoken.id === '+' || nexttoken.id === '++') {
4598 warning("Confusing plusses.");
4599 }
4600 break;
4601 }
4602
4603 if (token.type === '(string)' || token.identifier) {
4604 anonname = token.value;
4605 }
4606
4607 if (id && nexttoken.id !== id) {
4608 if (t) {
4609 if (nexttoken.id === '(end)') {
4610 warning("Unmatched '{a}'.", t, t.id);
4611 } else {
4612 warning("Expected '{a}' to match '{b}' from line {c} and instead saw '{d}'.",
4613 nexttoken, id, t.id, t.line, nexttoken.value);
4614 }
4615 } else if (nexttoken.type !== '(identifier)' ||
4616 nexttoken.value !== id) {
4617 warning("Expected '{a}' and instead saw '{b}'.",
4618 nexttoken, id, nexttoken.value);
4619 }
4620 }
4621
4622 prevtoken = token;
4623 token = nexttoken;
4624 for (;;) {
4625 nexttoken = lookahead.shift() || lex.token();
4626 if (nexttoken.id === '(end)' || nexttoken.id === '(error)') {
4627 return;
4628 }
4629 if (nexttoken.type === 'special') {
4630 doOption();
4631 } else {
4632 if (nexttoken.id !== '(endline)') {
4633 break;
4634 }
4635 }
4636 }
4637 }
4638
4639
4640 // This is the heart of JSHINT, the Pratt parser. In addition to parsing, it
4641 // is looking for ad hoc lint patterns. We add .fud to Pratt's model, which is
4642 // like .nud except that it is only used on the first token of a statement.
4643 // Having .fud makes it much easier to define statement-oriented languages like
4644 // JavaScript. I retained Pratt's nomenclature.
4645
4646 // .nud Null denotation
4647 // .fud First null denotation
4648 // .led Left denotation
4649 // lbp Left binding power
4650 // rbp Right binding power
4651
4652 // They are elements of the parsing method called Top Down Operator Precedence.
4653
4654 function expression(rbp, initial) {
4655 var left, isArray = false, isObject = false;
4656
4657 if (nexttoken.id === '(end)')
4658 error("Unexpected early end of program.", token);
4659
4660 advance();
4661 if (initial) {
4662 anonname = 'anonymous';
4663 funct['(verb)'] = token.value;
4664 }
4665 if (initial === true && token.fud) {
4666 left = token.fud();
4667 } else {
4668 if (token.nud) {
4669 left = token.nud();
4670 } else {
4671 if (nexttoken.type === '(number)' && token.id === '.') {
4672 warning("A leading decimal point can be confused with a dot: '.{a}'.",
4673 token, nexttoken.value);
4674 advance();
4675 return token;
4676 } else {
4677 error("Expected an identifier and instead saw '{a}'.",
4678 token, token.id);
4679 }
4680 }
4681 while (rbp < nexttoken.lbp) {
4682 isArray = token.value === 'Array';
4683 isObject = token.value === 'Object';
4684 advance();
4685 if (isArray && token.id === '(' && nexttoken.id === ')')
4686 warning("Use the array literal notation [].", token);
4687 if (isObject && token.id === '(' && nexttoken.id === ')')
4688 warning("Use the object literal notation {}.", token);
4689 if (token.led) {
4690 left = token.led(left);
4691 } else {
4692 error("Expected an operator and instead saw '{a}'.",
4693 token, token.id);
4694 }
4695 }
4696 }
4697 return left;
4698 }
4699
4700
4701 // Functions for conformance of style.
4702
4703 function adjacent(left, right) {
4704 left = left || token;
4705 right = right || nexttoken;
4706 if (option.white) {
4707 if (left.character !== right.from && left.line === right.line) {
4708 left.from += (left.character - left.from);
4709 warning("Unexpected space after '{a}'.", left, left.value);
4710 }
4711 }
4712 }
4713
4714 function nobreak(left, right) {
4715 left = left || token;
4716 right = right || nexttoken;
4717 if (option.white && (left.character !== right.from || left.line !== right.line)) {
4718 warning("Unexpected space before '{a}'.", right, right.value);
4719 }
4720 }
4721
4722 function nospace(left, right) {
4723 left = left || token;
4724 right = right || nexttoken;
4725 if (option.white && !left.comment) {
4726 if (left.line === right.line) {
4727 adjacent(left, right);
4728 }
4729 }
4730 }
4731
4732 function nonadjacent(left, right) {
4733 if (option.white) {
4734 left = left || token;
4735 right = right || nexttoken;
4736 if (left.line === right.line && left.character === right.from) {
4737 left.from += (left.character - left.from);
4738 warning("Missing space after '{a}'.",
4739 left, left.value);
4740 }
4741 }
4742 }
4743
4744 function nobreaknonadjacent(left, right) {
4745 left = left || token;
4746 right = right || nexttoken;
4747 if (!option.laxbreak && left.line !== right.line) {
4748 warning("Bad line breaking before '{a}'.", right, right.id);
4749 } else if (option.white) {
4750 left = left || token;
4751 right = right || nexttoken;
4752 if (left.character === right.from) {
4753 left.from += (left.character - left.from);
4754 warning("Missing space after '{a}'.",
4755 left, left.value);
4756 }
4757 }
4758 }
4759
4760 function indentation(bias) {
4761 var i;
4762 if (option.white && nexttoken.id !== '(end)') {
4763 i = indent + (bias || 0);
4764 if (nexttoken.from !== i) {
4765 warning(
4766 "Expected '{a}' to have an indentation at {b} instead at {c}.",
4767 nexttoken, nexttoken.value, i, nexttoken.from);
4768 }
4769 }
4770 }
4771
4772 function nolinebreak(t) {
4773 t = t || token;
4774 if (t.line !== nexttoken.line) {
4775 warning("Line breaking error '{a}'.", t, t.value);
4776 }
4777 }
4778
4779
4780 function comma() {
4781 if (token.line !== nexttoken.line) {
4782 if (!option.laxcomma) {
4783 if (comma.first) {
4784 warning("Comma warnings can be turned off with 'laxcomma'");
4785 comma.first = false;
4786 }
4787 warning("Bad line breaking before '{a}'.", token, nexttoken.id);
4788 }
4789 } else if (!token.comment && token.character !== nexttoken.from && option.white) {
4790 token.from += (token.character - token.from);
4791 warning("Unexpected space after '{a}'.", token, token.value);
4792 }
4793 advance(',');
4794 nonadjacent(token, nexttoken);
4795 }
4796
4797
4798 // Functional constructors for making the symbols that will be inherited by
4799 // tokens.
4800
4801 function symbol(s, p) {
4802 var x = syntax[s];
4803 if (!x || typeof x !== 'object') {
4804 syntax[s] = x = {
4805 id: s,
4806 lbp: p,
4807 value: s
4808 };
4809 }
4810 return x;
4811 }
4812
4813
4814 function delim(s) {
4815 return symbol(s, 0);
4816 }
4817
4818
4819 function stmt(s, f) {
4820 var x = delim(s);
4821 x.identifier = x.reserved = true;
4822 x.fud = f;
4823 return x;
4824 }
4825
4826
4827 function blockstmt(s, f) {
4828 var x = stmt(s, f);
4829 x.block = true;
4830 return x;
4831 }
4832
4833
4834 function reserveName(x) {
4835 var c = x.id.charAt(0);
4836 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
4837 x.identifier = x.reserved = true;
4838 }
4839 return x;
4840 }
4841
4842
4843 function prefix(s, f) {
4844 var x = symbol(s, 150);
4845 reserveName(x);
4846 x.nud = (typeof f === 'function') ? f : function () {
4847 this.right = expression(150);
4848 this.arity = 'unary';
4849 if (this.id === '++' || this.id === '--') {
4850 if (option.plusplus) {
4851 warning("Unexpected use of '{a}'.", this, this.id);
4852 } else if ((!this.right.identifier || this.right.reserved) &&
4853 this.right.id !== '.' && this.right.id !== '[') {
4854 warning("Bad operand.", this);
4855 }
4856 }
4857 return this;
4858 };
4859 return x;
4860 }
4861
4862
4863 function type(s, f) {
4864 var x = delim(s);
4865 x.type = s;
4866 x.nud = f;
4867 return x;
4868 }
4869
4870
4871 function reserve(s, f) {
4872 var x = type(s, f);
4873 x.identifier = x.reserved = true;
4874 return x;
4875 }
4876
4877
4878 function reservevar(s, v) {
4879 return reserve(s, function () {
4880 if (typeof v === 'function') {
4881 v(this);
4882 }
4883 return this;
4884 });
4885 }
4886
4887
4888 function infix(s, f, p, w) {
4889 var x = symbol(s, p);
4890 reserveName(x);
4891 x.led = function (left) {
4892 if (!w) {
4893 nobreaknonadjacent(prevtoken, token);
4894 nonadjacent(token, nexttoken);
4895 }
4896 if (s === "in" && left.id === "!") {
4897 warning("Confusing use of '{a}'.", left, '!');
4898 }
4899 if (typeof f === 'function') {
4900 return f(left, this);
4901 } else {
4902 this.left = left;
4903 this.right = expression(p);
4904 return this;
4905 }
4906 };
4907 return x;
4908 }
4909
4910
4911 function relation(s, f) {
4912 var x = symbol(s, 100);
4913 x.led = function (left) {
4914 nobreaknonadjacent(prevtoken, token);
4915 nonadjacent(token, nexttoken);
4916 var right = expression(100);
4917 if ((left && left.id === 'NaN') || (right && right.id === 'NaN')) {
4918 warning("Use the isNaN function to compare with NaN.", this);
4919 } else if (f) {
4920 f.apply(this, [left, right]);
4921 }
4922 if (left.id === '!') {
4923 warning("Confusing use of '{a}'.", left, '!');
4924 }
4925 if (right.id === '!') {
4926 warning("Confusing use of '{a}'.", right, '!');
4927 }
4928 this.left = left;
4929 this.right = right;
4930 return this;
4931 };
4932 return x;
4933 }
4934
4935
4936 function isPoorRelation(node) {
4937 return node &&
4938 ((node.type === '(number)' && +node.value === 0) ||
4939 (node.type === '(string)' && node.value === '') ||
4940 (node.type === 'null' && !option.eqnull) ||
4941 node.type === 'true' ||
4942 node.type === 'false' ||
4943 node.type === 'undefined');
4944 }
4945
4946
4947 function assignop(s, f) {
4948 symbol(s, 20).exps = true;
4949 return infix(s, function (left, that) {
4950 var l;
4951 that.left = left;
4952 if (predefined[left.value] === false &&
4953 scope[left.value]['(global)'] === true) {
4954 warning("Read only.", left);
4955 } else if (left['function']) {
4956 warning("'{a}' is a function.", left, left.value);
4957 }
4958 if (left) {
4959 if (option.esnext && funct[left.value] === 'const') {
4960 warning("Attempting to override '{a}' which is a constant", left, left.value);
4961 }
4962 if (left.id === '.' || left.id === '[') {
4963 if (!left.left || left.left.value === 'arguments') {
4964 warning('Bad assignment.', that);
4965 }
4966 that.right = expression(19);
4967 return that;
4968 } else if (left.identifier && !left.reserved) {
4969 if (funct[left.value] === 'exception') {
4970 warning("Do not assign to the exception parameter.", left);
4971 }
4972 that.right = expression(19);
4973 return that;
4974 }
4975 if (left === syntax['function']) {
4976 warning(
4977 "Expected an identifier in an assignment and instead saw a function invocation.",
4978 token);
4979 }
4980 }
4981 error("Bad assignment.", that);
4982 }, 20);
4983 }
4984
4985
4986 function bitwise(s, f, p) {
4987 var x = symbol(s, p);
4988 reserveName(x);
4989 x.led = (typeof f === 'function') ? f : function (left) {
4990 if (option.bitwise) {
4991 warning("Unexpected use of '{a}'.", this, this.id);
4992 }
4993 this.left = left;
4994 this.right = expression(p);
4995 return this;
4996 };
4997 return x;
4998 }
4999
5000
5001 function bitwiseassignop(s) {
5002 symbol(s, 20).exps = true;
5003 return infix(s, function (left, that) {
5004 if (option.bitwise) {
5005 warning("Unexpected use of '{a}'.", that, that.id);
5006 }
5007 nonadjacent(prevtoken, token);
5008 nonadjacent(token, nexttoken);
5009 if (left) {
5010 if (left.id === '.' || left.id === '[' ||
5011 (left.identifier && !left.reserved)) {
5012 expression(19);
5013 return that;
5014 }
5015 if (left === syntax['function']) {
5016 warning(
5017 "Expected an identifier in an assignment, and instead saw a function invocation.",
5018 token);
5019 }
5020 return that;
5021 }
5022 error("Bad assignment.", that);
5023 }, 20);
5024 }
5025
5026
5027 function suffix(s, f) {
5028 var x = symbol(s, 150);
5029 x.led = function (left) {
5030 if (option.plusplus) {
5031 warning("Unexpected use of '{a}'.", this, this.id);
5032 } else if ((!left.identifier || left.reserved) &&
5033 left.id !== '.' && left.id !== '[') {
5034 warning("Bad operand.", this);
5035 }
5036 this.left = left;
5037 return this;
5038 };
5039 return x;
5040 }
5041
5042
5043 // fnparam means that this identifier is being defined as a function
5044 // argument (see identifier())
5045 function optionalidentifier(fnparam) {
5046 if (nexttoken.identifier) {
5047 advance();
5048 if (token.reserved && !option.es5) {
5049 // `undefined` as a function param is a common pattern to protect
5050 // against the case when somebody does `undefined = true` and
5051 // help with minification. More info: https://gist.github.com/315916
5052 if (!fnparam || token.value !== 'undefined') {
5053 warning("Expected an identifier and instead saw '{a}' (a reserved word).",
5054 token, token.id);
5055 }
5056 }
5057 return token.value;
5058 }
5059 }
5060
5061 // fnparam means that this identifier is being defined as a function
5062 // argument
5063 function identifier(fnparam) {
5064 var i = optionalidentifier(fnparam);
5065 if (i) {
5066 return i;
5067 }
5068 if (token.id === 'function' && nexttoken.id === '(') {
5069 warning("Missing name in function declaration.");
5070 } else {
5071 error("Expected an identifier and instead saw '{a}'.",
5072 nexttoken, nexttoken.value);
5073 }
5074 }
5075
5076
5077 function reachable(s) {
5078 var i = 0, t;
5079 if (nexttoken.id !== ';' || noreach) {
5080 return;
5081 }
5082 for (;;) {
5083 t = peek(i);
5084 if (t.reach) {
5085 return;
5086 }
5087 if (t.id !== '(endline)') {
5088 if (t.id === 'function') {
5089 if (!option.latedef) {
5090 break;
5091 }
5092 warning(
5093 "Inner functions should be listed at the top of the outer function.", t);
5094 break;
5095 }
5096 warning("Unreachable '{a}' after '{b}'.", t, t.value, s);
5097 break;
5098 }
5099 i += 1;
5100 }
5101 }
5102
5103
5104 function statement(noindent) {
5105 var i = indent, r, s = scope, t = nexttoken;
5106
5107 if (t.id === ";") {
5108 advance(";");
5109 return;
5110 }
5111
5112 // Is this a labelled statement?
5113
5114 if (t.identifier && !t.reserved && peek().id === ':') {
5115 advance();
5116 advance(':');
5117 scope = Object.create(s);
5118 addlabel(t.value, 'label');
5119 if (!nexttoken.labelled) {
5120 warning("Label '{a}' on {b} statement.",
5121 nexttoken, t.value, nexttoken.value);
5122 }
5123 if (jx.test(t.value + ':')) {
5124 warning("Label '{a}' looks like a javascript url.",
5125 t, t.value);
5126 }
5127 nexttoken.label = t.value;
5128 t = nexttoken;
5129 }
5130
5131 // Parse the statement.
5132
5133 if (!noindent) {
5134 indentation();
5135 }
5136 r = expression(0, true);
5137
5138 // Look for the final semicolon.
5139 if (!t.block) {
5140 if (!option.expr && (!r || !r.exps)) {
5141 warning("Expected an assignment or function call and instead saw an expression.",
5142 token);
5143 } else if (option.nonew && r.id === '(' && r.left.id === 'new') {
5144 warning("Do not use 'new' for side effects.");
5145 }
5146
5147 if (nexttoken.id === ',') {
5148 return comma();
5149 }
5150
5151 if (nexttoken.id !== ';') {
5152 if (!option.asi) {
5153 // If this is the last statement in a block that ends on
5154 // the same line *and* option lastsemic is on, ignore the warning.
5155 // Otherwise, complain about missing semicolon.
5156 if (!option.lastsemic || nexttoken.id !== '}' ||
5157 nexttoken.line !== token.line) {
5158 warningAt("Missing semicolon.", token.line, token.character);
5159 }
5160 }
5161 } else {
5162 adjacent(token, nexttoken);
5163 advance(';');
5164 nonadjacent(token, nexttoken);
5165 }
5166 }
5167
5168 // Restore the indentation.
5169
5170 indent = i;
5171 scope = s;
5172 return r;
5173 }
5174
5175
5176 function statements(startLine) {
5177 var a = [], f, p;
5178
5179 while (!nexttoken.reach && nexttoken.id !== '(end)') {
5180 if (nexttoken.id === ';') {
5181 p = peek();
5182 if (!p || p.id !== "(") {
5183 warning("Unnecessary semicolon.");
5184 }
5185 advance(';');
5186 } else {
5187 a.push(statement(startLine === nexttoken.line));
5188 }
5189 }
5190 return a;
5191 }
5192
5193
5194 /*
5195 * read all directives
5196 * recognizes a simple form of asi, but always
5197 * warns, if it is used
5198 */
5199 function directives() {
5200 var i, p, pn;
5201
5202 for (;;) {
5203 if (nexttoken.id === "(string)") {
5204 p = peek(0);
5205 if (p.id === "(endline)") {
5206 i = 1;
5207 do {
5208 pn = peek(i);
5209 i = i + 1;
5210 } while (pn.id === "(endline)");
5211
5212 if (pn.id !== ";") {
5213 if (pn.id !== "(string)" && pn.id !== "(number)" &&
5214 pn.id !== "(regexp)" && pn.identifier !== true &&
5215 pn.id !== "}") {
5216 break;
5217 }
5218 warning("Missing semicolon.", nexttoken);
5219 } else {
5220 p = pn;
5221 }
5222 } else if (p.id === "}") {
5223 // directive with no other statements, warn about missing semicolon
5224 warning("Missing semicolon.", p);
5225 } else if (p.id !== ";") {
5226 break;
5227 }
5228
5229 indentation();
5230 advance();
5231 if (directive[token.value]) {
5232 warning("Unnecessary directive \"{a}\".", token, token.value);
5233 }
5234
5235 if (token.value === "use strict") {
5236 option.newcap = true;
5237 option.undef = true;
5238 }
5239
5240 // there's no directive negation, so always set to true
5241 directive[token.value] = true;
5242
5243 if (p.id === ";") {
5244 advance(";");
5245 }
5246 continue;
5247 }
5248 break;
5249 }
5250 }
5251
5252
5253 /*
5254 * Parses a single block. A block is a sequence of statements wrapped in
5255 * braces.
5256 *
5257 * ordinary - true for everything but function bodies and try blocks.
5258 * stmt - true if block can be a single statement (e.g. in if/for/while).
5259 * isfunc - true if block is a function body
5260 */
5261 function block(ordinary, stmt, isfunc) {
5262 var a,
5263 b = inblock,
5264 old_indent = indent,
5265 m,
5266 s = scope,
5267 t,
5268 line,
5269 d;
5270
5271 inblock = ordinary;
5272 if (!ordinary || !option.funcscope) scope = Object.create(scope);
5273 nonadjacent(token, nexttoken);
5274 t = nexttoken;
5275
5276 if (nexttoken.id === '{') {
5277 advance('{');
5278 line = token.line;
5279 if (nexttoken.id !== '}') {
5280 indent += option.indent;
5281 while (!ordinary && nexttoken.from > indent) {
5282 indent += option.indent;
5283 }
5284
5285 if (isfunc) {
5286 m = {};
5287 for (d in directive) {
5288 if (is_own(directive, d)) {
5289 m[d] = directive[d];
5290 }
5291 }
5292 directives();
5293
5294 if (option.strict && funct['(context)']['(global)']) {
5295 if (!m["use strict"] && !directive["use strict"]) {
5296 warning("Missing \"use strict\" statement.");
5297 }
5298 }
5299 }
5300
5301 a = statements(line);
5302
5303 if (isfunc) {
5304 directive = m;
5305 }
5306
5307 indent -= option.indent;
5308 if (line !== nexttoken.line) {
5309 indentation();
5310 }
5311 } else if (line !== nexttoken.line) {
5312 indentation();
5313 }
5314 advance('}', t);
5315 indent = old_indent;
5316 } else if (!ordinary) {
5317 error("Expected '{a}' and instead saw '{b}'.",
5318 nexttoken, '{', nexttoken.value);
5319 } else {
5320 if (!stmt || option.curly)
5321 warning("Expected '{a}' and instead saw '{b}'.",
5322 nexttoken, '{', nexttoken.value);
5323
5324 noreach = true;
5325 indent += option.indent;
5326 // test indentation only if statement is in new line
5327 a = [statement(nexttoken.line === token.line)];
5328 indent -= option.indent;
5329 noreach = false;
5330 }
5331 funct['(verb)'] = null;
5332 if (!ordinary || !option.funcscope) scope = s;
5333 inblock = b;
5334 if (ordinary && option.noempty && (!a || a.length === 0)) {
5335 warning("Empty block.");
5336 }
5337 return a;
5338 }
5339
5340
5341 function countMember(m) {
5342 if (membersOnly && typeof membersOnly[m] !== 'boolean') {
5343 warning("Unexpected /*member '{a}'.", token, m);
5344 }
5345 if (typeof member[m] === 'number') {
5346 member[m] += 1;
5347 } else {
5348 member[m] = 1;
5349 }
5350 }
5351
5352
5353 function note_implied(token) {
5354 var name = token.value, line = token.line, a = implied[name];
5355 if (typeof a === 'function') {
5356 a = false;
5357 }
5358
5359 if (!a) {
5360 a = [line];
5361 implied[name] = a;
5362 } else if (a[a.length - 1] !== line) {
5363 a.push(line);
5364 }
5365 }
5366
5367
5368 // Build the syntax table by declaring the syntactic elements of the language.
5369
5370 type('(number)', function () {
5371 return this;
5372 });
5373
5374 type('(string)', function () {
5375 return this;
5376 });
5377
5378 syntax['(identifier)'] = {
5379 type: '(identifier)',
5380 lbp: 0,
5381 identifier: true,
5382 nud: function () {
5383 var v = this.value,
5384 s = scope[v],
5385 f;
5386
5387 if (typeof s === 'function') {
5388 // Protection against accidental inheritance.
5389 s = undefined;
5390 } else if (typeof s === 'boolean') {
5391 f = funct;
5392 funct = functions[0];
5393 addlabel(v, 'var');
5394 s = funct;
5395 funct = f;
5396 }
5397
5398 // The name is in scope and defined in the current function.
5399 if (funct === s) {
5400 // Change 'unused' to 'var', and reject labels.
5401 switch (funct[v]) {
5402 case 'unused':
5403 funct[v] = 'var';
5404 break;
5405 case 'unction':
5406 funct[v] = 'function';
5407 this['function'] = true;
5408 break;
5409 case 'function':
5410 this['function'] = true;
5411 break;
5412 case 'label':
5413 warning("'{a}' is a statement label.", token, v);
5414 break;
5415 }
5416 } else if (funct['(global)']) {
5417 // The name is not defined in the function. If we are in the global
5418 // scope, then we have an undefined variable.
5419 //
5420 // Operators typeof and delete do not raise runtime errors even if
5421 // the base object of a reference is null so no need to display warning
5422 // if we're inside of typeof or delete.
5423
5424 if (option.undef && typeof predefined[v] !== 'boolean') {
5425 // Attempting to subscript a null reference will throw an
5426 // error, even within the typeof and delete operators
5427 if (!(anonname === 'typeof' || anonname === 'delete') ||
5428 (nexttoken && (nexttoken.value === '.' || nexttoken.value === '['))) {
5429
5430 isundef(funct, "'{a}' is not defined.", token, v);
5431 }
5432 }
5433 note_implied(token);
5434 } else {
5435 // If the name is already defined in the current
5436 // function, but not as outer, then there is a scope error.
5437
5438 switch (funct[v]) {
5439 case 'closure':
5440 case 'function':
5441 case 'var':
5442 case 'unused':
5443 warning("'{a}' used out of scope.", token, v);
5444 break;
5445 case 'label':
5446 warning("'{a}' is a statement label.", token, v);
5447 break;
5448 case 'outer':
5449 case 'global':
5450 break;
5451 default:
5452 // If the name is defined in an outer function, make an outer entry,
5453 // and if it was unused, make it var.
5454 if (s === true) {
5455 funct[v] = true;
5456 } else if (s === null) {
5457 warning("'{a}' is not allowed.", token, v);
5458 note_implied(token);
5459 } else if (typeof s !== 'object') {
5460 // Operators typeof and delete do not raise runtime errors even
5461 // if the base object of a reference is null so no need to
5462 // display warning if we're inside of typeof or delete.
5463 if (option.undef) {
5464 // Attempting to subscript a null reference will throw an
5465 // error, even within the typeof and delete operators
5466 if (!(anonname === 'typeof' || anonname === 'delete') ||
5467 (nexttoken &&
5468 (nexttoken.value === '.' || nexttoken.value === '['))) {
5469
5470 isundef(funct, "'{a}' is not defined.", token, v);
5471 }
5472 }
5473 funct[v] = true;
5474 note_implied(token);
5475 } else {
5476 switch (s[v]) {
5477 case 'function':
5478 case 'unction':
5479 this['function'] = true;
5480 s[v] = 'closure';
5481 funct[v] = s['(global)'] ? 'global' : 'outer';
5482 break;
5483 case 'var':
5484 case 'unused':
5485 s[v] = 'closure';
5486 funct[v] = s['(global)'] ? 'global' : 'outer';
5487 break;
5488 case 'closure':
5489 case 'parameter':
5490 funct[v] = s['(global)'] ? 'global' : 'outer';
5491 break;
5492 case 'label':
5493 warning("'{a}' is a statement label.", token, v);
5494 }
5495 }
5496 }
5497 }
5498 return this;
5499 },
5500 led: function () {
5501 error("Expected an operator and instead saw '{a}'.",
5502 nexttoken, nexttoken.value);
5503 }
5504 };
5505
5506 type('(regexp)', function () {
5507 return this;
5508 });
5509
5510
5511 // ECMAScript parser
5512
5513 delim('(endline)');
5514 delim('(begin)');
5515 delim('(end)').reach = true;
5516 delim('</').reach = true;
5517 delim('<!');
5518 delim('<!--');
5519 delim('-->');
5520 delim('(error)').reach = true;
5521 delim('}').reach = true;
5522 delim(')');
5523 delim(']');
5524 delim('"').reach = true;
5525 delim("'").reach = true;
5526 delim(';');
5527 delim(':').reach = true;
5528 delim(',');
5529 delim('#');
5530 delim('@');
5531 reserve('else');
5532 reserve('case').reach = true;
5533 reserve('catch');
5534 reserve('default').reach = true;
5535 reserve('finally');
5536 reservevar('arguments', function (x) {
5537 if (directive['use strict'] && funct['(global)']) {
5538 warning("Strict violation.", x);
5539 }
5540 });
5541 reservevar('eval');
5542 reservevar('false');
5543 reservevar('Infinity');
5544 reservevar('NaN');
5545 reservevar('null');
5546 reservevar('this', function (x) {
5547 if (directive['use strict'] && !option.validthis && ((funct['(statement)'] &&
5548 funct['(name)'].charAt(0) > 'Z') || funct['(global)'])) {
5549 warning("Possible strict violation.", x);
5550 }
5551 });
5552 reservevar('true');
5553 reservevar('undefined');
5554 assignop('=', 'assign', 20);
5555 assignop('+=', 'assignadd', 20);
5556 assignop('-=', 'assignsub', 20);
5557 assignop('*=', 'assignmult', 20);
5558 assignop('/=', 'assigndiv', 20).nud = function () {
5559 error("A regular expression literal can be confused with '/='.");
5560 };
5561 assignop('%=', 'assignmod', 20);
5562 bitwiseassignop('&=', 'assignbitand', 20);
5563 bitwiseassignop('|=', 'assignbitor', 20);
5564 bitwiseassignop('^=', 'assignbitxor', 20);
5565 bitwiseassignop('<<=', 'assignshiftleft', 20);
5566 bitwiseassignop('>>=', 'assignshiftright', 20);
5567 bitwiseassignop('>>>=', 'assignshiftrightunsigned', 20);
5568 infix('?', function (left, that) {
5569 that.left = left;
5570 that.right = expression(10);
5571 advance(':');
5572 that['else'] = expression(10);
5573 return that;
5574 }, 30);
5575
5576 infix('||', 'or', 40);
5577 infix('&&', 'and', 50);
5578 bitwise('|', 'bitor', 70);
5579 bitwise('^', 'bitxor', 80);
5580 bitwise('&', 'bitand', 90);
5581 relation('==', function (left, right) {
5582 var eqnull = option.eqnull && (left.value === 'null' || right.value === 'null');
5583
5584 if (!eqnull && option.eqeqeq)
5585 warning("Expected '{a}' and instead saw '{b}'.", this, '===', '==');
5586 else if (isPoorRelation(left))
5587 warning("Use '{a}' to compare with '{b}'.", this, '===', left.value);
5588 else if (isPoorRelation(right))
5589 warning("Use '{a}' to compare with '{b}'.", this, '===', right.value);
5590
5591 return this;
5592 });
5593 relation('===');
5594 relation('!=', function (left, right) {
5595 var eqnull = option.eqnull &&
5596 (left.value === 'null' || right.value === 'null');
5597
5598 if (!eqnull && option.eqeqeq) {
5599 warning("Expected '{a}' and instead saw '{b}'.",
5600 this, '!==', '!=');
5601 } else if (isPoorRelation(left)) {
5602 warning("Use '{a}' to compare with '{b}'.",
5603 this, '!==', left.value);
5604 } else if (isPoorRelation(right)) {
5605 warning("Use '{a}' to compare with '{b}'.",
5606 this, '!==', right.value);
5607 }
5608 return this;
5609 });
5610 relation('!==');
5611 relation('<');
5612 relation('>');
5613 relation('<=');
5614 relation('>=');
5615 bitwise('<<', 'shiftleft', 120);
5616 bitwise('>>', 'shiftright', 120);
5617 bitwise('>>>', 'shiftrightunsigned', 120);
5618 infix('in', 'in', 120);
5619 infix('instanceof', 'instanceof', 120);
5620 infix('+', function (left, that) {
5621 var right = expression(130);
5622 if (left && right && left.id === '(string)' && right.id === '(string)') {
5623 left.value += right.value;
5624 left.character = right.character;
5625 if (!option.scripturl && jx.test(left.value)) {
5626 warning("JavaScript URL.", left);
5627 }
5628 return left;
5629 }
5630 that.left = left;
5631 that.right = right;
5632 return that;
5633 }, 130);
5634 prefix('+', 'num');
5635 prefix('+++', function () {
5636 warning("Confusing pluses.");
5637 this.right = expression(150);
5638 this.arity = 'unary';
5639 return this;
5640 });
5641 infix('+++', function (left) {
5642 warning("Confusing pluses.");
5643 this.left = left;
5644 this.right = expression(130);
5645 return this;
5646 }, 130);
5647 infix('-', 'sub', 130);
5648 prefix('-', 'neg');
5649 prefix('---', function () {
5650 warning("Confusing minuses.");
5651 this.right = expression(150);
5652 this.arity = 'unary';
5653 return this;
5654 });
5655 infix('---', function (left) {
5656 warning("Confusing minuses.");
5657 this.left = left;
5658 this.right = expression(130);
5659 return this;
5660 }, 130);
5661 infix('*', 'mult', 140);
5662 infix('/', 'div', 140);
5663 infix('%', 'mod', 140);
5664
5665 suffix('++', 'postinc');
5666 prefix('++', 'preinc');
5667 syntax['++'].exps = true;
5668
5669 suffix('--', 'postdec');
5670 prefix('--', 'predec');
5671 syntax['--'].exps = true;
5672 prefix('delete', function () {
5673 var p = expression(0);
5674 if (!p || (p.id !== '.' && p.id !== '[')) {
5675 warning("Variables should not be deleted.");
5676 }
5677 this.first = p;
5678 return this;
5679 }).exps = true;
5680
5681 prefix('~', function () {
5682 if (option.bitwise) {
5683 warning("Unexpected '{a}'.", this, '~');
5684 }
5685 expression(150);
5686 return this;
5687 });
5688
5689 prefix('!', function () {
5690 this.right = expression(150);
5691 this.arity = 'unary';
5692 if (bang[this.right.id] === true) {
5693 warning("Confusing use of '{a}'.", this, '!');
5694 }
5695 return this;
5696 });
5697 prefix('typeof', 'typeof');
5698 prefix('new', function () {
5699 var c = expression(155), i;
5700 if (c && c.id !== 'function') {
5701 if (c.identifier) {
5702 c['new'] = true;
5703 switch (c.value) {
5704 case 'Number':
5705 case 'String':
5706 case 'Boolean':
5707 case 'Math':
5708 case 'JSON':
5709 warning("Do not use {a} as a constructor.", token, c.value);
5710 break;
5711 case 'Function':
5712 if (!option.evil) {
5713 warning("The Function constructor is eval.");
5714 }
5715 break;
5716 case 'Date':
5717 case 'RegExp':
5718 break;
5719 default:
5720 if (c.id !== 'function') {
5721 i = c.value.substr(0, 1);
5722 if (option.newcap && (i < 'A' || i > 'Z')) {
5723 warning("A constructor name should start with an uppercase letter.",
5724 token);
5725 }
5726 }
5727 }
5728 } else {
5729 if (c.id !== '.' && c.id !== '[' && c.id !== '(') {
5730 warning("Bad constructor.", token);
5731 }
5732 }
5733 } else {
5734 if (!option.supernew)
5735 warning("Weird construction. Delete 'new'.", this);
5736 }
5737 adjacent(token, nexttoken);
5738 if (nexttoken.id !== '(' && !option.supernew) {
5739 warning("Missing '()' invoking a constructor.");
5740 }
5741 this.first = c;
5742 return this;
5743 });
5744 syntax['new'].exps = true;
5745
5746 prefix('void').exps = true;
5747
5748 infix('.', function (left, that) {
5749 adjacent(prevtoken, token);
5750 nobreak();
5751 var m = identifier();
5752 if (typeof m === 'string') {
5753 countMember(m);
5754 }
5755 that.left = left;
5756 that.right = m;
5757 if (left && left.value === 'arguments' && (m === 'callee' || m === 'caller')) {
5758 if (option.noarg)
5759 warning("Avoid arguments.{a}.", left, m);
5760 else if (directive['use strict'])
5761 error('Strict violation.');
5762 } else if (!option.evil && left && left.value === 'document' &&
5763 (m === 'write' || m === 'writeln')) {
5764 warning("document.write can be a form of eval.", left);
5765 }
5766 if (!option.evil && (m === 'eval' || m === 'execScript')) {
5767 warning('eval is evil.');
5768 }
5769 return that;
5770 }, 160, true);
5771
5772 infix('(', function (left, that) {
5773 if (prevtoken.id !== '}' && prevtoken.id !== ')') {
5774 nobreak(prevtoken, token);
5775 }
5776 nospace();
5777 if (option.immed && !left.immed && left.id === 'function') {
5778 warning("Wrap an immediate function invocation in parentheses " +
5779 "to assist the reader in understanding that the expression " +
5780 "is the result of a function, and not the function itself.");
5781 }
5782 var n = 0,
5783 p = [];
5784 if (left) {
5785 if (left.type === '(identifier)') {
5786 if (left.value.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)) {
5787 if (left.value !== 'Number' && left.value !== 'String' &&
5788 left.value !== 'Boolean' &&
5789 left.value !== 'Date') {
5790 if (left.value === 'Math') {
5791 warning("Math is not a function.", left);
5792 } else if (option.newcap) {
5793 warning(
5794 "Missing 'new' prefix when invoking a constructor.", left);
5795 }
5796 }
5797 }
5798 }
5799 }
5800 if (nexttoken.id !== ')') {
5801 for (;;) {
5802 p[p.length] = expression(10);
5803 n += 1;
5804 if (nexttoken.id !== ',') {
5805 break;
5806 }
5807 comma();
5808 }
5809 }
5810 advance(')');
5811 nospace(prevtoken, token);
5812 if (typeof left === 'object') {
5813 if (left.value === 'parseInt' && n === 1) {
5814 warning("Missing radix parameter.", left);
5815 }
5816 if (!option.evil) {
5817 if (left.value === 'eval' || left.value === 'Function' ||
5818 left.value === 'execScript') {
5819 warning("eval is evil.", left);
5820 } else if (p[0] && p[0].id === '(string)' &&
5821 (left.value === 'setTimeout' ||
5822 left.value === 'setInterval')) {
5823 warning(
5824 "Implied eval is evil. Pass a function instead of a string.", left);
5825 }
5826 }
5827 if (!left.identifier && left.id !== '.' && left.id !== '[' &&
5828 left.id !== '(' && left.id !== '&&' && left.id !== '||' &&
5829 left.id !== '?') {
5830 warning("Bad invocation.", left);
5831 }
5832 }
5833 that.left = left;
5834 return that;
5835 }, 155, true).exps = true;
5836
5837 prefix('(', function () {
5838 nospace();
5839 if (nexttoken.id === 'function') {
5840 nexttoken.immed = true;
5841 }
5842 var v = expression(0);
5843 advance(')', this);
5844 nospace(prevtoken, token);
5845 if (option.immed && v.id === 'function') {
5846 if (nexttoken.id === '(' ||
5847 (nexttoken.id === '.' && (peek().value === 'call' || peek().value === 'apply'))) {
5848 warning(
5849 "Move the invocation into the parens that contain the function.", nexttoken);
5850 } else {
5851 warning(
5852 "Do not wrap function literals in parens unless they are to be immediately invoked.",
5853 this);
5854 }
5855 }
5856 return v;
5857 });
5858
5859 infix('[', function (left, that) {
5860 nobreak(prevtoken, token);
5861 nospace();
5862 var e = expression(0), s;
5863 if (e && e.type === '(string)') {
5864 if (!option.evil && (e.value === 'eval' || e.value === 'execScript')) {
5865 warning("eval is evil.", that);
5866 }
5867 countMember(e.value);
5868 if (!option.sub && ix.test(e.value)) {
5869 s = syntax[e.value];
5870 if (!s || !s.reserved) {
5871 warning("['{a}'] is better written in dot notation.",
5872 e, e.value);
5873 }
5874 }
5875 }
5876 advance(']', that);
5877 nospace(prevtoken, token);
5878 that.left = left;
5879 that.right = e;
5880 return that;
5881 }, 160, true);
5882
5883 prefix('[', function () {
5884 var b = token.line !== nexttoken.line;
5885 this.first = [];
5886 if (b) {
5887 indent += option.indent;
5888 if (nexttoken.from === indent + option.indent) {
5889 indent += option.indent;
5890 }
5891 }
5892 while (nexttoken.id !== '(end)') {
5893 while (nexttoken.id === ',') {
5894 warning("Extra comma.");
5895 advance(',');
5896 }
5897 if (nexttoken.id === ']') {
5898 break;
5899 }
5900 if (b && token.line !== nexttoken.line) {
5901 indentation();
5902 }
5903 this.first.push(expression(10));
5904 if (nexttoken.id === ',') {
5905 comma();
5906 if (nexttoken.id === ']' && !option.es5) {
5907 warning("Extra comma.", token);
5908 break;
5909 }
5910 } else {
5911 break;
5912 }
5913 }
5914 if (b) {
5915 indent -= option.indent;
5916 indentation();
5917 }
5918 advance(']', this);
5919 return this;
5920 }, 160);
5921
5922
5923 function property_name() {
5924 var id = optionalidentifier(true);
5925 if (!id) {
5926 if (nexttoken.id === '(string)') {
5927 id = nexttoken.value;
5928 advance();
5929 } else if (nexttoken.id === '(number)') {
5930 id = nexttoken.value.toString();
5931 advance();
5932 }
5933 }
5934 return id;
5935 }
5936
5937
5938 function functionparams() {
5939 var i, t = nexttoken, p = [];
5940 advance('(');
5941 nospace();
5942 if (nexttoken.id === ')') {
5943 advance(')');
5944 return;
5945 }
5946 for (;;) {
5947 i = identifier(true);
5948 p.push(i);
5949 addlabel(i, 'parameter');
5950 if (nexttoken.id === ',') {
5951 comma();
5952 } else {
5953 advance(')', t);
5954 nospace(prevtoken, token);
5955 return p;
5956 }
5957 }
5958 }
5959
5960
5961 function doFunction(i, statement) {
5962 var f,
5963 oldOption = option,
5964 oldScope = scope;
5965
5966 option = Object.create(option);
5967 scope = Object.create(scope);
5968
5969 funct = {
5970 '(name)' : i || '"' + anonname + '"',
5971 '(line)' : nexttoken.line,
5972 '(context)' : funct,
5973 '(breakage)' : 0,
5974 '(loopage)' : 0,
5975 '(scope)' : scope,
5976 '(statement)': statement
5977 };
5978 f = funct;
5979 token.funct = funct;
5980 functions.push(funct);
5981 if (i) {
5982 addlabel(i, 'function');
5983 }
5984 funct['(params)'] = functionparams();
5985
5986 block(false, false, true);
5987 scope = oldScope;
5988 option = oldOption;
5989 funct['(last)'] = token.line;
5990 funct = funct['(context)'];
5991 return f;
5992 }
5993
5994
5995 (function (x) {
5996 x.nud = function () {
5997 var b, f, i, j, p, t;
5998 var props = {}; // All properties, including accessors
5999
6000 function saveProperty(name, token) {
6001 if (props[name] && is_own(props, name))
6002 warning("Duplicate member '{a}'.", nexttoken, i);
6003 else
6004 props[name] = {};
6005
6006 props[name].basic = true;
6007 props[name].basicToken = token;
6008 }
6009
6010 function saveSetter(name, token) {
6011 if (props[name] && is_own(props, name)) {
6012 if (props[name].basic || props[name].setter)
6013 warning("Duplicate member '{a}'.", nexttoken, i);
6014 } else {
6015 props[name] = {};
6016 }
6017
6018 props[name].setter = true;
6019 props[name].setterToken = token;
6020 }
6021
6022 function saveGetter(name) {
6023 if (props[name] && is_own(props, name)) {
6024 if (props[name].basic || props[name].getter)
6025 warning("Duplicate member '{a}'.", nexttoken, i);
6026 } else {
6027 props[name] = {};
6028 }
6029
6030 props[name].getter = true;
6031 props[name].getterToken = token;
6032 }
6033
6034 b = token.line !== nexttoken.line;
6035 if (b) {
6036 indent += option.indent;
6037 if (nexttoken.from === indent + option.indent) {
6038 indent += option.indent;
6039 }
6040 }
6041 for (;;) {
6042 if (nexttoken.id === '}') {
6043 break;
6044 }
6045 if (b) {
6046 indentation();
6047 }
6048 if (nexttoken.value === 'get' && peek().id !== ':') {
6049 advance('get');
6050 if (!option.es5) {
6051 error("get/set are ES5 features.");
6052 }
6053 i = property_name();
6054 if (!i) {
6055 error("Missing property name.");
6056 }
6057 saveGetter(i);
6058 t = nexttoken;
6059 adjacent(token, nexttoken);
6060 f = doFunction();
6061 p = f['(params)'];
6062 if (p) {
6063 warning("Unexpected parameter '{a}' in get {b} function.", t, p[0], i);
6064 }
6065 adjacent(token, nexttoken);
6066 } else if (nexttoken.value === 'set' && peek().id !== ':') {
6067 advance('set');
6068 if (!option.es5) {
6069 error("get/set are ES5 features.");
6070 }
6071 i = property_name();
6072 if (!i) {
6073 error("Missing property name.");
6074 }
6075 saveSetter(i, nexttoken);
6076 t = nexttoken;
6077 adjacent(token, nexttoken);
6078 f = doFunction();
6079 p = f['(params)'];
6080 if (!p || p.length !== 1) {
6081 warning("Expected a single parameter in set {a} function.", t, i);
6082 }
6083 } else {
6084 i = property_name();
6085 saveProperty(i, nexttoken);
6086 if (typeof i !== 'string') {
6087 break;
6088 }
6089 advance(':');
6090 nonadjacent(token, nexttoken);
6091 expression(10);
6092 }
6093
6094 countMember(i);
6095 if (nexttoken.id === ',') {
6096 comma();
6097 if (nexttoken.id === ',') {
6098 warning("Extra comma.", token);
6099 } else if (nexttoken.id === '}' && !option.es5) {
6100 warning("Extra comma.", token);
6101 }
6102 } else {
6103 break;
6104 }
6105 }
6106 if (b) {
6107 indent -= option.indent;
6108 indentation();
6109 }
6110 advance('}', this);
6111
6112 // Check for lonely setters if in the ES5 mode.
6113 if (option.es5) {
6114 for (var name in props) {
6115 if (is_own(props, name) && props[name].setter && !props[name].getter) {
6116 warning("Setter is defined without getter.", props[name].setterToken);
6117 }
6118 }
6119 }
6120 return this;
6121 };
6122 x.fud = function () {
6123 error("Expected to see a statement and instead saw a block.", token);
6124 };
6125 }(delim('{')));
6126
6127 // This Function is called when esnext option is set to true
6128 // it adds the `const` statement to JSHINT
6129
6130 useESNextSyntax = function () {
6131 var conststatement = stmt('const', function (prefix) {
6132 var id, name, value;
6133
6134 this.first = [];
6135 for (;;) {
6136 nonadjacent(token, nexttoken);
6137 id = identifier();
6138 if (funct[id] === "const") {
6139 warning("const '" + id + "' has already been declared");
6140 }
6141 if (funct['(global)'] && predefined[id] === false) {
6142 warning("Redefinition of '{a}'.", token, id);
6143 }
6144 addlabel(id, 'const');
6145 if (prefix) {
6146 break;
6147 }
6148 name = token;
6149 this.first.push(token);
6150
6151 if (nexttoken.id !== "=") {
6152 warning("const " +
6153 "'{a}' is initialized to 'undefined'.", token, id);
6154 }
6155
6156 if (nexttoken.id === '=') {
6157 nonadjacent(token, nexttoken);
6158 advance('=');
6159 nonadjacent(token, nexttoken);
6160 if (nexttoken.id === 'undefined') {
6161 warning("It is not necessary to initialize " +
6162 "'{a}' to 'undefined'.", token, id);
6163 }
6164 if (peek(0).id === '=' && nexttoken.identifier) {
6165 error("Constant {a} was not declared correctly.",
6166 nexttoken, nexttoken.value);
6167 }
6168 value = expression(0);
6169 name.first = value;
6170 }
6171
6172 if (nexttoken.id !== ',') {
6173 break;
6174 }
6175 comma();
6176 }
6177 return this;
6178 });
6179 conststatement.exps = true;
6180 };
6181
6182 var varstatement = stmt('var', function (prefix) {
6183 // JavaScript does not have block scope. It only has function scope. So,
6184 // declaring a variable in a block can have unexpected consequences.
6185 var id, name, value;
6186
6187 if (funct['(onevar)'] && option.onevar) {
6188 warning("Too many var statements.");
6189 } else if (!funct['(global)']) {
6190 funct['(onevar)'] = true;
6191 }
6192 this.first = [];
6193 for (;;) {
6194 nonadjacent(token, nexttoken);
6195 id = identifier();
6196 if (option.esnext && funct[id] === "const") {
6197 warning("const '" + id + "' has already been declared");
6198 }
6199 if (funct['(global)'] && predefined[id] === false) {
6200 warning("Redefinition of '{a}'.", token, id);
6201 }
6202 addlabel(id, 'unused');
6203 if (prefix) {
6204 break;
6205 }
6206 name = token;
6207 this.first.push(token);
6208 if (nexttoken.id === '=') {
6209 nonadjacent(token, nexttoken);
6210 advance('=');
6211 nonadjacent(token, nexttoken);
6212 if (nexttoken.id === 'undefined') {
6213 warning("It is not necessary to initialize '{a}' to 'undefined'.", token, id);
6214 }
6215 if (peek(0).id === '=' && nexttoken.identifier) {
6216 error("Variable {a} was not declared correctly.",
6217 nexttoken, nexttoken.value);
6218 }
6219 value = expression(0);
6220 name.first = value;
6221 }
6222 if (nexttoken.id !== ',') {
6223 break;
6224 }
6225 comma();
6226 }
6227 return this;
6228 });
6229 varstatement.exps = true;
6230
6231 blockstmt('function', function () {
6232 if (inblock) {
6233 warning("Function declarations should not be placed in blocks. " +
6234 "Use a function expression or move the statement to the top of " +
6235 "the outer function.", token);
6236
6237 }
6238 var i = identifier();
6239 if (option.esnext && funct[i] === "const") {
6240 warning("const '" + i + "' has already been declared");
6241 }
6242 adjacent(token, nexttoken);
6243 addlabel(i, 'unction');
6244 doFunction(i, true);
6245 if (nexttoken.id === '(' && nexttoken.line === token.line) {
6246 error(
6247 "Function declarations are not invocable. Wrap the whole function invocation in parens.");
6248 }
6249 return this;
6250 });
6251
6252 prefix('function', function () {
6253 var i = optionalidentifier();
6254 if (i) {
6255 adjacent(token, nexttoken);
6256 } else {
6257 nonadjacent(token, nexttoken);
6258 }
6259 doFunction(i);
6260 if (!option.loopfunc && funct['(loopage)']) {
6261 warning("Don't make functions within a loop.");
6262 }
6263 return this;
6264 });
6265
6266 blockstmt('if', function () {
6267 var t = nexttoken;
6268 advance('(');
6269 nonadjacent(this, t);
6270 nospace();
6271 expression(20);
6272 if (nexttoken.id === '=') {
6273 if (!option.boss)
6274 warning("Expected a conditional expression and instead saw an assignment.");
6275 advance('=');
6276 expression(20);
6277 }
6278 advance(')', t);
6279 nospace(prevtoken, token);
6280 block(true, true);
6281 if (nexttoken.id === 'else') {
6282 nonadjacent(token, nexttoken);
6283 advance('else');
6284 if (nexttoken.id === 'if' || nexttoken.id === 'switch') {
6285 statement(true);
6286 } else {
6287 block(true, true);
6288 }
6289 }
6290 return this;
6291 });
6292
6293 blockstmt('try', function () {
6294 var b, e, s;
6295
6296 block(false);
6297 if (nexttoken.id === 'catch') {
6298 advance('catch');
6299 nonadjacent(token, nexttoken);
6300 advance('(');
6301 s = scope;
6302 scope = Object.create(s);
6303 e = nexttoken.value;
6304 if (nexttoken.type !== '(identifier)') {
6305 warning("Expected an identifier and instead saw '{a}'.",
6306 nexttoken, e);
6307 } else {
6308 addlabel(e, 'exception');
6309 }
6310 advance();
6311 advance(')');
6312 block(false);
6313 b = true;
6314 scope = s;
6315 }
6316 if (nexttoken.id === 'finally') {
6317 advance('finally');
6318 block(false);
6319 return;
6320 } else if (!b) {
6321 error("Expected '{a}' and instead saw '{b}'.",
6322 nexttoken, 'catch', nexttoken.value);
6323 }
6324 return this;
6325 });
6326
6327 blockstmt('while', function () {
6328 var t = nexttoken;
6329 funct['(breakage)'] += 1;
6330 funct['(loopage)'] += 1;
6331 advance('(');
6332 nonadjacent(this, t);
6333 nospace();
6334 expression(20);
6335 if (nexttoken.id === '=') {
6336 if (!option.boss)
6337 warning("Expected a conditional expression and instead saw an assignment.");
6338 advance('=');
6339 expression(20);
6340 }
6341 advance(')', t);
6342 nospace(prevtoken, token);
6343 block(true, true);
6344 funct['(breakage)'] -= 1;
6345 funct['(loopage)'] -= 1;
6346 return this;
6347 }).labelled = true;
6348
6349 blockstmt('with', function () {
6350 var t = nexttoken;
6351 if (directive['use strict']) {
6352 error("'with' is not allowed in strict mode.", token);
6353 } else if (!option.withstmt) {
6354 warning("Don't use 'with'.", token);
6355 }
6356
6357 advance('(');
6358 nonadjacent(this, t);
6359 nospace();
6360 expression(0);
6361 advance(')', t);
6362 nospace(prevtoken, token);
6363 block(true, true);
6364
6365 return this;
6366 });
6367
6368 blockstmt('switch', function () {
6369 var t = nexttoken,
6370 g = false;
6371 funct['(breakage)'] += 1;
6372 advance('(');
6373 nonadjacent(this, t);
6374 nospace();
6375 this.condition = expression(20);
6376 advance(')', t);
6377 nospace(prevtoken, token);
6378 nonadjacent(token, nexttoken);
6379 t = nexttoken;
6380 advance('{');
6381 nonadjacent(token, nexttoken);
6382 indent += option.indent;
6383 this.cases = [];
6384 for (;;) {
6385 switch (nexttoken.id) {
6386 case 'case':
6387 switch (funct['(verb)']) {
6388 case 'break':
6389 case 'case':
6390 case 'continue':
6391 case 'return':
6392 case 'switch':
6393 case 'throw':
6394 break;
6395 default:
6396 // You can tell JSHint that you don't use break intentionally by
6397 // adding a comment /* falls through */ on a line just before
6398 // the next `case`.
6399 if (!ft.test(lines[nexttoken.line - 2])) {
6400 warning(
6401 "Expected a 'break' statement before 'case'.",
6402 token);
6403 }
6404 }
6405 indentation(-option.indent);
6406 advance('case');
6407 this.cases.push(expression(20));
6408 g = true;
6409 advance(':');
6410 funct['(verb)'] = 'case';
6411 break;
6412 case 'default':
6413 switch (funct['(verb)']) {
6414 case 'break':
6415 case 'continue':
6416 case 'return':
6417 case 'throw':
6418 break;
6419 default:
6420 if (!ft.test(lines[nexttoken.line - 2])) {
6421 warning(
6422 "Expected a 'break' statement before 'default'.",
6423 token);
6424 }
6425 }
6426 indentation(-option.indent);
6427 advance('default');
6428 g = true;
6429 advance(':');
6430 break;
6431 case '}':
6432 indent -= option.indent;
6433 indentation();
6434 advance('}', t);
6435 if (this.cases.length === 1 || this.condition.id === 'true' ||
6436 this.condition.id === 'false') {
6437 if (!option.onecase)
6438 warning("This 'switch' should be an 'if'.", this);
6439 }
6440 funct['(breakage)'] -= 1;
6441 funct['(verb)'] = undefined;
6442 return;
6443 case '(end)':
6444 error("Missing '{a}'.", nexttoken, '}');
6445 return;
6446 default:
6447 if (g) {
6448 switch (token.id) {
6449 case ',':
6450 error("Each value should have its own case label.");
6451 return;
6452 case ':':
6453 g = false;
6454 statements();
6455 break;
6456 default:
6457 error("Missing ':' on a case clause.", token);
6458 return;
6459 }
6460 } else {
6461 if (token.id === ':') {
6462 advance(':');
6463 error("Unexpected '{a}'.", token, ':');
6464 statements();
6465 } else {
6466 error("Expected '{a}' and instead saw '{b}'.",
6467 nexttoken, 'case', nexttoken.value);
6468 return;
6469 }
6470 }
6471 }
6472 }
6473 }).labelled = true;
6474
6475 stmt('debugger', function () {
6476 if (!option.debug) {
6477 warning("All 'debugger' statements should be removed.");
6478 }
6479 return this;
6480 }).exps = true;
6481
6482 (function () {
6483 var x = stmt('do', function () {
6484 funct['(breakage)'] += 1;
6485 funct['(loopage)'] += 1;
6486 this.first = block(true);
6487 advance('while');
6488 var t = nexttoken;
6489 nonadjacent(token, t);
6490 advance('(');
6491 nospace();
6492 expression(20);
6493 if (nexttoken.id === '=') {
6494 if (!option.boss)
6495 warning("Expected a conditional expression and instead saw an assignment.");
6496 advance('=');
6497 expression(20);
6498 }
6499 advance(')', t);
6500 nospace(prevtoken, token);
6501 funct['(breakage)'] -= 1;
6502 funct['(loopage)'] -= 1;
6503 return this;
6504 });
6505 x.labelled = true;
6506 x.exps = true;
6507 }());
6508
6509 blockstmt('for', function () {
6510 var s, t = nexttoken;
6511 funct['(breakage)'] += 1;
6512 funct['(loopage)'] += 1;
6513 advance('(');
6514 nonadjacent(this, t);
6515 nospace();
6516 if (peek(nexttoken.id === 'var' ? 1 : 0).id === 'in') {
6517 if (nexttoken.id === 'var') {
6518 advance('var');
6519 varstatement.fud.call(varstatement, true);
6520 } else {
6521 switch (funct[nexttoken.value]) {
6522 case 'unused':
6523 funct[nexttoken.value] = 'var';
6524 break;
6525 case 'var':
6526 break;
6527 default:
6528 warning("Bad for in variable '{a}'.",
6529 nexttoken, nexttoken.value);
6530 }
6531 advance();
6532 }
6533 advance('in');
6534 expression(20);
6535 advance(')', t);
6536 s = block(true, true);
6537 if (option.forin && s && (s.length > 1 || typeof s[0] !== 'object' ||
6538 s[0].value !== 'if')) {
6539 warning("The body of a for in should be wrapped in an if statement to filter " +
6540 "unwanted properties from the prototype.", this);
6541 }
6542 funct['(breakage)'] -= 1;
6543 funct['(loopage)'] -= 1;
6544 return this;
6545 } else {
6546 if (nexttoken.id !== ';') {
6547 if (nexttoken.id === 'var') {
6548 advance('var');
6549 varstatement.fud.call(varstatement);
6550 } else {
6551 for (;;) {
6552 expression(0, 'for');
6553 if (nexttoken.id !== ',') {
6554 break;
6555 }
6556 comma();
6557 }
6558 }
6559 }
6560 nolinebreak(token);
6561 advance(';');
6562 if (nexttoken.id !== ';') {
6563 expression(20);
6564 if (nexttoken.id === '=') {
6565 if (!option.boss)
6566 warning("Expected a conditional expression and instead saw an assignment.");
6567 advance('=');
6568 expression(20);
6569 }
6570 }
6571 nolinebreak(token);
6572 advance(';');
6573 if (nexttoken.id === ';') {
6574 error("Expected '{a}' and instead saw '{b}'.",
6575 nexttoken, ')', ';');
6576 }
6577 if (nexttoken.id !== ')') {
6578 for (;;) {
6579 expression(0, 'for');
6580 if (nexttoken.id !== ',') {
6581 break;
6582 }
6583 comma();
6584 }
6585 }
6586 advance(')', t);
6587 nospace(prevtoken, token);
6588 block(true, true);
6589 funct['(breakage)'] -= 1;
6590 funct['(loopage)'] -= 1;
6591 return this;
6592 }
6593 }).labelled = true;
6594
6595
6596 stmt('break', function () {
6597 var v = nexttoken.value;
6598
6599 if (funct['(breakage)'] === 0)
6600 warning("Unexpected '{a}'.", nexttoken, this.value);
6601
6602 if (!option.asi)
6603 nolinebreak(this);
6604
6605 if (nexttoken.id !== ';') {
6606 if (token.line === nexttoken.line) {
6607 if (funct[v] !== 'label') {
6608 warning("'{a}' is not a statement label.", nexttoken, v);
6609 } else if (scope[v] !== funct) {
6610 warning("'{a}' is out of scope.", nexttoken, v);
6611 }
6612 this.first = nexttoken;
6613 advance();
6614 }
6615 }
6616 reachable('break');
6617 return this;
6618 }).exps = true;
6619
6620
6621 stmt('continue', function () {
6622 var v = nexttoken.value;
6623
6624 if (funct['(breakage)'] === 0)
6625 warning("Unexpected '{a}'.", nexttoken, this.value);
6626
6627 if (!option.asi)
6628 nolinebreak(this);
6629
6630 if (nexttoken.id !== ';') {
6631 if (token.line === nexttoken.line) {
6632 if (funct[v] !== 'label') {
6633 warning("'{a}' is not a statement label.", nexttoken, v);
6634 } else if (scope[v] !== funct) {
6635 warning("'{a}' is out of scope.", nexttoken, v);
6636 }
6637 this.first = nexttoken;
6638 advance();
6639 }
6640 } else if (!funct['(loopage)']) {
6641 warning("Unexpected '{a}'.", nexttoken, this.value);
6642 }
6643 reachable('continue');
6644 return this;
6645 }).exps = true;
6646
6647
6648 stmt('return', function () {
6649 if (this.line === nexttoken.line) {
6650 if (nexttoken.id === '(regexp)')
6651 warning("Wrap the /regexp/ literal in parens to disambiguate the slash operator.");
6652
6653 if (nexttoken.id !== ';' && !nexttoken.reach) {
6654 nonadjacent(token, nexttoken);
6655 if (peek().value === "=" && !option.boss) {
6656 warningAt("Did you mean to return a conditional instead of an assignment?",
6657 token.line, token.character + 1);
6658 }
6659 this.first = expression(0);
6660 }
6661 } else if (!option.asi) {
6662 nolinebreak(this); // always warn (Line breaking error)
6663 }
6664 reachable('return');
6665 return this;
6666 }).exps = true;
6667
6668
6669 stmt('throw', function () {
6670 nolinebreak(this);
6671 nonadjacent(token, nexttoken);
6672 this.first = expression(20);
6673 reachable('throw');
6674 return this;
6675 }).exps = true;
6676
6677 // Superfluous reserved words
6678
6679 reserve('class');
6680 reserve('const');
6681 reserve('enum');
6682 reserve('export');
6683 reserve('extends');
6684 reserve('import');
6685 reserve('super');
6686
6687 reserve('let');
6688 reserve('yield');
6689 reserve('implements');
6690 reserve('interface');
6691 reserve('package');
6692 reserve('private');
6693 reserve('protected');
6694 reserve('public');
6695 reserve('static');
6696
6697
6698 // Parse JSON
6699
6700 function jsonValue() {
6701
6702 function jsonObject() {
6703 var o = {}, t = nexttoken;
6704 advance('{');
6705 if (nexttoken.id !== '}') {
6706 for (;;) {
6707 if (nexttoken.id === '(end)') {
6708 error("Missing '}' to match '{' from line {a}.",
6709 nexttoken, t.line);
6710 } else if (nexttoken.id === '}') {
6711 warning("Unexpected comma.", token);
6712 break;
6713 } else if (nexttoken.id === ',') {
6714 error("Unexpected comma.", nexttoken);
6715 } else if (nexttoken.id !== '(string)') {
6716 warning("Expected a string and instead saw {a}.",
6717 nexttoken, nexttoken.value);
6718 }
6719 if (o[nexttoken.value] === true) {
6720 warning("Duplicate key '{a}'.",
6721 nexttoken, nexttoken.value);
6722 } else if ((nexttoken.value === '__proto__' &&
6723 !option.proto) || (nexttoken.value === '__iterator__' &&
6724 !option.iterator)) {
6725 warning("The '{a}' key may produce unexpected results.",
6726 nexttoken, nexttoken.value);
6727 } else {
6728 o[nexttoken.value] = true;
6729 }
6730 advance();
6731 advance(':');
6732 jsonValue();
6733 if (nexttoken.id !== ',') {
6734 break;
6735 }
6736 advance(',');
6737 }
6738 }
6739 advance('}');
6740 }
6741
6742 function jsonArray() {
6743 var t = nexttoken;
6744 advance('[');
6745 if (nexttoken.id !== ']') {
6746 for (;;) {
6747 if (nexttoken.id === '(end)') {
6748 error("Missing ']' to match '[' from line {a}.",
6749 nexttoken, t.line);
6750 } else if (nexttoken.id === ']') {
6751 warning("Unexpected comma.", token);
6752 break;
6753 } else if (nexttoken.id === ',') {
6754 error("Unexpected comma.", nexttoken);
6755 }
6756 jsonValue();
6757 if (nexttoken.id !== ',') {
6758 break;
6759 }
6760 advance(',');
6761 }
6762 }
6763 advance(']');
6764 }
6765
6766 switch (nexttoken.id) {
6767 case '{':
6768 jsonObject();
6769 break;
6770 case '[':
6771 jsonArray();
6772 break;
6773 case 'true':
6774 case 'false':
6775 case 'null':
6776 case '(number)':
6777 case '(string)':
6778 advance();
6779 break;
6780 case '-':
6781 advance('-');
6782 if (token.character !== nexttoken.from) {
6783 warning("Unexpected space after '-'.", token);
6784 }
6785 adjacent(token, nexttoken);
6786 advance('(number)');
6787 break;
6788 default:
6789 error("Expected a JSON value.", nexttoken);
6790 }
6791 }
6792
6793
6794 // The actual JSHINT function itself.
6795
6796 var itself = function (s, o, g) {
6797 var a, i, k;
6798 JSHINT.errors = [];
6799 JSHINT.undefs = [];
6800 predefined = Object.create(standard);
6801 combine(predefined, g || {});
6802 if (o) {
6803 a = o.predef;
6804 if (a) {
6805 if (Array.isArray(a)) {
6806 for (i = 0; i < a.length; i += 1) {
6807 predefined[a[i]] = true;
6808 }
6809 } else if (typeof a === 'object') {
6810 k = Object.keys(a);
6811 for (i = 0; i < k.length; i += 1) {
6812 predefined[k[i]] = !!a[k[i]];
6813 }
6814 }
6815 }
6816 option = o;
6817 } else {
6818 option = {};
6819 }
6820 option.indent = option.indent || 4;
6821 option.maxerr = option.maxerr || 50;
6822
6823 tab = '';
6824 for (i = 0; i < option.indent; i += 1) {
6825 tab += ' ';
6826 }
6827 indent = 1;
6828 global = Object.create(predefined);
6829 scope = global;
6830 funct = {
6831 '(global)': true,
6832 '(name)': '(global)',
6833 '(scope)': scope,
6834 '(breakage)': 0,
6835 '(loopage)': 0
6836 };
6837 functions = [funct];
6838 urls = [];
6839 stack = null;
6840 member = {};
6841 membersOnly = null;
6842 implied = {};
6843 inblock = false;
6844 lookahead = [];
6845 jsonmode = false;
6846 warnings = 0;
6847 lex.init(s);
6848 prereg = true;
6849 directive = {};
6850
6851 prevtoken = token = nexttoken = syntax['(begin)'];
6852
6853 // Check options
6854 for (var name in o) {
6855 if (is_own(o, name)) {
6856 checkOption(name, token);
6857 }
6858 }
6859
6860 assume();
6861
6862 // combine the passed globals after we've assumed all our options
6863 combine(predefined, g || {});
6864
6865 //reset values
6866 comma.first = true;
6867
6868 try {
6869 advance();
6870 switch (nexttoken.id) {
6871 case '{':
6872 case '[':
6873 option.laxbreak = true;
6874 jsonmode = true;
6875 jsonValue();
6876 break;
6877 default:
6878 directives();
6879 if (directive["use strict"] && !option.globalstrict) {
6880 warning("Use the function form of \"use strict\".", prevtoken);
6881 }
6882
6883 statements();
6884 }
6885 advance('(end)');
6886
6887 var markDefined = function (name, context) {
6888 do {
6889 if (typeof context[name] === 'string') {
6890 // JSHINT marks unused variables as 'unused' and
6891 // unused function declaration as 'unction'. This
6892 // code changes such instances back 'var' and
6893 // 'closure' so that the code in JSHINT.data()
6894 // doesn't think they're unused.
6895
6896 if (context[name] === 'unused')
6897 context[name] = 'var';
6898 else if (context[name] === 'unction')
6899 context[name] = 'closure';
6900
6901 return true;
6902 }
6903
6904 context = context['(context)'];
6905 } while (context);
6906
6907 return false;
6908 };
6909
6910 var clearImplied = function (name, line) {
6911 if (!implied[name])
6912 return;
6913
6914 var newImplied = [];
6915 for (var i = 0; i < implied[name].length; i += 1) {
6916 if (implied[name][i] !== line)
6917 newImplied.push(implied[name][i]);
6918 }
6919
6920 if (newImplied.length === 0)
6921 delete implied[name];
6922 else
6923 implied[name] = newImplied;
6924 };
6925
6926 // Check queued 'x is not defined' instances to see if they're still undefined.
6927 for (i = 0; i < JSHINT.undefs.length; i += 1) {
6928 k = JSHINT.undefs[i].slice(0);
6929
6930 if (markDefined(k[2].value, k[0])) {
6931 clearImplied(k[2].value, k[2].line);
6932 } else {
6933 warning.apply(warning, k.slice(1));
6934 }
6935 }
6936 } catch (e) {
6937 if (e) {
6938 var nt = nexttoken || {};
6939 JSHINT.errors.push({
6940 raw : e.raw,
6941 reason : e.message,
6942 line : e.line || nt.line,
6943 character : e.character || nt.from
6944 }, null);
6945 }
6946 }
6947
6948 return JSHINT.errors.length === 0;
6949 };
6950
6951 // Data summary.
6952 itself.data = function () {
6953
6954 var data = { functions: [], options: option }, fu, globals, implieds = [], f, i, j,
6955 members = [], n, unused = [], v;
6956 if (itself.errors.length) {
6957 data.errors = itself.errors;
6958 }
6959
6960 if (jsonmode) {
6961 data.json = true;
6962 }
6963
6964 for (n in implied) {
6965 if (is_own(implied, n)) {
6966 implieds.push({
6967 name: n,
6968 line: implied[n]
6969 });
6970 }
6971 }
6972 if (implieds.length > 0) {
6973 data.implieds = implieds;
6974 }
6975
6976 if (urls.length > 0) {
6977 data.urls = urls;
6978 }
6979
6980 globals = Object.keys(scope);
6981 if (globals.length > 0) {
6982 data.globals = globals;
6983 }
6984 for (i = 1; i < functions.length; i += 1) {
6985 f = functions[i];
6986 fu = {};
6987 for (j = 0; j < functionicity.length; j += 1) {
6988 fu[functionicity[j]] = [];
6989 }
6990 for (n in f) {
6991 if (is_own(f, n) && n.charAt(0) !== '(') {
6992 v = f[n];
6993 if (v === 'unction') {
6994 v = 'unused';
6995 }
6996 if (Array.isArray(fu[v])) {
6997 fu[v].push(n);
6998 if (v === 'unused') {
6999 unused.push({
7000 name: n,
7001 line: f['(line)'],
7002 'function': f['(name)']
7003 });
7004 }
7005 }
7006 }
7007 }
7008 for (j = 0; j < functionicity.length; j += 1) {
7009 if (fu[functionicity[j]].length === 0) {
7010 delete fu[functionicity[j]];
7011 }
7012 }
7013 fu.name = f['(name)'];
7014 fu.param = f['(params)'];
7015 fu.line = f['(line)'];
7016 fu.last = f['(last)'];
7017 data.functions.push(fu);
7018 }
7019
7020 if (unused.length > 0) {
7021 data.unused = unused;
7022 }
7023
7024 members = [];
7025 for (n in member) {
7026 if (typeof member[n] === 'number') {
7027 data.member = member;
7028 break;
7029 }
7030 }
7031
7032 return data;
7033 };
7034
7035 itself.report = function (option) {
7036 var data = itself.data();
7037
7038 var a = [], c, e, err, f, i, k, l, m = '', n, o = [], s;
7039
7040 function detail(h, array) {
7041 var b, i, singularity;
7042 if (array) {
7043 o.push('<div><i>' + h + '</i> ');
7044 array = array.sort();
7045 for (i = 0; i < array.length; i += 1) {
7046 if (array[i] !== singularity) {
7047 singularity = array[i];
7048 o.push((b ? ', ' : '') + singularity);
7049 b = true;
7050 }
7051 }
7052 o.push('</div>');
7053 }
7054 }
7055
7056
7057 if (data.errors || data.implieds || data.unused) {
7058 err = true;
7059 o.push('<div id=errors><i>Error:</i>');
7060 if (data.errors) {
7061 for (i = 0; i < data.errors.length; i += 1) {
7062 c = data.errors[i];
7063 if (c) {
7064 e = c.evidence || '';
7065 o.push('<p>Problem' + (isFinite(c.line) ? ' at line ' +
7066 c.line + ' character ' + c.character : '') +
7067 ': ' + c.reason.entityify() +
7068 '</p><p class=evidence>' +
7069 (e && (e.length > 80 ? e.slice(0, 77) + '...' :
7070 e).entityify()) + '</p>');
7071 }
7072 }
7073 }
7074
7075 if (data.implieds) {
7076 s = [];
7077 for (i = 0; i < data.implieds.length; i += 1) {
7078 s[i] = '<code>' + data.implieds[i].name + '</code>&nbsp;<i>' +
7079 data.implieds[i].line + '</i>';
7080 }
7081 o.push('<p><i>Implied global:</i> ' + s.join(', ') + '</p>');
7082 }
7083
7084 if (data.unused) {
7085 s = [];
7086 for (i = 0; i < data.unused.length; i += 1) {
7087 s[i] = '<code><u>' + data.unused[i].name + '</u></code>&nbsp;<i>' +
7088 data.unused[i].line + '</i> <code>' +
7089 data.unused[i]['function'] + '</code>';
7090 }
7091 o.push('<p><i>Unused variable:</i> ' + s.join(', ') + '</p>');
7092 }
7093 if (data.json) {
7094 o.push('<p>JSON: bad.</p>');
7095 }
7096 o.push('</div>');
7097 }
7098
7099 if (!option) {
7100
7101 o.push('<br><div id=functions>');
7102
7103 if (data.urls) {
7104 detail("URLs<br>", data.urls, '<br>');
7105 }
7106
7107 if (data.json && !err) {
7108 o.push('<p>JSON: good.</p>');
7109 } else if (data.globals) {
7110 o.push('<div><i>Global</i> ' +
7111 data.globals.sort().join(', ') + '</div>');
7112 } else {
7113 o.push('<div><i>No new global variables introduced.</i></div>');
7114 }
7115
7116 for (i = 0; i < data.functions.length; i += 1) {
7117 f = data.functions[i];
7118
7119 o.push('<br><div class=function><i>' + f.line + '-' +
7120 f.last + '</i> ' + (f.name || '') + '(' +
7121 (f.param ? f.param.join(', ') : '') + ')</div>');
7122 detail('<big><b>Unused</b></big>', f.unused);
7123 detail('Closure', f.closure);
7124 detail('Variable', f['var']);
7125 detail('Exception', f.exception);
7126 detail('Outer', f.outer);
7127 detail('Global', f.global);
7128 detail('Label', f.label);
7129 }
7130
7131 if (data.member) {
7132 a = Object.keys(data.member);
7133 if (a.length) {
7134 a = a.sort();
7135 m = '<br><pre id=members>/*members ';
7136 l = 10;
7137 for (i = 0; i < a.length; i += 1) {
7138 k = a[i];
7139 n = k.name();
7140 if (l + n.length > 72) {
7141 o.push(m + '<br>');
7142 m = ' ';
7143 l = 1;
7144 }
7145 l += n.length + 2;
7146 if (data.member[k] === 1) {
7147 n = '<i>' + n + '</i>';
7148 }
7149 if (i < a.length - 1) {
7150 n += ', ';
7151 }
7152 m += n;
7153 }
7154 o.push(m + '<br>*/</pre>');
7155 }
7156 o.push('</div>');
7157 }
7158 }
7159 return o.join('');
7160 };
7161
7162 itself.jshint = itself;
7163
7164 return itself;
7165 }());
7166
7167 // Make JSHINT a Node module, if possible.
7168 if (typeof exports === 'object' && exports)
7169 exports.JSHINT = JSHINT;
7170
7171 });/* -*- Mode: JS; tab-width: 4; indent-tabs-mode: nil; -*-
7172 * vim: set sw=4 ts=4 et tw=78:
7173 * ***** BEGIN LICENSE BLOCK *****
7174 *
7175 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7176 *
7177 * The contents of this file are subject to the Mozilla Public License Version
7178 * 1.1 (the "License"); you may not use this file except in compliance with
7179 * the License. You may obtain a copy of the License at
7180 * http://www.mozilla.org/MPL/
7181 *
7182 * Software distributed under the License is distributed on an "AS IS" basis,
7183 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
7184 * for the specific language governing rights and limitations under the
7185 * License.
7186 *
7187 * The Original Code is the Narcissus JavaScript engine.
7188 *
7189 * The Initial Developer of the Original Code is
7190 * Brendan Eich <brendan@mozilla.org>.
7191 * Portions created by the Initial Developer are Copyright (C) 2004
7192 * the Initial Developer. All Rights Reserved.
7193 *
7194 * Contributor(s):
7195 * Tom Austin <taustin@ucsc.edu>
7196 * Brendan Eich <brendan@mozilla.org>
7197 * Shu-Yu Guo <shu@rfrn.org>
7198 * Dave Herman <dherman@mozilla.com>
7199 * Dimitris Vardoulakis <dimvar@ccs.neu.edu>
7200 * Patrick Walton <pcwalton@mozilla.com>
7201 *
7202 * Alternatively, the contents of this file may be used under the terms of
7203 * either the GNU General Public License Version 2 or later (the "GPL"), or
7204 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
7205 * in which case the provisions of the GPL or the LGPL are applicable instead
7206 * of those above. If you wish to allow use of your version of this file only
7207 * under the terms of either the GPL or the LGPL, and not to allow others to
7208 * use your version of this file under the terms of the MPL, indicate your
7209 * decision by deleting the provisions above and replace them with the notice
7210 * and other provisions required by the GPL or the LGPL. If you do not delete
7211 * the provisions above, a recipient may use your version of this file under
7212 * the terms of any one of the MPL, the GPL or the LGPL.
7213 *
7214 * ***** END LICENSE BLOCK ***** */
7215
7216 /*
7217 * Narcissus - JS implemented in JS.
7218 *
7219 * Parser.
7220 */
7221
7222 define('ace/narcissus/parser', ['require', 'exports', 'module' , 'ace/narcissus/lexer', 'ace/narcissus/definitions', 'ace/narcissus/options'], function(require, exports, module) {
7223
7224 var lexer = require('./lexer');
7225 var definitions = require('./definitions');
7226 var options = require('./options');
7227 var Tokenizer = lexer.Tokenizer;
7228
7229 var Dict = definitions.Dict;
7230 var Stack = definitions.Stack;
7231
7232 // Set constants in the local scope.
7233 eval(definitions.consts);
7234
7235 /*
7236 * pushDestructuringVarDecls :: (node, hoisting node) -> void
7237 *
7238 * Recursively add all destructured declarations to varDecls.
7239 */
7240 function pushDestructuringVarDecls(n, s) {
7241 for (var i in n) {
7242 var sub = n[i];
7243 if (sub.type === IDENTIFIER) {
7244 s.varDecls.push(sub);
7245 } else {
7246 pushDestructuringVarDecls(sub, s);
7247 }
7248 }
7249 }
7250
7251 function Parser(tokenizer) {
7252 tokenizer.parser = this;
7253 this.t = tokenizer;
7254 this.x = null;
7255 this.unexpectedEOF = false;
7256 options.mozillaMode && (this.mozillaMode = true);
7257 options.parenFreeMode && (this.parenFreeMode = true);
7258 }
7259
7260 function StaticContext(parentScript, parentBlock, inModule, inFunction, strictMode) {
7261 this.parentScript = parentScript;
7262 this.parentBlock = parentBlock || parentScript;
7263 this.inModule = inModule || false;
7264 this.inFunction = inFunction || false;
7265 this.inForLoopInit = false;
7266 this.topLevel = true;
7267 this.allLabels = new Stack();
7268 this.currentLabels = new Stack();
7269 this.labeledTargets = new Stack();
7270 this.defaultLoopTarget = null;
7271 this.defaultTarget = null;
7272 this.strictMode = strictMode;
7273 }
7274
7275 StaticContext.prototype = {
7276 // non-destructive update via prototype extension
7277 update: function(ext) {
7278 var desc = {};
7279 for (var key in ext) {
7280 desc[key] = {
7281 value: ext[key],
7282 writable: true,
7283 enumerable: true,
7284 configurable: true
7285 }
7286 }
7287 return Object.create(this, desc);
7288 },
7289 pushLabel: function(label) {
7290 return this.update({ currentLabels: this.currentLabels.push(label),
7291 allLabels: this.allLabels.push(label) });
7292 },
7293 pushTarget: function(target) {
7294 var isDefaultLoopTarget = target.isLoop;
7295 var isDefaultTarget = isDefaultLoopTarget || target.type === SWITCH;
7296
7297 if (this.currentLabels.isEmpty()) {
7298 if (isDefaultLoopTarget) this.update({ defaultLoopTarget: target });
7299 if (isDefaultTarget) this.update({ defaultTarget: target });
7300 return this;
7301 }
7302
7303 target.labels = new Dict();
7304 this.currentLabels.forEach(function(label) {
7305 target.labels.set(label, true);
7306 });
7307 return this.update({ currentLabels: new Stack(),
7308 labeledTargets: this.labeledTargets.push(target),
7309 defaultLoopTarget: isDefaultLoopTarget
7310 ? target
7311 : this.defaultLoopTarget,
7312 defaultTarget: isDefaultTarget
7313 ? target
7314 : this.defaultTarget });
7315 },
7316 nest: function() {
7317 return this.topLevel ? this.update({ topLevel: false }) : this;
7318 },
7319 canImport: function() {
7320 return this.topLevel && !this.inFunction;
7321 },
7322 canExport: function() {
7323 return this.inModule && this.topLevel && !this.inFunction;
7324 },
7325 banWith: function() {
7326 return this.strictMode || this.inModule;
7327 },
7328 modulesAllowed: function() {
7329 return this.topLevel && !this.inFunction;
7330 }
7331 };
7332
7333 var Pp = Parser.prototype;
7334
7335 Pp.mozillaMode = false;
7336
7337 Pp.parenFreeMode = false;
7338
7339 Pp.withContext = function(x, f) {
7340 var x0 = this.x;
7341 this.x = x;
7342 var result = f.call(this);
7343 // NB: we don't bother with finally, since exceptions trash the parser
7344 this.x = x0;
7345 return result;
7346 };
7347
7348 Pp.newNode = function newNode(opts) {
7349 return new Node(this.t, opts);
7350 };
7351
7352 Pp.fail = function fail(msg) {
7353 throw this.t.newSyntaxError(msg);
7354 };
7355
7356 Pp.match = function match(tt, scanOperand, keywordIsName) {
7357 return this.t.match(tt, scanOperand, keywordIsName);
7358 };
7359
7360 Pp.mustMatch = function mustMatch(tt, keywordIsName) {
7361 return this.t.mustMatch(tt, keywordIsName);
7362 };
7363
7364 Pp.peek = function peek(scanOperand) {
7365 return this.t.peek(scanOperand);
7366 };
7367
7368 Pp.peekOnSameLine = function peekOnSameLine(scanOperand) {
7369 return this.t.peekOnSameLine(scanOperand);
7370 };
7371
7372 Pp.done = function done() {
7373 return this.t.done;
7374 };
7375
7376 /*
7377 * Script :: (boolean, boolean, boolean) -> node
7378 *
7379 * Parses the toplevel and module/function bodies.
7380 */
7381 Pp.Script = function Script(inModule, inFunction, expectEnd) {
7382 var node = this.newNode(scriptInit());
7383 var x2 = new StaticContext(node, node, inModule, inFunction);
7384 this.withContext(x2, function() {
7385 this.Statements(node, true);
7386 });
7387 if (expectEnd && !this.done())
7388 this.fail("expected end of input");
7389 return node;
7390 };
7391
7392 /*
7393 * Pragma :: (expression statement node) -> boolean
7394 *
7395 * Checks whether a node is a pragma and annotates it.
7396 */
7397 function Pragma(n) {
7398 if (n.type === SEMICOLON) {
7399 var e = n.expression;
7400 if (e.type === STRING && e.value === "use strict") {
7401 n.pragma = "strict";
7402 return true;
7403 }
7404 }
7405 return false;
7406 }
7407
7408 /*
7409 * Node :: (tokenizer, optional init object) -> node
7410 */
7411 function Node(t, init) {
7412 var token = t.token;
7413 if (token) {
7414 // If init.type exists it will override token.type.
7415 this.type = token.type;
7416 this.value = token.value;
7417 this.lineno = token.lineno;
7418
7419 // Start and end are file positions for error handling.
7420 this.start = token.start;
7421 this.end = token.end;
7422 } else {
7423 this.lineno = t.lineno;
7424 }
7425
7426 this.filename = t.filename;
7427 this.children = [];
7428
7429 for (var prop in init)
7430 this[prop] = init[prop];
7431 }
7432
7433 /*
7434 * SyntheticNode :: (optional init object) -> node
7435 */
7436 function SyntheticNode(init) {
7437 this.children = [];
7438 for (var prop in init)
7439 this[prop] = init[prop];
7440 this.synthetic = true;
7441 }
7442
7443 var Np = Node.prototype = SyntheticNode.prototype = {};
7444 Np.constructor = Node;
7445
7446 var TO_SOURCE_SKIP = {
7447 type: true,
7448 value: true,
7449 lineno: true,
7450 start: true,
7451 end: true,
7452 tokenizer: true,
7453 assignOp: true
7454 };
7455 function unevalableConst(code) {
7456 var token = definitions.tokens[code];
7457 var constName = definitions.opTypeNames.hasOwnProperty(token)
7458 ? definitions.opTypeNames[token]
7459 : token in definitions.keywords
7460 ? token.toUpperCase()
7461 : token;
7462 return { toSource: function() { return constName } };
7463 }
7464 Np.toSource = function toSource() {
7465 var mock = {};
7466 var self = this;
7467 mock.type = unevalableConst(this.type);
7468 // avoid infinite recursion in case of back-links
7469 if (this.generatingSource)
7470 return mock.toSource();
7471 this.generatingSource = true;
7472 if ("value" in this)
7473 mock.value = this.value;
7474 if ("lineno" in this)
7475 mock.lineno = this.lineno;
7476 if ("start" in this)
7477 mock.start = this.start;
7478 if ("end" in this)
7479 mock.end = this.end;
7480 if (this.assignOp)
7481 mock.assignOp = unevalableConst(this.assignOp);
7482 for (var key in this) {
7483 if (this.hasOwnProperty(key) && !(key in TO_SOURCE_SKIP))
7484 mock[key] = this[key];
7485 }
7486 try {
7487 return mock.toSource();
7488 } finally {
7489 delete this.generatingSource;
7490 }
7491 };
7492
7493 // Always use push to add operands to an expression, to update start and end.
7494 Np.push = function (kid) {
7495 // kid can be null e.g. [1, , 2].
7496 if (kid !== null) {
7497 if (kid.start < this.start)
7498 this.start = kid.start;
7499 if (this.end < kid.end)
7500 this.end = kid.end;
7501 }
7502 return this.children.push(kid);
7503 }
7504
7505 Node.indentLevel = 0;
7506
7507 function tokenString(tt) {
7508 var t = definitions.tokens[tt];
7509 return /^\W/.test(t) ? definitions.opTypeNames[t] : t.toUpperCase();
7510 }
7511
7512 Np.toString = function () {
7513 var a = [];
7514 for (var i in this) {
7515 if (this.hasOwnProperty(i) && i !== 'type' && i !== 'target')
7516 a.push({id: i, value: this[i]});
7517 }
7518 a.sort(function (a,b) { return (a.id < b.id) ? -1 : 1; });
7519 var INDENTATION = " ";
7520 var n = ++Node.indentLevel;
7521 var s = "{\n" + INDENTATION.repeat(n) + "type: " + tokenString(this.type);
7522 for (i = 0; i < a.length; i++)
7523 s += ",\n" + INDENTATION.repeat(n) + a[i].id + ": " + a[i].value;
7524 n = --Node.indentLevel;
7525 s += "\n" + INDENTATION.repeat(n) + "}";
7526 return s;
7527 }
7528
7529 Np.synth = function(init) {
7530 var node = new SyntheticNode(init);
7531 node.filename = this.filename;
7532 node.lineno = this.lineno;
7533 node.start = this.start;
7534 node.end = this.end;
7535 return node;
7536 };
7537
7538 /*
7539 * Helper init objects for common nodes.
7540 */
7541
7542 var LOOP_INIT = { isLoop: true };
7543
7544 function blockInit() {
7545 return { type: BLOCK, varDecls: [] };
7546 }
7547
7548 function scriptInit() {
7549 return { type: SCRIPT,
7550 funDecls: [],
7551 varDecls: [],
7552 modDefns: new Dict(),
7553 modAssns: new Dict(),
7554 modDecls: new Dict(),
7555 modLoads: new Dict(),
7556 impDecls: [],
7557 expDecls: [],
7558 exports: new Dict(),
7559 hasEmptyReturn: false,
7560 hasReturnWithValue: false,
7561 hasYield: false };
7562 }
7563
7564 definitions.defineGetter(Np, "length",
7565 function() {
7566 throw new Error("Node.prototype.length is gone; " +
7567 "use n.children.length instead");
7568 });
7569
7570 definitions.defineProperty(String.prototype, "repeat",
7571 function(n) {
7572 var s = "", t = this + s;
7573 while (--n >= 0)
7574 s += t;
7575 return s;
7576 }, false, false, true);
7577
7578 Pp.MaybeLeftParen = function MaybeLeftParen() {
7579 if (this.parenFreeMode)
7580 return this.match(LEFT_PAREN) ? LEFT_PAREN : END;
7581 return this.mustMatch(LEFT_PAREN).type;
7582 };
7583
7584 Pp.MaybeRightParen = function MaybeRightParen(p) {
7585 if (p === LEFT_PAREN)
7586 this.mustMatch(RIGHT_PAREN);
7587 }
7588
7589 /*
7590 * Statements :: (node[, boolean]) -> void
7591 *
7592 * Parses a sequence of Statements.
7593 */
7594 Pp.Statements = function Statements(n, topLevel) {
7595 var prologue = !!topLevel;
7596 try {
7597 while (!this.done() && this.peek(true) !== RIGHT_CURLY) {
7598 var n2 = this.Statement();
7599 n.push(n2);
7600 if (prologue && Pragma(n2)) {
7601 this.x.strictMode = true;
7602 n.strict = true;
7603 } else {
7604 prologue = false;
7605 }
7606 }
7607 } catch (e) {
7608 try {
7609 if (this.done())
7610 this.unexpectedEOF = true;
7611 } catch(e) {}
7612 throw e;
7613 }
7614 }
7615
7616 Pp.Block = function Block() {
7617 this.mustMatch(LEFT_CURLY);
7618 var n = this.newNode(blockInit());
7619 var x2 = this.x.update({ parentBlock: n }).pushTarget(n);
7620 this.withContext(x2, function() {
7621 this.Statements(n);
7622 });
7623 this.mustMatch(RIGHT_CURLY);
7624 return n;
7625 }
7626
7627 var DECLARED_FORM = 0, EXPRESSED_FORM = 1, STATEMENT_FORM = 2;
7628
7629 /*
7630 * Export :: (binding node, boolean) -> Export
7631 *
7632 * Static semantic representation of a module export.
7633 */
7634 function Export(node, isDefinition) {
7635 this.node = node; // the AST node declaring this individual export
7636 this.isDefinition = isDefinition; // is the node an 'export'-annotated definition?
7637 this.resolved = null; // resolved pointer to the target of this export
7638 }
7639
7640 /*
7641 * registerExport :: (Dict, EXPORT node) -> void
7642 */
7643 function registerExport(exports, decl) {
7644 function register(name, exp) {
7645 if (exports.has(name))
7646 throw new SyntaxError("multiple exports of " + name);
7647 exports.set(name, exp);
7648 }
7649
7650 switch (decl.type) {
7651 case MODULE:
7652 case FUNCTION:
7653 register(decl.name, new Export(decl, true));
7654 break;
7655
7656 case VAR:
7657 for (var i = 0; i < decl.children.length; i++)
7658 register(decl.children[i].name, new Export(decl.children[i], true));
7659 break;
7660
7661 case LET:
7662 case CONST:
7663 throw new Error("NYI: " + definitions.tokens[decl.type]);
7664
7665 case EXPORT:
7666 for (var i = 0; i < decl.pathList.length; i++) {
7667 var path = decl.pathList[i];
7668 switch (path.type) {
7669 case OBJECT_INIT:
7670 for (var j = 0; j < path.children.length; j++) {
7671 // init :: IDENTIFIER | PROPERTY_INIT
7672 var init = path.children[j];
7673 if (init.type === IDENTIFIER)
7674 register(init.value, new Export(init, false));
7675 else
7676 register(init.children[0].value, new Export(init.children[1], false));
7677 }
7678 break;
7679
7680 case DOT:
7681 register(path.children[1].value, new Export(path, false));
7682 break;
7683
7684 case IDENTIFIER:
7685 register(path.value, new Export(path, false));
7686 break;
7687
7688 default:
7689 throw new Error("unexpected export path: " + definitions.tokens[path.type]);
7690 }
7691 }
7692 break;
7693
7694 default:
7695 throw new Error("unexpected export decl: " + definitions.tokens[exp.type]);
7696 }
7697 }
7698
7699 /*
7700 * Module :: (node) -> Module
7701 *
7702 * Static semantic representation of a module.
7703 */
7704 function Module(node) {
7705 var exports = node.body.exports;
7706 var modDefns = node.body.modDefns;
7707
7708 var exportedModules = new Dict();
7709
7710 exports.forEach(function(name, exp) {
7711 var node = exp.node;
7712 if (node.type === MODULE) {
7713 exportedModules.set(name, node);
7714 } else if (!exp.isDefinition && node.type === IDENTIFIER && modDefns.has(node.value)) {
7715 var mod = modDefns.get(node.value);
7716 exportedModules.set(name, mod);
7717 }
7718 });
7719
7720 this.node = node;
7721 this.exports = exports;
7722 this.exportedModules = exportedModules;
7723 }
7724
7725 /*
7726 * Statement :: () -> node
7727 *
7728 * Parses a Statement.
7729 */
7730 Pp.Statement = function Statement() {
7731 var i, label, n, n2, p, c, ss, tt = this.t.get(true), tt2, x0, x2, x3;
7732
7733 var comments = this.t.blockComments;
7734
7735 // Cases for statements ending in a right curly return early, avoiding the
7736 // common semicolon insertion magic after this switch.
7737 switch (tt) {
7738 case IMPORT:
7739 if (!this.x.canImport())
7740 this.fail("illegal context for import statement");
7741 n = this.newNode();
7742 n.pathList = this.ImportPathList();
7743 this.x.parentScript.impDecls.push(n);
7744 break;
7745
7746 case EXPORT:
7747 if (!this.x.canExport())
7748 this.fail("export statement not in module top level");
7749 switch (this.peek()) {
7750 case MODULE:
7751 case FUNCTION:
7752 case LET:
7753 case VAR:
7754 case CONST:
7755 n = this.Statement();
7756 n.blockComments = comments;
7757 n.exported = true;
7758 this.x.parentScript.expDecls.push(n);
7759 registerExport(this.x.parentScript.exports, n);
7760 return n;
7761 }
7762 n = this.newNode();
7763 n.pathList = this.ExportPathList();
7764 this.x.parentScript.expDecls.push(n);
7765 registerExport(this.x.parentScript.exports, n);
7766 break;
7767
7768 case FUNCTION:
7769 // DECLARED_FORM extends funDecls of x, STATEMENT_FORM doesn't.
7770 return this.FunctionDefinition(true, this.x.topLevel ? DECLARED_FORM : STATEMENT_FORM, comments);
7771
7772 case LEFT_CURLY:
7773 n = this.newNode(blockInit());
7774 x2 = this.x.update({ parentBlock: n }).pushTarget(n).nest();
7775 this.withContext(x2, function() {
7776 this.Statements(n);
7777 });
7778 this.mustMatch(RIGHT_CURLY);
7779 return n;
7780
7781 case IF:
7782 n = this.newNode();
7783 n.condition = this.HeadExpression();
7784 x2 = this.x.pushTarget(n).nest();
7785 this.withContext(x2, function() {
7786 n.thenPart = this.Statement();
7787 n.elsePart = this.match(ELSE, true) ? this.Statement() : null;
7788 });
7789 return n;
7790
7791 case SWITCH:
7792 // This allows CASEs after a DEFAULT, which is in the standard.
7793 n = this.newNode({ cases: [], defaultIndex: -1 });
7794 n.discriminant = this.HeadExpression();
7795 x2 = this.x.pushTarget(n).nest();
7796 this.withContext(x2, function() {
7797 this.mustMatch(LEFT_CURLY);
7798 while ((tt = this.t.get()) !== RIGHT_CURLY) {
7799 switch (tt) {
7800 case DEFAULT:
7801 if (n.defaultIndex >= 0)
7802 this.fail("More than one switch default");
7803 // FALL THROUGH
7804 case CASE:
7805 n2 = this.newNode();
7806 if (tt === DEFAULT)
7807 n.defaultIndex = n.cases.length;
7808 else
7809 n2.caseLabel = this.Expression(COLON);
7810 break;
7811
7812 default:
7813 this.fail("Invalid switch case");
7814 }
7815 this.mustMatch(COLON);
7816 n2.statements = this.newNode(blockInit());
7817 while ((tt=this.peek(true)) !== CASE && tt !== DEFAULT &&
7818 tt !== RIGHT_CURLY)
7819 n2.statements.push(this.Statement());
7820 n.cases.push(n2);
7821 }
7822 });
7823 return n;
7824
7825 case FOR:
7826 n = this.newNode(LOOP_INIT);
7827 n.blockComments = comments;
7828 if (this.match(IDENTIFIER)) {
7829 if (this.t.token.value === "each")
7830 n.isEach = true;
7831 else
7832 this.t.unget();
7833 }
7834 if (!this.parenFreeMode)
7835 this.mustMatch(LEFT_PAREN);
7836 x2 = this.x.pushTarget(n).nest();
7837 x3 = this.x.update({ inForLoopInit: true });
7838 n2 = null;
7839 if ((tt = this.peek(true)) !== SEMICOLON) {
7840 this.withContext(x3, function() {
7841 if (tt === VAR || tt === CONST) {
7842 this.t.get();
7843 n2 = this.Variables();
7844 } else if (tt === LET) {
7845 this.t.get();
7846 if (this.peek() === LEFT_PAREN) {
7847 n2 = this.LetBlock(false);
7848 } else {
7849 // Let in for head, we need to add an implicit block
7850 // around the rest of the for.
7851 this.x.parentBlock = n;
7852 n.varDecls = [];
7853 n2 = this.Variables();
7854 }
7855 } else {
7856 n2 = this.Expression();
7857 }
7858 });
7859 }
7860 if (n2 && this.match(IN)) {
7861 n.type = FOR_IN;
7862 this.withContext(x3, function() {
7863 n.object = this.Expression();
7864 if (n2.type === VAR || n2.type === LET) {
7865 c = n2.children;
7866
7867 // Destructuring turns one decl into multiples, so either
7868 // there must be only one destructuring or only one
7869 // decl.
7870 if (c.length !== 1 && n2.destructurings.length !== 1) {
7871 // FIXME: this.fail ?
7872 throw new SyntaxError("Invalid for..in left-hand side",
7873 this.filename, n2.lineno);
7874 }
7875 if (n2.destructurings.length > 0) {
7876 n.iterator = n2.destructurings[0];
7877 } else {
7878 n.iterator = c[0];
7879 }
7880 n.varDecl = n2;
7881 } else {
7882 if (n2.type === ARRAY_INIT || n2.type === OBJECT_INIT) {
7883 n2.destructuredNames = this.checkDestructuring(n2);
7884 }
7885 n.iterator = n2;
7886 }
7887 });
7888 } else {
7889 x3.inForLoopInit = false;
7890 n.setup = n2;
7891 this.mustMatch(SEMICOLON);
7892 if (n.isEach)
7893 this.fail("Invalid for each..in loop");
7894 this.withContext(x3, function() {
7895 n.condition = (this.peek(true) === SEMICOLON)
7896 ? null
7897 : this.Expression();
7898 this.mustMatch(SEMICOLON);
7899 tt2 = this.peek(true);
7900 n.update = (this.parenFreeMode
7901 ? tt2 === LEFT_CURLY || definitions.isStatementStartCode[tt2]
7902 : tt2 === RIGHT_PAREN)
7903 ? null
7904 : this.Expression();
7905 });
7906 }
7907 if (!this.parenFreeMode)
7908 this.mustMatch(RIGHT_PAREN);
7909 this.withContext(x2, function() {
7910 n.body = this.Statement();
7911 });
7912 return n;
7913
7914 case WHILE:
7915 n = this.newNode({ isLoop: true });
7916 n.blockComments = comments;
7917 n.condition = this.HeadExpression();
7918 x2 = this.x.pushTarget(n).nest();
7919 this.withContext(x2, function() {
7920 n.body = this.Statement();
7921 });
7922 return n;
7923
7924 case DO:
7925 n = this.newNode({ isLoop: true });
7926 n.blockComments = comments;
7927 x2 = this.x.pushTarget(n).next();
7928 this.withContext(x2, function() {
7929 n.body = this.Statement();
7930 });
7931 this.mustMatch(WHILE);
7932 n.condition = this.HeadExpression();
7933 // <script language="JavaScript"> (without version hints) may need
7934 // automatic semicolon insertion without a newline after do-while.
7935 // See http://bugzilla.mozilla.org/show_bug.cgi?id=238945.
7936 this.match(SEMICOLON);
7937 return n;
7938
7939 case BREAK:
7940 case CONTINUE:
7941 n = this.newNode();
7942 n.blockComments = comments;
7943
7944 // handle the |foo: break foo;| corner case
7945 x2 = this.x.pushTarget(n);
7946
7947 if (this.peekOnSameLine() === IDENTIFIER) {
7948 this.t.get();
7949 n.label = this.t.token.value;
7950 }
7951
7952 if (n.label) {
7953 n.target = x2.labeledTargets.find(function(target) {
7954 return target.labels.has(n.label)
7955 });
7956 } else if (tt === CONTINUE) {
7957 n.target = x2.defaultLoopTarget;
7958 } else {
7959 n.target = x2.defaultTarget;
7960 }
7961
7962 if (!n.target)
7963 this.fail("Invalid " + ((tt === BREAK) ? "break" : "continue"));
7964 if (!n.target.isLoop && tt === CONTINUE)
7965 this.fail("Invalid continue");
7966
7967 break;
7968
7969 case TRY:
7970 n = this.newNode({ catchClauses: [] });
7971 n.blockComments = comments;
7972 n.tryBlock = this.Block();
7973 while (this.match(CATCH)) {
7974 n2 = this.newNode();
7975 p = this.MaybeLeftParen();
7976 switch (this.t.get()) {
7977 case LEFT_BRACKET:
7978 case LEFT_CURLY:
7979 // Destructured catch identifiers.
7980 this.t.unget();
7981 n2.varName = this.DestructuringExpression(true);
7982 break;
7983 case IDENTIFIER:
7984 n2.varName = this.t.token.value;
7985 break;
7986 default:
7987 this.fail("missing identifier in catch");
7988 break;
7989 }
7990 if (this.match(IF)) {
7991 if (!this.mozillaMode)
7992 this.fail("Illegal catch guard");
7993 if (n.catchClauses.length && !n.catchClauses.top().guard)
7994 this.fail("Guarded catch after unguarded");
7995 n2.guard = this.Expression();
7996 }
7997 this.MaybeRightParen(p);
7998 n2.block = this.Block();
7999 n.catchClauses.push(n2);
8000 }
8001 if (this.match(FINALLY))
8002 n.finallyBlock = this.Block();
8003 if (!n.catchClauses.length && !n.finallyBlock)
8004 this.fail("Invalid try statement");
8005 return n;
8006
8007 case CATCH:
8008 case FINALLY:
8009 this.fail(definitions.tokens[tt] + " without preceding try");
8010
8011 case THROW:
8012 n = this.newNode();
8013 n.exception = this.Expression();
8014 break;
8015
8016 case RETURN:
8017 n = this.ReturnOrYield();
8018 break;
8019
8020 case WITH:
8021 if (this.x.banWith())
8022 this.fail("with statements not allowed in strict code or modules");
8023 n = this.newNode();
8024 n.blockComments = comments;
8025 n.object = this.HeadExpression();
8026 x2 = this.x.pushTarget(n).next();
8027 this.withContext(x2, function() {
8028 n.body = this.Statement();
8029 });
8030 return n;
8031
8032 case VAR:
8033 case CONST:
8034 n = this.Variables();
8035 break;
8036
8037 case LET:
8038 if (this.peek() === LEFT_PAREN) {
8039 n = this.LetBlock(true);
8040 return n;
8041 }
8042 n = this.Variables();
8043 break;
8044
8045 case DEBUGGER:
8046 n = this.newNode();
8047 break;
8048
8049 case NEWLINE:
8050 case SEMICOLON:
8051 n = this.newNode({ type: SEMICOLON });
8052 n.blockComments = comments;
8053 n.expression = null;
8054 return n;
8055
8056 case IDENTIFIER:
8057 case USE:
8058 case MODULE:
8059 switch (this.t.token.value) {
8060 case "use":
8061 if (!isPragmaToken(this.peekOnSameLine())) {
8062 this.t.unget();
8063 break;
8064 }
8065 return this.newNode({ type: USE, params: this.Pragmas() });
8066
8067 case "module":
8068 if (!this.x.modulesAllowed())
8069 this.fail("module declaration not at top level");
8070 this.x.parentScript.hasModules = true;
8071 tt = this.peekOnSameLine();
8072 if (tt !== IDENTIFIER && tt !== LEFT_CURLY) {
8073 this.t.unget();
8074 break;
8075 }
8076 n = this.newNode({ type: MODULE });
8077 n.blockComments = comments;
8078 this.mustMatch(IDENTIFIER);
8079 label = this.t.token.value;
8080
8081 if (this.match(LEFT_CURLY)) {
8082 n.name = label;
8083 n.body = this.Script(true, false);
8084 n.module = new Module(n);
8085 this.mustMatch(RIGHT_CURLY);
8086 this.x.parentScript.modDefns.set(n.name, n);
8087 return n;
8088 }
8089
8090 this.t.unget();
8091 this.ModuleVariables(n);
8092 return n;
8093
8094 default:
8095 tt = this.peek();
8096 // Labeled statement.
8097 if (tt === COLON) {
8098 label = this.t.token.value;
8099 if (this.x.allLabels.has(label))
8100 this.fail("Duplicate label: " + label);
8101 this.t.get();
8102 n = this.newNode({ type: LABEL, label: label });
8103 n.blockComments = comments;
8104 x2 = this.x.pushLabel(label).nest();
8105 this.withContext(x2, function() {
8106 n.statement = this.Statement();
8107 });
8108 n.target = (n.statement.type === LABEL) ? n.statement.target : n.statement;
8109 return n;
8110 }
8111 // FALL THROUGH
8112 }
8113 // FALL THROUGH
8114
8115 default:
8116 // Expression statement.
8117 // We unget the current token to parse the expression as a whole.
8118 n = this.newNode({ type: SEMICOLON });
8119 this.t.unget();
8120 n.blockComments = comments;
8121 n.expression = this.Expression();
8122 n.end = n.expression.end;
8123 break;
8124 }
8125
8126 n.blockComments = comments;
8127 this.MagicalSemicolon();
8128 return n;
8129 }
8130
8131 /*
8132 * isPragmaToken :: (number) -> boolean
8133 */
8134 function isPragmaToken(tt) {
8135 switch (tt) {
8136 case IDENTIFIER:
8137 case STRING:
8138 case NUMBER:
8139 case NULL:
8140 case TRUE:
8141 case FALSE:
8142 return true;
8143 }
8144 return false;
8145 }
8146
8147 /*
8148 * Pragmas :: () -> Array[Array[token]]
8149 */
8150 Pp.Pragmas = function Pragmas() {
8151 var pragmas = [];
8152 do {
8153 pragmas.push(this.Pragma());
8154 } while (this.match(COMMA));
8155 this.MagicalSemicolon();
8156 return pragmas;
8157 }
8158
8159 /*
8160 * Pragmas :: () -> Array[token]
8161 */
8162 Pp.Pragma = function Pragma() {
8163 var items = [];
8164 var tt;
8165 do {
8166 tt = this.t.get(true);
8167 items.push(this.t.token);
8168 } while (isPragmaToken(this.peek()));
8169 return items;
8170 }
8171
8172 /*
8173 * MagicalSemicolon :: () -> void
8174 */
8175 Pp.MagicalSemicolon = function MagicalSemicolon() {
8176 var tt;
8177 if (this.t.lineno === this.t.token.lineno) {
8178 tt = this.peekOnSameLine();
8179 if (tt !== END && tt !== NEWLINE && tt !== SEMICOLON && tt !== RIGHT_CURLY)
8180 this.fail("missing ; before statement");
8181 }
8182 this.match(SEMICOLON);
8183 }
8184
8185 /*
8186 * ReturnOrYield :: () -> (RETURN | YIELD) node
8187 */
8188 Pp.ReturnOrYield = function ReturnOrYield() {
8189 var n, b, tt = this.t.token.type, tt2;
8190
8191 var parentScript = this.x.parentScript;
8192
8193 if (tt === RETURN) {
8194 if (!this.x.inFunction)
8195 this.fail("Return not in function");
8196 } else /* if (tt === YIELD) */ {
8197 if (!this.x.inFunction)
8198 this.fail("Yield not in function");
8199 parentScript.hasYield = true;
8200 }
8201 n = this.newNode({ value: undefined });
8202
8203 tt2 = (tt === RETURN) ? this.peekOnSameLine(true) : this.peek(true);
8204 if (tt2 !== END && tt2 !== NEWLINE &&
8205 tt2 !== SEMICOLON && tt2 !== RIGHT_CURLY
8206 && (tt !== YIELD ||
8207 (tt2 !== tt && tt2 !== RIGHT_BRACKET && tt2 !== RIGHT_PAREN &&
8208 tt2 !== COLON && tt2 !== COMMA))) {
8209 if (tt === RETURN) {
8210 n.value = this.Expression();
8211 parentScript.hasReturnWithValue = true;
8212 } else {
8213 n.value = this.AssignExpression();
8214 }
8215 } else if (tt === RETURN) {
8216 parentScript.hasEmptyReturn = true;
8217 }
8218
8219 return n;
8220 }
8221
8222 /*
8223 * ModuleExpression :: () -> (STRING | IDENTIFIER | DOT) node
8224 */
8225 Pp.ModuleExpression = function ModuleExpression() {
8226 return this.match(STRING) ? this.newNode() : this.QualifiedPath();
8227 }
8228
8229 /*
8230 * ImportPathList :: () -> Array[DOT node]
8231 */
8232 Pp.ImportPathList = function ImportPathList() {
8233 var a = [];
8234 do {
8235 a.push(this.ImportPath());
8236 } while (this.match(COMMA));
8237 return a;
8238 }
8239
8240 /*
8241 * ImportPath :: () -> DOT node
8242 */
8243 Pp.ImportPath = function ImportPath() {
8244 var n = this.QualifiedPath();
8245 if (!this.match(DOT)) {
8246 if (n.type === IDENTIFIER)
8247 this.fail("cannot import local variable");
8248 return n;
8249 }
8250
8251 var n2 = this.newNode();
8252 n2.push(n);
8253 n2.push(this.ImportSpecifierSet());
8254 return n2;
8255 }
8256
8257 /*
8258 * ExplicitSpecifierSet :: (() -> node) -> OBJECT_INIT node
8259 */
8260 Pp.ExplicitSpecifierSet = function ExplicitSpecifierSet(SpecifierRHS) {
8261 var n, n2, id, tt;
8262
8263 n = this.newNode({ type: OBJECT_INIT });
8264 this.mustMatch(LEFT_CURLY);
8265
8266 if (!this.match(RIGHT_CURLY)) {
8267 do {
8268 id = this.Identifier();
8269 if (this.match(COLON)) {
8270 n2 = this.newNode({ type: PROPERTY_INIT });
8271 n2.push(id);
8272 n2.push(SpecifierRHS());
8273 n.push(n2);
8274 } else {
8275 n.push(id);
8276 }
8277 } while (!this.match(RIGHT_CURLY) && this.mustMatch(COMMA));
8278 }
8279
8280 return n;
8281 }
8282
8283 /*
8284 * ImportSpecifierSet :: () -> (IDENTIFIER | OBJECT_INIT) node
8285 */
8286 Pp.ImportSpecifierSet = function ImportSpecifierSet() {
8287 var self = this;
8288 return this.match(MUL)
8289 ? this.newNode({ type: IDENTIFIER, name: "*" })
8290 : ExplicitSpecifierSet(function() { return self.Identifier() });
8291 }
8292
8293 /*
8294 * Identifier :: () -> IDENTIFIER node
8295 */
8296 Pp.Identifier = function Identifier() {
8297 this.mustMatch(IDENTIFIER);
8298 return this.newNode({ type: IDENTIFIER });
8299 }
8300
8301 /*
8302 * IdentifierName :: () -> IDENTIFIER node
8303 */
8304 Pp.IdentifierName = function IdentifierName() {
8305 this.mustMatch(IDENTIFIER, true);
8306 return this.newNode({ type: IDENTIFIER });
8307 }
8308
8309 /*
8310 * QualifiedPath :: () -> (IDENTIFIER | DOT) node
8311 */
8312 Pp.QualifiedPath = function QualifiedPath() {
8313 var n, n2;
8314
8315 n = this.Identifier();
8316
8317 while (this.match(DOT)) {
8318 if (this.peek() !== IDENTIFIER) {
8319 // Unget the '.' token, which isn't part of the QualifiedPath.
8320 this.t.unget();
8321 break;
8322 }
8323 n2 = this.newNode();
8324 n2.push(n);
8325 n2.push(this.Identifier());
8326 n = n2;
8327 }
8328
8329 return n;
8330 }
8331
8332 /*
8333 * ExportPath :: () -> (IDENTIFIER | DOT | OBJECT_INIT) node
8334 */
8335 Pp.ExportPath = function ExportPath() {
8336 var self = this;
8337 if (this.peek() === LEFT_CURLY)
8338 return this.ExplicitSpecifierSet(function() { return self.QualifiedPath() });
8339 return this.QualifiedPath();
8340 }
8341
8342 /*
8343 * ExportPathList :: () -> Array[(IDENTIFIER | DOT | OBJECT_INIT) node]
8344 */
8345 Pp.ExportPathList = function ExportPathList() {
8346 var a = [];
8347 do {
8348 a.push(this.ExportPath());
8349 } while (this.match(COMMA));
8350 return a;
8351 }
8352
8353 /*
8354 * FunctionDefinition :: (boolean,
8355 * DECLARED_FORM or EXPRESSED_FORM or STATEMENT_FORM,
8356 * [string] or null or undefined)
8357 * -> node
8358 */
8359 Pp.FunctionDefinition = function FunctionDefinition(requireName, functionForm, comments) {
8360 var tt;
8361 var f = this.newNode({ params: [], paramComments: [] });
8362 if (typeof comments === "undefined")
8363 comments = null;
8364 f.blockComments = comments;
8365 if (f.type !== FUNCTION)
8366 f.type = (f.value === "get") ? GETTER : SETTER;
8367 if (this.match(MUL))
8368 f.isExplicitGenerator = true;
8369 if (this.match(IDENTIFIER, false, true))
8370 f.name = this.t.token.value;
8371 else if (requireName)
8372 this.fail("missing function identifier");
8373
8374 var inModule = this.x.inModule;
8375 x2 = new StaticContext(null, null, inModule, true, this.x.strictMode);
8376 this.withContext(x2, function() {
8377 this.mustMatch(LEFT_PAREN);
8378 if (!this.match(RIGHT_PAREN)) {
8379 do {
8380 tt = this.t.get();
8381 f.paramComments.push(this.t.lastBlockComment());
8382 switch (tt) {
8383 case LEFT_BRACKET:
8384 case LEFT_CURLY:
8385 // Destructured formal parameters.
8386 this.t.unget();
8387 f.params.push(this.DestructuringExpression());
8388 break;
8389 case IDENTIFIER:
8390 f.params.push(this.t.token.value);
8391 break;
8392 default:
8393 this.fail("missing formal parameter");
8394 }
8395 } while (this.match(COMMA));
8396 this.mustMatch(RIGHT_PAREN);
8397 }
8398
8399 // Do we have an expression closure or a normal body?
8400 tt = this.t.get(true);
8401 if (tt !== LEFT_CURLY)
8402 this.t.unget();
8403
8404 if (tt !== LEFT_CURLY) {
8405 f.body = this.AssignExpression();
8406 } else {
8407 f.body = this.Script(inModule, true);
8408 }
8409 });
8410
8411 if (tt === LEFT_CURLY)
8412 this.mustMatch(RIGHT_CURLY);
8413
8414 f.end = this.t.token.end;
8415 f.functionForm = functionForm;
8416 if (functionForm === DECLARED_FORM)
8417 this.x.parentScript.funDecls.push(f);
8418
8419 if (this.x.inModule && !f.isExplicitGenerator && f.body.hasYield)
8420 this.fail("yield in non-generator function");
8421
8422 if (f.isExplicitGenerator || f.body.hasYield)
8423 f.body = this.newNode({ type: GENERATOR, body: f.body });
8424
8425 return f;
8426 }
8427
8428 /*
8429 * ModuleVariables :: (MODULE node) -> void
8430 *
8431 * Parses a comma-separated list of module declarations (and maybe
8432 * initializations).
8433 */
8434 Pp.ModuleVariables = function ModuleVariables(n) {
8435 var n1, n2;
8436 do {
8437 n1 = this.Identifier();
8438 if (this.match(ASSIGN)) {
8439 n2 = this.ModuleExpression();
8440 n1.initializer = n2;
8441 if (n2.type === STRING)
8442 this.x.parentScript.modLoads.set(n1.value, n2.value);
8443 else
8444 this.x.parentScript.modAssns.set(n1.value, n1);
8445 }
8446 n.push(n1);
8447 } while (this.match(COMMA));
8448 }
8449
8450 /*
8451 * Variables :: () -> node
8452 *
8453 * Parses a comma-separated list of var declarations (and maybe
8454 * initializations).
8455 */
8456 Pp.Variables = function Variables(letBlock) {
8457 var n, n2, ss, i, s, tt;
8458
8459 tt = this.t.token.type;
8460 switch (tt) {
8461 case VAR:
8462 case CONST:
8463 s = this.x.parentScript;
8464 break;
8465 case LET:
8466 s = this.x.parentBlock;
8467 break;
8468 case LEFT_PAREN:
8469 tt = LET;
8470 s = letBlock;
8471 break;
8472 }
8473
8474 n = this.newNode({ type: tt, destructurings: [] });
8475
8476 do {
8477 tt = this.t.get();
8478 if (tt === LEFT_BRACKET || tt === LEFT_CURLY) {
8479 // Need to unget to parse the full destructured expression.
8480 this.t.unget();
8481
8482 var dexp = this.DestructuringExpression(true);
8483
8484 n2 = this.newNode({ type: IDENTIFIER,
8485 name: dexp,
8486 readOnly: n.type === CONST });
8487 n.push(n2);
8488 pushDestructuringVarDecls(n2.name.destructuredNames, s);
8489 n.destructurings.push({ exp: dexp, decl: n2 });
8490
8491 if (this.x.inForLoopInit && this.peek() === IN) {
8492 continue;
8493 }
8494
8495 this.mustMatch(ASSIGN);
8496 if (this.t.token.assignOp)
8497 this.fail("Invalid variable initialization");
8498
8499 n2.blockComment = this.t.lastBlockComment();
8500 n2.initializer = this.AssignExpression();
8501
8502 continue;
8503 }
8504
8505 if (tt !== IDENTIFIER)
8506 this.fail("missing variable name");
8507
8508 n2 = this.newNode({ type: IDENTIFIER,
8509 name: this.t.token.value,
8510 readOnly: n.type === CONST });
8511 n.push(n2);
8512 s.varDecls.push(n2);
8513
8514 if (this.match(ASSIGN)) {
8515 var comment = this.t.lastBlockComment();
8516 if (this.t.token.assignOp)
8517 this.fail("Invalid variable initialization");
8518
8519 n2.initializer = this.AssignExpression();
8520 } else {
8521 var comment = this.t.lastBlockComment();
8522 }
8523 n2.blockComment = comment;
8524 } while (this.match(COMMA));
8525
8526 return n;
8527 }
8528
8529 /*
8530 * LetBlock :: (boolean) -> node
8531 *
8532 * Does not handle let inside of for loop init.
8533 */
8534 Pp.LetBlock = function LetBlock(isStatement) {
8535 var n, n2;
8536
8537 // t.token.type must be LET
8538 n = this.newNode({ type: LET_BLOCK, varDecls: [] });
8539 this.mustMatch(LEFT_PAREN);
8540 n.variables = this.Variables(n);
8541 this.mustMatch(RIGHT_PAREN);
8542
8543 if (isStatement && this.peek() !== LEFT_CURLY) {
8544 /*
8545 * If this is really an expression in let statement guise, then we
8546 * need to wrap the LET_BLOCK node in a SEMICOLON node so that we pop
8547 * the return value of the expression.
8548 */
8549 n2 = this.newNode({ type: SEMICOLON, expression: n });
8550 isStatement = false;
8551 }
8552
8553 if (isStatement)
8554 n.block = this.Block();
8555 else
8556 n.expression = this.AssignExpression();
8557
8558 return n;
8559 }
8560
8561 Pp.checkDestructuring = function checkDestructuring(n, simpleNamesOnly) {
8562 if (n.type === ARRAY_COMP)
8563 this.fail("Invalid array comprehension left-hand side");
8564 if (n.type !== ARRAY_INIT && n.type !== OBJECT_INIT)
8565 return;
8566
8567 var lhss = {};
8568 var nn, n2, idx, sub, cc, c = n.children;
8569 for (var i = 0, j = c.length; i < j; i++) {
8570 if (!(nn = c[i]))
8571 continue;
8572 if (nn.type === PROPERTY_INIT) {
8573 cc = nn.children;
8574 sub = cc[1];
8575 idx = cc[0].value;
8576 } else if (n.type === OBJECT_INIT) {
8577 // Do we have destructuring shorthand {foo, bar}?
8578 sub = nn;
8579 idx = nn.value;
8580 } else {
8581 sub = nn;
8582 idx = i;
8583 }
8584
8585 if (sub.type === ARRAY_INIT || sub.type === OBJECT_INIT) {
8586 lhss[idx] = this.checkDestructuring(sub, simpleNamesOnly);
8587 } else {
8588 if (simpleNamesOnly && sub.type !== IDENTIFIER) {
8589 // In declarations, lhs must be simple names
8590 this.fail("missing name in pattern");
8591 }
8592
8593 lhss[idx] = sub;
8594 }
8595 }
8596
8597 return lhss;
8598 }
8599
8600 Pp.DestructuringExpression = function DestructuringExpression(simpleNamesOnly) {
8601 var n = this.PrimaryExpression();
8602 // Keep the list of lefthand sides for varDecls
8603 n.destructuredNames = this.checkDestructuring(n, simpleNamesOnly);
8604 return n;
8605 }
8606
8607 Pp.GeneratorExpression = function GeneratorExpression(e) {
8608 return this.newNode({ type: GENERATOR,
8609 expression: e,
8610 tail: this.ComprehensionTail() });
8611 }
8612
8613 Pp.ComprehensionTail = function ComprehensionTail() {
8614 var body, n, n2, n3, p;
8615
8616 // t.token.type must be FOR
8617 body = this.newNode({ type: COMP_TAIL });
8618
8619 do {
8620 // Comprehension tails are always for..in loops.
8621 n = this.newNode({ type: FOR_IN, isLoop: true });
8622 if (this.match(IDENTIFIER)) {
8623 // But sometimes they're for each..in.
8624 if (this.mozillaMode && this.t.token.value === "each")
8625 n.isEach = true;
8626 else
8627 this.t.unget();
8628 }
8629 p = this.MaybeLeftParen();
8630 switch(this.t.get()) {
8631 case LEFT_BRACKET:
8632 case LEFT_CURLY:
8633 this.t.unget();
8634 // Destructured left side of for in comprehension tails.
8635 n.iterator = this.DestructuringExpression();
8636 break;
8637
8638 case IDENTIFIER:
8639 n.iterator = n3 = this.newNode({ type: IDENTIFIER });
8640 n3.name = n3.value;
8641 n.varDecl = n2 = this.newNode({ type: VAR });
8642 n2.push(n3);
8643 this.x.parentScript.varDecls.push(n3);
8644 // Don't add to varDecls since the semantics of comprehensions is
8645 // such that the variables are in their own function when
8646 // desugared.
8647 break;
8648
8649 default:
8650 this.fail("missing identifier");
8651 }
8652 this.mustMatch(IN);
8653 n.object = this.Expression();
8654 this.MaybeRightParen(p);
8655 body.push(n);
8656 } while (this.match(FOR));
8657
8658 // Optional guard.
8659 if (this.match(IF))
8660 body.guard = this.HeadExpression();
8661
8662 return body;
8663 }
8664
8665 Pp.HeadExpression = function HeadExpression() {
8666 var p = this.MaybeLeftParen();
8667 var n = this.ParenExpression();
8668 this.MaybeRightParen(p);
8669 if (p === END && !n.parenthesized) {
8670 var tt = this.peek();
8671 if (tt !== LEFT_CURLY && !definitions.isStatementStartCode[tt])
8672 this.fail("Unparenthesized head followed by unbraced body");
8673 }
8674 return n;
8675 }
8676
8677 Pp.ParenExpression = function ParenExpression() {
8678 // Always accept the 'in' operator in a parenthesized expression,
8679 // where it's unambiguous, even if we might be parsing the init of a
8680 // for statement.
8681 var x2 = this.x.update({
8682 inForLoopInit: this.x.inForLoopInit && (this.t.token.type === LEFT_PAREN)
8683 });
8684 var n = this.withContext(x2, function() {
8685 return this.Expression();
8686 });
8687 if (this.match(FOR)) {
8688 if (n.type === YIELD && !n.parenthesized)
8689 this.fail("Yield expression must be parenthesized");
8690 if (n.type === COMMA && !n.parenthesized)
8691 this.fail("Generator expression must be parenthesized");
8692 n = this.GeneratorExpression(n);
8693 }
8694
8695 return n;
8696 }
8697
8698 /*
8699 * Expression :: () -> node
8700 *
8701 * Top-down expression parser matched against SpiderMonkey.
8702 */
8703 Pp.Expression = function Expression() {
8704 var n, n2;
8705
8706 n = this.AssignExpression();
8707 if (this.match(COMMA)) {
8708 n2 = this.newNode({ type: COMMA });
8709 n2.push(n);
8710 n = n2;
8711 do {
8712 n2 = n.children[n.children.length-1];
8713 if (n2.type === YIELD && !n2.parenthesized)
8714 this.fail("Yield expression must be parenthesized");
8715 n.push(this.AssignExpression());
8716 } while (this.match(COMMA));
8717 }
8718
8719 return n;
8720 }
8721
8722 Pp.AssignExpression = function AssignExpression() {
8723 var n, lhs;
8724
8725 // Have to treat yield like an operand because it could be the leftmost
8726 // operand of the expression.
8727 if (this.match(YIELD, true))
8728 return this.ReturnOrYield();
8729
8730 n = this.newNode({ type: ASSIGN });
8731 lhs = this.ConditionalExpression();
8732
8733 if (!this.match(ASSIGN)) {
8734 return lhs;
8735 }
8736
8737 n.blockComment = this.t.lastBlockComment();
8738
8739 switch (lhs.type) {
8740 case OBJECT_INIT:
8741 case ARRAY_INIT:
8742 lhs.destructuredNames = this.checkDestructuring(lhs);
8743 // FALL THROUGH
8744 case IDENTIFIER: case DOT: case INDEX: case CALL:
8745 break;
8746 default:
8747 this.fail("Bad left-hand side of assignment");
8748 break;
8749 }
8750
8751 n.assignOp = lhs.assignOp = this.t.token.assignOp;
8752 n.push(lhs);
8753 n.push(this.AssignExpression());
8754
8755 return n;
8756 }
8757
8758 Pp.ConditionalExpression = function ConditionalExpression() {
8759 var n, n2;
8760
8761 n = this.OrExpression();
8762 if (this.match(HOOK)) {
8763 n2 = n;
8764 n = this.newNode({ type: HOOK });
8765 n.push(n2);
8766 /*
8767 * Always accept the 'in' operator in the middle clause of a ternary,
8768 * where it's unambiguous, even if we might be parsing the init of a
8769 * for statement.
8770 */
8771 var x2 = this.x.update({ inForLoopInit: false });
8772 this.withContext(x2, function() {
8773 n.push(this.AssignExpression());
8774 });
8775 if (!this.match(COLON))
8776 this.fail("missing : after ?");
8777 n.push(this.AssignExpression());
8778 }
8779
8780 return n;
8781 }
8782
8783 Pp.OrExpression = function OrExpression() {
8784 var n, n2;
8785
8786 n = this.AndExpression();
8787 while (this.match(OR)) {
8788 n2 = this.newNode();
8789 n2.push(n);
8790 n2.push(this.AndExpression());
8791 n = n2;
8792 }
8793
8794 return n;
8795 }
8796
8797 Pp.AndExpression = function AndExpression() {
8798 var n, n2;
8799
8800 n = this.BitwiseOrExpression();
8801 while (this.match(AND)) {
8802 n2 = this.newNode();
8803 n2.push(n);
8804 n2.push(this.BitwiseOrExpression());
8805 n = n2;
8806 }
8807
8808 return n;
8809 }
8810
8811 Pp.BitwiseOrExpression = function BitwiseOrExpression() {
8812 var n, n2;
8813
8814 n = this.BitwiseXorExpression();
8815 while (this.match(BITWISE_OR)) {
8816 n2 = this.newNode();
8817 n2.push(n);
8818 n2.push(this.BitwiseXorExpression());
8819 n = n2;
8820 }
8821
8822 return n;
8823 }
8824
8825 Pp.BitwiseXorExpression = function BitwiseXorExpression() {
8826 var n, n2;
8827
8828 n = this.BitwiseAndExpression();
8829 while (this.match(BITWISE_XOR)) {
8830 n2 = this.newNode();
8831 n2.push(n);
8832 n2.push(this.BitwiseAndExpression());
8833 n = n2;
8834 }
8835
8836 return n;
8837 }
8838
8839 Pp.BitwiseAndExpression = function BitwiseAndExpression() {
8840 var n, n2;
8841
8842 n = this.EqualityExpression();
8843 while (this.match(BITWISE_AND)) {
8844 n2 = this.newNode();
8845 n2.push(n);
8846 n2.push(this.EqualityExpression());
8847 n = n2;
8848 }
8849
8850 return n;
8851 }
8852
8853 Pp.EqualityExpression = function EqualityExpression() {
8854 var n, n2;
8855
8856 n = this.RelationalExpression();
8857 while (this.match(EQ) || this.match(NE) ||
8858 this.match(STRICT_EQ) || this.match(STRICT_NE)) {
8859 n2 = this.newNode();
8860 n2.push(n);
8861 n2.push(this.RelationalExpression());
8862 n = n2;
8863 }
8864
8865 return n;
8866 }
8867
8868 Pp.RelationalExpression = function RelationalExpression() {
8869 var n, n2;
8870
8871 /*
8872 * Uses of the in operator in shiftExprs are always unambiguous,
8873 * so unset the flag that prohibits recognizing it.
8874 */
8875 var x2 = this.x.update({ inForLoopInit: false });
8876 this.withContext(x2, function() {
8877 n = this.ShiftExpression();
8878 while ((this.match(LT) || this.match(LE) || this.match(GE) || this.match(GT) ||
8879 (!this.x.inForLoopInit && this.match(IN)) ||
8880 this.match(INSTANCEOF))) {
8881 n2 = this.newNode();
8882 n2.push(n);
8883 n2.push(this.ShiftExpression());
8884 n = n2;
8885 }
8886 });
8887
8888 return n;
8889 }
8890
8891 Pp.ShiftExpression = function ShiftExpression() {
8892 var n, n2;
8893
8894 n = this.AddExpression();
8895 while (this.match(LSH) || this.match(RSH) || this.match(URSH)) {
8896 n2 = this.newNode();
8897 n2.push(n);
8898 n2.push(this.AddExpression());
8899 n = n2;
8900 }
8901
8902 return n;
8903 }
8904
8905 Pp.AddExpression = function AddExpression() {
8906 var n, n2;
8907
8908 n = this.MultiplyExpression();
8909 while (this.match(PLUS) || this.match(MINUS)) {
8910 n2 = this.newNode();
8911 n2.push(n);
8912 n2.push(this.MultiplyExpression());
8913 n = n2;
8914 }
8915
8916 return n;
8917 }
8918
8919 Pp.MultiplyExpression = function MultiplyExpression() {
8920 var n, n2;
8921
8922 n = this.UnaryExpression();
8923 while (this.match(MUL) || this.match(DIV) || this.match(MOD)) {
8924 n2 = this.newNode();
8925 n2.push(n);
8926 n2.push(this.UnaryExpression());
8927 n = n2;
8928 }
8929
8930 return n;
8931 }
8932
8933 Pp.UnaryExpression = function UnaryExpression() {
8934 var n, n2, tt;
8935
8936 switch (tt = this.t.get(true)) {
8937 case DELETE: case VOID: case TYPEOF:
8938 case NOT: case BITWISE_NOT: case PLUS: case MINUS:
8939 if (tt === PLUS)
8940 n = this.newNode({ type: UNARY_PLUS });
8941 else if (tt === MINUS)
8942 n = this.newNode({ type: UNARY_MINUS });
8943 else
8944 n = this.newNode();
8945 n.push(this.UnaryExpression());
8946 break;
8947
8948 case INCREMENT:
8949 case DECREMENT:
8950 // Prefix increment/decrement.
8951 n = this.newNode();
8952 n.push(this.MemberExpression(true));
8953 break;
8954
8955 default:
8956 this.t.unget();
8957 n = this.MemberExpression(true);
8958
8959 // Don't look across a newline boundary for a postfix {in,de}crement.
8960 if (this.t.tokens[(this.t.tokenIndex + this.t.lookahead - 1) & 3].lineno ===
8961 this.t.lineno) {
8962 if (this.match(INCREMENT) || this.match(DECREMENT)) {
8963 n2 = this.newNode({ postfix: true });
8964 n2.push(n);
8965 n = n2;
8966 }
8967 }
8968 break;
8969 }
8970
8971 return n;
8972 }
8973
8974 Pp.MemberExpression = function MemberExpression(allowCallSyntax) {
8975 var n, n2, name, tt;
8976
8977 if (this.match(NEW)) {
8978 n = this.newNode();
8979 n.push(this.MemberExpression(false));
8980 if (this.match(LEFT_PAREN)) {
8981 n.type = NEW_WITH_ARGS;
8982 n.push(this.ArgumentList());
8983 }
8984 } else {
8985 n = this.PrimaryExpression();
8986 }
8987
8988 while ((tt = this.t.get()) !== END) {
8989 switch (tt) {
8990 case DOT:
8991 n2 = this.newNode();
8992 n2.push(n);
8993 n2.push(this.IdentifierName());
8994 break;
8995
8996 case LEFT_BRACKET:
8997 n2 = this.newNode({ type: INDEX });
8998 n2.push(n);
8999 n2.push(this.Expression());
9000 this.mustMatch(RIGHT_BRACKET);
9001 break;
9002
9003 case LEFT_PAREN:
9004 if (allowCallSyntax) {
9005 n2 = this.newNode({ type: CALL });
9006 n2.push(n);
9007 n2.push(this.ArgumentList());
9008 break;
9009 }
9010
9011 // FALL THROUGH
9012 default:
9013 this.t.unget();
9014 return n;
9015 }
9016
9017 n = n2;
9018 }
9019
9020 return n;
9021 }
9022
9023 Pp.ArgumentList = function ArgumentList() {
9024 var n, n2;
9025
9026 n = this.newNode({ type: LIST });
9027 if (this.match(RIGHT_PAREN, true))
9028 return n;
9029 do {
9030 n2 = this.AssignExpression();
9031 if (n2.type === YIELD && !n2.parenthesized && this.peek() === COMMA)
9032 this.fail("Yield expression must be parenthesized");
9033 if (this.match(FOR)) {
9034 n2 = this.GeneratorExpression(n2);
9035 if (n.children.length > 1 || this.peek(true) === COMMA)
9036 this.fail("Generator expression must be parenthesized");
9037 }
9038 n.push(n2);
9039 } while (this.match(COMMA));
9040 this.mustMatch(RIGHT_PAREN);
9041
9042 return n;
9043 }
9044
9045 Pp.PrimaryExpression = function PrimaryExpression() {
9046 var n, n2, tt = this.t.get(true);
9047
9048 switch (tt) {
9049 case FUNCTION:
9050 n = this.FunctionDefinition(false, EXPRESSED_FORM);
9051 break;
9052
9053 case LEFT_BRACKET:
9054 n = this.newNode({ type: ARRAY_INIT });
9055 while ((tt = this.peek(true)) !== RIGHT_BRACKET) {
9056 if (tt === COMMA) {
9057 this.t.get();
9058 n.push(null);
9059 continue;
9060 }
9061 n.push(this.AssignExpression());
9062 if (tt !== COMMA && !this.match(COMMA))
9063 break;
9064 }
9065
9066 // If we matched exactly one element and got a FOR, we have an
9067 // array comprehension.
9068 if (n.children.length === 1 && this.match(FOR)) {
9069 n2 = this.newNode({ type: ARRAY_COMP,
9070 expression: n.children[0],
9071 tail: this.ComprehensionTail() });
9072 n = n2;
9073 }
9074 this.mustMatch(RIGHT_BRACKET);
9075 break;
9076
9077 case LEFT_CURLY:
9078 var id, fd;
9079 n = this.newNode({ type: OBJECT_INIT });
9080
9081 object_init:
9082 if (!this.match(RIGHT_CURLY)) {
9083 do {
9084 tt = this.t.get();
9085 if ((this.t.token.value === "get" || this.t.token.value === "set") &&
9086 this.peek() === IDENTIFIER) {
9087 n.push(this.FunctionDefinition(true, EXPRESSED_FORM));
9088 } else {
9089 var comments = this.t.blockComments;
9090 switch (tt) {
9091 case IDENTIFIER: case NUMBER: case STRING:
9092 id = this.newNode({ type: IDENTIFIER });
9093 break;
9094 case RIGHT_CURLY:
9095 break object_init;
9096 default:
9097 if (this.t.token.value in definitions.keywords) {
9098 id = this.newNode({ type: IDENTIFIER });
9099 break;
9100 }
9101 this.fail("Invalid property name");
9102 }
9103 if (this.match(COLON)) {
9104 n2 = this.newNode({ type: PROPERTY_INIT });
9105 n2.push(id);
9106 n2.push(this.AssignExpression());
9107 n2.blockComments = comments;
9108 n.push(n2);
9109 } else {
9110 // Support, e.g., |var {x, y} = o| as destructuring shorthand
9111 // for |var {x: x, y: y} = o|, per proposed JS2/ES4 for JS1.8.
9112 if (this.peek() !== COMMA && this.peek() !== RIGHT_CURLY)
9113 this.fail("missing : after property");
9114 n.push(id);
9115 }
9116 }
9117 } while (this.match(COMMA));
9118 this.mustMatch(RIGHT_CURLY);
9119 }
9120 break;
9121
9122 case LEFT_PAREN:
9123 n = this.ParenExpression();
9124 this.mustMatch(RIGHT_PAREN);
9125 n.parenthesized = true;
9126 break;
9127
9128 case LET:
9129 n = this.LetBlock(false);
9130 break;
9131
9132 case NULL: case THIS: case TRUE: case FALSE:
9133 case IDENTIFIER: case NUMBER: case STRING: case REGEXP:
9134 n = this.newNode();
9135 break;
9136
9137 default:
9138 this.fail("missing operand; found " + definitions.tokens[tt]);
9139 break;
9140 }
9141
9142 return n;
9143 }
9144
9145 /*
9146 * parse :: (source, filename, line number) -> node
9147 */
9148 function parse(s, f, l) {
9149 var t = new Tokenizer(s, f, l, options.allowHTMLComments);
9150 var p = new Parser(t);
9151 return p.Script(false, false, true);
9152 }
9153
9154 /*
9155 * parseFunction :: (source, boolean,
9156 * DECLARED_FORM or EXPRESSED_FORM or STATEMENT_FORM,
9157 * filename, line number)
9158 * -> node
9159 */
9160 function parseFunction(s, requireName, form, f, l) {
9161 var t = new Tokenizer(s, f, l);
9162 var p = new Parser(t);
9163 p.x = new StaticContext(null, null, false, false, false);
9164 return p.FunctionDefinition(requireName, form);
9165 }
9166
9167 /*
9168 * parseStdin :: (source, {line number}, string, (string) -> boolean) -> program node
9169 */
9170 function parseStdin(s, ln, prefix, isCommand) {
9171 // the special .begin command is only recognized at the beginning
9172 if (s.match(/^[\s]*\.begin[\s]*$/)) {
9173 ++ln.value;
9174 return parseMultiline(ln, prefix);
9175 }
9176
9177 // commands at the beginning are treated as the entire input
9178 if (isCommand(s.trim()))
9179 s = "";
9180
9181 for (;;) {
9182 try {
9183 var t = new Tokenizer(s, "stdin", ln.value, false);
9184 var p = new Parser(t);
9185 var n = p.Script(false, false);
9186 ln.value = t.lineno;
9187 return n;
9188 } catch (e) {
9189 if (!p.unexpectedEOF)
9190 throw e;
9191
9192 // commands in the middle are not treated as part of the input
9193 var more;
9194 do {
9195 if (prefix)
9196 putstr(prefix);
9197 more = readline();
9198 if (!more)
9199 throw e;
9200 } while (isCommand(more.trim()));
9201
9202 s += "\n" + more;
9203 }
9204 }
9205 }
9206
9207 /*
9208 * parseMultiline :: ({line number}, string | null) -> program node
9209 */
9210 function parseMultiline(ln, prefix) {
9211 var s = "";
9212 for (;;) {
9213 if (prefix)
9214 putstr(prefix);
9215 var more = readline();
9216 if (more === null)
9217 return null;
9218 // the only command recognized in multiline mode is .end
9219 if (more.match(/^[\s]*\.end[\s]*$/))
9220 break;
9221 s += "\n" + more;
9222 }
9223 var t = new Tokenizer(s, "stdin", ln.value, false);
9224 var p = new Parser(t);
9225 var n = p.Script(false, false);
9226 ln.value = t.lineno;
9227 return n;
9228 }
9229
9230 exports.parse = parse;
9231 exports.parseStdin = parseStdin;
9232 exports.parseFunction = parseFunction;
9233 exports.Node = Node;
9234 exports.DECLARED_FORM = DECLARED_FORM;
9235 exports.EXPRESSED_FORM = EXPRESSED_FORM;
9236 exports.STATEMENT_FORM = STATEMENT_FORM;
9237 exports.Tokenizer = Tokenizer;
9238 exports.Parser = Parser;
9239 exports.Module = Module;
9240 exports.Export = Export;
9241
9242 });/* vim: set sw=4 ts=4 et tw=78: */
9243 /* ***** BEGIN LICENSE BLOCK *****
9244 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
9245 *
9246 * The contents of this file are subject to the Mozilla Public License Version
9247 * 1.1 (the "License"); you may not use this file except in compliance with
9248 * the License. You may obtain a copy of the License at
9249 * http://www.mozilla.org/MPL/
9250 *
9251 * Software distributed under the License is distributed on an "AS IS" basis,
9252 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
9253 * for the specific language governing rights and limitations under the
9254 * License.
9255 *
9256 * The Original Code is the Narcissus JavaScript engine.
9257 *
9258 * The Initial Developer of the Original Code is
9259 * Brendan Eich <brendan@mozilla.org>.
9260 * Portions created by the Initial Developer are Copyright (C) 2004
9261 * the Initial Developer. All Rights Reserved.
9262 *
9263 * Contributor(s):
9264 * Tom Austin <taustin@ucsc.edu>
9265 * Brendan Eich <brendan@mozilla.org>
9266 * Shu-Yu Guo <shu@rfrn.org>
9267 * Stephan Herhut <stephan.a.herhut@intel.com>
9268 * Dave Herman <dherman@mozilla.com>
9269 * Dimitris Vardoulakis <dimvar@ccs.neu.edu>
9270 * Patrick Walton <pcwalton@mozilla.com>
9271 *
9272 * Alternatively, the contents of this file may be used under the terms of
9273 * either the GNU General Public License Version 2 or later (the "GPL"), or
9274 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
9275 * in which case the provisions of the GPL or the LGPL are applicable instead
9276 * of those above. If you wish to allow use of your version of this file only
9277 * under the terms of either the GPL or the LGPL, and not to allow others to
9278 * use your version of this file under the terms of the MPL, indicate your
9279 * decision by deleting the provisions above and replace them with the notice
9280 * and other provisions required by the GPL or the LGPL. If you do not delete
9281 * the provisions above, a recipient may use your version of this file under
9282 * the terms of any one of the MPL, the GPL or the LGPL.
9283 *
9284 * ***** END LICENSE BLOCK ***** */
9285
9286 /*
9287 * Narcissus - JS implemented in JS.
9288 *
9289 * Lexical scanner.
9290 */
9291
9292 define('ace/narcissus/lexer', ['require', 'exports', 'module' , 'ace/narcissus/definitions'], function(require, exports, module) {
9293
9294 var definitions = require('./definitions');
9295
9296 // Set constants in the local scope.
9297 eval(definitions.consts);
9298
9299 // Build up a trie of operator tokens.
9300 var opTokens = {};
9301 for (var op in definitions.opTypeNames) {
9302 if (op === '\n' || op === '.')
9303 continue;
9304
9305 var node = opTokens;
9306 for (var i = 0; i < op.length; i++) {
9307 var ch = op[i];
9308 if (!(ch in node))
9309 node[ch] = {};
9310 node = node[ch];
9311 node.op = op;
9312 }
9313 }
9314
9315 /*
9316 * Since JavaScript provides no convenient way to determine if a
9317 * character is in a particular Unicode category, we use
9318 * metacircularity to accomplish this (oh yeaaaah!)
9319 */
9320 function isValidIdentifierChar(ch, first) {
9321 // check directly for ASCII
9322 if (ch <= "\u007F") {
9323 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch === '$' || ch === '_' ||
9324 (!first && (ch >= '0' && ch <= '9'))) {
9325 return true;
9326 }
9327 return false;
9328 }
9329
9330 // create an object to test this in
9331 var x = {};
9332 x["x"+ch] = true;
9333 x[ch] = true;
9334
9335 // then use eval to determine if it's a valid character
9336 var valid = false;
9337 try {
9338 valid = (Function("x", "return (x." + (first?"":"x") + ch + ");")(x) === true);
9339 } catch (ex) {}
9340
9341 return valid;
9342 }
9343
9344 function isIdentifier(str) {
9345 if (typeof str !== "string")
9346 return false;
9347
9348 if (str.length === 0)
9349 return false;
9350
9351 if (!isValidIdentifierChar(str[0], true))
9352 return false;
9353
9354 for (var i = 1; i < str.length; i++) {
9355 if (!isValidIdentifierChar(str[i], false))
9356 return false;
9357 }
9358
9359 return true;
9360 }
9361
9362 /*
9363 * Tokenizer :: (source, filename, line number, boolean) -> Tokenizer
9364 */
9365 function Tokenizer(s, f, l, allowHTMLComments) {
9366 this.cursor = 0;
9367 this.source = String(s);
9368 this.tokens = [];
9369 this.tokenIndex = 0;
9370 this.lookahead = 0;
9371 this.scanNewlines = false;
9372 this.filename = f || "";
9373 this.lineno = l || 1;
9374 this.allowHTMLComments = allowHTMLComments;
9375 this.blockComments = null;
9376 }
9377
9378 Tokenizer.prototype = {
9379 get done() {
9380 // We need to set scanOperand to true here because the first thing
9381 // might be a regexp.
9382 return this.peek(true) === END;
9383 },
9384
9385 get token() {
9386 return this.tokens[this.tokenIndex];
9387 },
9388
9389 match: function (tt, scanOperand, keywordIsName) {
9390 return this.get(scanOperand, keywordIsName) === tt || this.unget();
9391 },
9392
9393 mustMatch: function (tt, keywordIsName) {
9394 if (!this.match(tt, false, keywordIsName)) {
9395 throw this.newSyntaxError("Missing " +
9396 definitions.tokens[tt].toLowerCase());
9397 }
9398 return this.token;
9399 },
9400
9401 peek: function (scanOperand) {
9402 var tt, next;
9403 if (this.lookahead) {
9404 next = this.tokens[(this.tokenIndex + this.lookahead) & 3];
9405 tt = (this.scanNewlines && next.lineno !== this.lineno)
9406 ? NEWLINE
9407 : next.type;
9408 } else {
9409 tt = this.get(scanOperand);
9410 this.unget();
9411 }
9412 return tt;
9413 },
9414
9415 peekOnSameLine: function (scanOperand) {
9416 this.scanNewlines = true;
9417 var tt = this.peek(scanOperand);
9418 this.scanNewlines = false;
9419 return tt;
9420 },
9421
9422 lastBlockComment: function() {
9423 var length = this.blockComments.length;
9424 return length ? this.blockComments[length - 1] : null;
9425 },
9426
9427 // Eat comments and whitespace.
9428 skip: function () {
9429 var input = this.source;
9430 this.blockComments = [];
9431 for (;;) {
9432 var ch = input[this.cursor++];
9433 var next = input[this.cursor];
9434 // handle \r, \r\n and (always preferable) \n
9435 if (ch === '\r') {
9436 // if the next character is \n, we don't care about this at all
9437 if (next === '\n') continue;
9438
9439 // otherwise, we want to consider this as a newline
9440 ch = '\n';
9441 }
9442
9443 if (ch === '\n' && !this.scanNewlines) {
9444 this.lineno++;
9445 } else if (ch === '/' && next === '*') {
9446 var commentStart = ++this.cursor;
9447 for (;;) {
9448 ch = input[this.cursor++];
9449 if (ch === undefined)
9450 throw this.newSyntaxError("Unterminated comment");
9451
9452 if (ch === '*') {
9453 next = input[this.cursor];
9454 if (next === '/') {
9455 var commentEnd = this.cursor - 1;
9456 this.cursor++;
9457 break;
9458 }
9459 } else if (ch === '\n') {
9460 this.lineno++;
9461 }
9462 }
9463 this.blockComments.push(input.substring(commentStart, commentEnd));
9464 } else if ((ch === '/' && next === '/') ||
9465 (this.allowHTMLComments && ch === '<' && next === '!' &&
9466 input[this.cursor + 1] === '-' && input[this.cursor + 2] === '-' &&
9467 (this.cursor += 2))) {
9468 this.cursor++;
9469 for (;;) {
9470 ch = input[this.cursor++];
9471 next = input[this.cursor];
9472 if (ch === undefined)
9473 return;
9474
9475 if (ch === '\r') {
9476 // check for \r\n
9477 if (next !== '\n') ch = '\n';
9478 }
9479
9480 if (ch === '\n') {
9481 if (this.scanNewlines) {
9482 this.cursor--;
9483 } else {
9484 this.lineno++;
9485 }
9486 break;
9487 }
9488 }
9489 } else if (!(ch in definitions.whitespace)) {
9490 this.cursor--;
9491 return;
9492 }
9493 }
9494 },
9495
9496 // Lex the exponential part of a number, if present. Return true iff an
9497 // exponential part was found.
9498 lexExponent: function() {
9499 var input = this.source;
9500 var next = input[this.cursor];
9501 if (next === 'e' || next === 'E') {
9502 this.cursor++;
9503 ch = input[this.cursor++];
9504 if (ch === '+' || ch === '-')
9505 ch = input[this.cursor++];
9506
9507 if (ch < '0' || ch > '9')
9508 throw this.newSyntaxError("Missing exponent");
9509
9510 do {
9511 ch = input[this.cursor++];
9512 } while (ch >= '0' && ch <= '9');
9513 this.cursor--;
9514
9515 return true;
9516 }
9517
9518 return false;
9519 },
9520
9521 lexZeroNumber: function (ch) {
9522 var token = this.token, input = this.source;
9523 token.type = NUMBER;
9524
9525 ch = input[this.cursor++];
9526 if (ch === '.') {
9527 do {
9528 ch = input[this.cursor++];
9529 } while (ch >= '0' && ch <= '9');
9530 this.cursor--;
9531
9532 this.lexExponent();
9533 token.value = parseFloat(
9534 input.substring(token.start, this.cursor));
9535 } else if (ch === 'x' || ch === 'X') {
9536 do {
9537 ch = input[this.cursor++];
9538 } while ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') ||
9539 (ch >= 'A' && ch <= 'F'));
9540 this.cursor--;
9541
9542 token.value = parseInt(input.substring(token.start, this.cursor));
9543 } else if (ch >= '0' && ch <= '7') {
9544 do {
9545 ch = input[this.cursor++];
9546 } while (ch >= '0' && ch <= '7');
9547 this.cursor--;
9548
9549 token.value = parseInt(input.substring(token.start, this.cursor));
9550 } else {
9551 this.cursor--;
9552 this.lexExponent(); // 0E1, &c.
9553 token.value = 0;
9554 }
9555 },
9556
9557 lexNumber: function (ch) {
9558 var token = this.token, input = this.source;
9559 token.type = NUMBER;
9560
9561 var floating = false;
9562 do {
9563 ch = input[this.cursor++];
9564 if (ch === '.' && !floating) {
9565 floating = true;
9566 ch = input[this.cursor++];
9567 }
9568 } while (ch >= '0' && ch <= '9');
9569
9570 this.cursor--;
9571
9572 var exponent = this.lexExponent();
9573 floating = floating || exponent;
9574
9575 var str = input.substring(token.start, this.cursor);
9576 token.value = floating ? parseFloat(str) : parseInt(str);
9577 },
9578
9579 lexDot: function (ch) {
9580 var token = this.token, input = this.source;
9581 var next = input[this.cursor];
9582 if (next >= '0' && next <= '9') {
9583 do {
9584 ch = input[this.cursor++];
9585 } while (ch >= '0' && ch <= '9');
9586 this.cursor--;
9587
9588 this.lexExponent();
9589
9590 token.type = NUMBER;
9591 token.value = parseFloat(
9592 input.substring(token.start, this.cursor));
9593 } else {
9594 token.type = DOT;
9595 token.assignOp = null;
9596 token.value = '.';
9597 }
9598 },
9599
9600 lexString: function (ch) {
9601 var token = this.token, input = this.source;
9602 token.type = STRING;
9603
9604 var hasEscapes = false;
9605 var delim = ch;
9606 if (input.length <= this.cursor)
9607 throw this.newSyntaxError("Unterminated string literal");
9608 while ((ch = input[this.cursor++]) !== delim) {
9609 if (ch == '\n' || ch == '\r')
9610 throw this.newSyntaxError("Unterminated string literal");
9611 if (this.cursor == input.length)
9612 throw this.newSyntaxError("Unterminated string literal");
9613 if (ch === '\\') {
9614 hasEscapes = true;
9615 if (++this.cursor == input.length)
9616 throw this.newSyntaxError("Unterminated string literal");
9617 }
9618 }
9619
9620 token.value = hasEscapes
9621 ? eval(input.substring(token.start, this.cursor))
9622 : input.substring(token.start + 1, this.cursor - 1);
9623 },
9624
9625 lexRegExp: function (ch) {
9626 var token = this.token, input = this.source;
9627 token.type = REGEXP;
9628
9629 do {
9630 ch = input[this.cursor++];
9631 if (ch === '\\') {
9632 this.cursor++;
9633 } else if (ch === '[') {
9634 do {
9635 if (ch === undefined)
9636 throw this.newSyntaxError("Unterminated character class");
9637
9638 if (ch === '\\')
9639 this.cursor++;
9640
9641 ch = input[this.cursor++];
9642 } while (ch !== ']');
9643 } else if (ch === undefined) {
9644 throw this.newSyntaxError("Unterminated regex");
9645 }
9646 } while (ch !== '/');
9647
9648 do {
9649 ch = input[this.cursor++];
9650 } while (ch >= 'a' && ch <= 'z');
9651
9652 this.cursor--;
9653
9654 token.value = eval(input.substring(token.start, this.cursor));
9655 },
9656
9657 lexOp: function (ch) {
9658 var token = this.token, input = this.source;
9659
9660 // A bit ugly, but it seems wasteful to write a trie lookup routine
9661 // for only 3 characters...
9662 var node = opTokens[ch];
9663 var next = input[this.cursor];
9664 if (next in node) {
9665 node = node[next];
9666 this.cursor++;
9667 next = input[this.cursor];
9668 if (next in node) {
9669 node = node[next];
9670 this.cursor++;
9671 next = input[this.cursor];
9672 }
9673 }
9674
9675 var op = node.op;
9676 if (definitions.assignOps[op] && input[this.cursor] === '=') {
9677 this.cursor++;
9678 token.type = ASSIGN;
9679 token.assignOp = definitions.tokenIds[definitions.opTypeNames[op]];
9680 op += '=';
9681 } else {
9682 token.type = definitions.tokenIds[definitions.opTypeNames[op]];
9683 token.assignOp = null;
9684 }
9685
9686 token.value = op;
9687 },
9688
9689 // FIXME: Unicode escape sequences
9690 lexIdent: function (ch, keywordIsName) {
9691 var token = this.token;
9692 var id = ch;
9693
9694 while ((ch = this.getValidIdentifierChar(false)) !== null) {
9695 id += ch;
9696 }
9697
9698 token.type = IDENTIFIER;
9699 token.value = id;
9700
9701 if (keywordIsName)
9702 return;
9703
9704 var kw;
9705
9706 if (this.parser.mozillaMode) {
9707 kw = definitions.mozillaKeywords[id];
9708 if (kw) {
9709 token.type = kw;
9710 return;
9711 }
9712 }
9713
9714 if (this.parser.x.strictMode) {
9715 kw = definitions.strictKeywords[id];
9716 if (kw) {
9717 token.type = kw;
9718 return;
9719 }
9720 }
9721
9722 kw = definitions.keywords[id];
9723 if (kw)
9724 token.type = kw;
9725 },
9726
9727 /*
9728 * Tokenizer.get :: ([boolean[, boolean]]) -> token type
9729 *
9730 * Consume input *only* if there is no lookahead.
9731 * Dispatch to the appropriate lexing function depending on the input.
9732 */
9733 get: function (scanOperand, keywordIsName) {
9734 var token;
9735 while (this.lookahead) {
9736 --this.lookahead;
9737 this.tokenIndex = (this.tokenIndex + 1) & 3;
9738 token = this.tokens[this.tokenIndex];
9739 if (token.type !== NEWLINE || this.scanNewlines)
9740 return token.type;
9741 }
9742
9743 this.skip();
9744
9745 this.tokenIndex = (this.tokenIndex + 1) & 3;
9746 token = this.tokens[this.tokenIndex];
9747 if (!token)
9748 this.tokens[this.tokenIndex] = token = {};
9749
9750 var input = this.source;
9751 if (this.cursor >= input.length)
9752 return token.type = END;
9753
9754 token.start = this.cursor;
9755 token.lineno = this.lineno;
9756
9757 var ich = this.getValidIdentifierChar(true);
9758 var ch = (ich === null) ? input[this.cursor++] : null;
9759 if (ich !== null) {
9760 this.lexIdent(ich, keywordIsName);
9761 } else if (scanOperand && ch === '/') {
9762 this.lexRegExp(ch);
9763 } else if (ch in opTokens) {
9764 this.lexOp(ch);
9765 } else if (ch === '.') {
9766 this.lexDot(ch);
9767 } else if (ch >= '1' && ch <= '9') {
9768 this.lexNumber(ch);
9769 } else if (ch === '0') {
9770 this.lexZeroNumber(ch);
9771 } else if (ch === '"' || ch === "'") {
9772 this.lexString(ch);
9773 } else if (this.scanNewlines && (ch === '\n' || ch === '\r')) {
9774 // if this was a \r, look for \r\n
9775 if (ch === '\r' && input[this.cursor] === '\n') this.cursor++;
9776 token.type = NEWLINE;
9777 token.value = '\n';
9778 this.lineno++;
9779 } else {
9780 throw this.newSyntaxError("Illegal token");
9781 }
9782
9783 token.end = this.cursor;
9784 return token.type;
9785 },
9786
9787 /*
9788 * Tokenizer.unget :: void -> undefined
9789 *
9790 * Match depends on unget returning undefined.
9791 */
9792 unget: function () {
9793 if (++this.lookahead === 4) throw "PANIC: too much lookahead!";
9794 this.tokenIndex = (this.tokenIndex - 1) & 3;
9795 },
9796
9797 newSyntaxError: function (m) {
9798 m = (this.filename ? this.filename + ":" : "") + this.lineno + ": " + m;
9799 var e = new SyntaxError(m, this.filename, this.lineno);
9800 e.source = this.source;
9801 e.cursor = this.lookahead
9802 ? this.tokens[(this.tokenIndex + this.lookahead) & 3].start
9803 : this.cursor;
9804 return e;
9805 },
9806
9807
9808 /* Gets a single valid identifier char from the input stream, or null
9809 * if there is none.
9810 */
9811 getValidIdentifierChar: function(first) {
9812 var input = this.source;
9813 if (this.cursor >= input.length) return null;
9814 var ch = input[this.cursor];
9815
9816 // first check for \u escapes
9817 if (ch === '\\' && input[this.cursor+1] === 'u') {
9818 // get the character value
9819 try {
9820 ch = String.fromCharCode(parseInt(
9821 input.substring(this.cursor + 2, this.cursor + 6),
9822 16));
9823 } catch (ex) {
9824 return null;
9825 }
9826 this.cursor += 5;
9827 }
9828
9829 var valid = isValidIdentifierChar(ch, first);
9830 if (valid) this.cursor++;
9831 return (valid ? ch : null);
9832 },
9833 };
9834
9835
9836 exports.isIdentifier = isIdentifier;
9837 exports.Tokenizer = Tokenizer;
9838
9839 });/* vim: set sw=4 ts=4 et tw=78: */
9840 /* ***** BEGIN LICENSE BLOCK *****
9841 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
9842 *
9843 * The contents of this file are subject to the Mozilla Public License Version
9844 * 1.1 (the "License"); you may not use this file except in compliance with
9845 * the License. You may obtain a copy of the License at
9846 * http://www.mozilla.org/MPL/
9847 *
9848 * Software distributed under the License is distributed on an "AS IS" basis,
9849 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
9850 * for the specific language governing rights and limitations under the
9851 * License.
9852 *
9853 * The Original Code is the Narcissus JavaScript engine.
9854 *
9855 * The Initial Developer of the Original Code is
9856 * Brendan Eich <brendan@mozilla.org>.
9857 * Portions created by the Initial Developer are Copyright (C) 2004
9858 * the Initial Developer. All Rights Reserved.
9859 *
9860 * Contributor(s):
9861 * Tom Austin <taustin@ucsc.edu>
9862 * Brendan Eich <brendan@mozilla.org>
9863 * Shu-Yu Guo <shu@rfrn.org>
9864 * Dave Herman <dherman@mozilla.com>
9865 * Dimitris Vardoulakis <dimvar@ccs.neu.edu>
9866 * Patrick Walton <pcwalton@mozilla.com>
9867 *
9868 * Alternatively, the contents of this file may be used under the terms of
9869 * either the GNU General Public License Version 2 or later (the "GPL"), or
9870 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
9871 * in which case the provisions of the GPL or the LGPL are applicable instead
9872 * of those above. If you wish to allow use of your version of this file only
9873 * under the terms of either the GPL or the LGPL, and not to allow others to
9874 * use your version of this file under the terms of the MPL, indicate your
9875 * decision by deleting the provisions above and replace them with the notice
9876 * and other provisions required by the GPL or the LGPL. If you do not delete
9877 * the provisions above, a recipient may use your version of this file under
9878 * the terms of any one of the MPL, the GPL or the LGPL.
9879 *
9880 * ***** END LICENSE BLOCK ***** */
9881
9882 /*
9883 * Narcissus - JS implemented in JS.
9884 *
9885 * Well-known constants and lookup tables. Many consts are generated from the
9886 * tokens table via eval to minimize redundancy, so consumers must be compiled
9887 * separately to take advantage of the simple switch-case constant propagation
9888 * done by SpiderMonkey.
9889 */
9890
9891 define('ace/narcissus/definitions', ['require', 'exports', 'module' ], function(require, exports, module) {
9892
9893 var tokens = [
9894 // End of source.
9895 "END",
9896
9897 // Operators and punctuators. Some pair-wise order matters, e.g. (+, -)
9898 // and (UNARY_PLUS, UNARY_MINUS).
9899 "\n", ";",
9900 ",",
9901 "=",
9902 "?", ":", "CONDITIONAL",
9903 "||",
9904 "&&",
9905 "|",
9906 "^",
9907 "&",
9908 "==", "!=", "===", "!==",
9909 "<", "<=", ">=", ">",
9910 "<<", ">>", ">>>",
9911 "+", "-",
9912 "*", "/", "%",
9913 "!", "~", "UNARY_PLUS", "UNARY_MINUS",
9914 "++", "--",
9915 ".",
9916 "[", "]",
9917 "{", "}",
9918 "(", ")",
9919
9920 // Nonterminal tree node type codes.
9921 "SCRIPT", "BLOCK", "LABEL", "FOR_IN", "CALL", "NEW_WITH_ARGS", "INDEX",
9922 "ARRAY_INIT", "OBJECT_INIT", "PROPERTY_INIT", "GETTER", "SETTER",
9923 "GROUP", "LIST", "LET_BLOCK", "ARRAY_COMP", "GENERATOR", "COMP_TAIL",
9924
9925 // Contextual keywords.
9926 "IMPLEMENTS", "INTERFACE", "LET", "MODULE", "PACKAGE", "PRIVATE",
9927 "PROTECTED", "PUBLIC", "STATIC", "USE", "YIELD",
9928
9929 // Terminals.
9930 "IDENTIFIER", "NUMBER", "STRING", "REGEXP",
9931
9932 // Keywords.
9933 "break",
9934 "case", "catch", "const", "continue",
9935 "debugger", "default", "delete", "do",
9936 "else", "export",
9937 "false", "finally", "for", "function",
9938 "if", "import", "in", "instanceof",
9939 "new", "null",
9940 "return",
9941 "switch",
9942 "this", "throw", "true", "try", "typeof",
9943 "var", "void",
9944 "while", "with",
9945 ];
9946
9947 var strictKeywords = {
9948 __proto__: null,
9949 "implements": true,
9950 "interface": true,
9951 "let": true,
9952 "module": true,
9953 "package": true,
9954 "private": true,
9955 "protected": true,
9956 "public": true,
9957 "static": true,
9958 "use": true,
9959 "yield": true
9960 };
9961
9962 var statementStartTokens = [
9963 "break",
9964 "const", "continue",
9965 "debugger", "do",
9966 "for",
9967 "if",
9968 "let",
9969 "return",
9970 "switch",
9971 "throw", "try",
9972 "var",
9973 "yield",
9974 "while", "with",
9975 ];
9976
9977 // Whitespace characters (see ECMA-262 7.2)
9978 var whitespaceChars = [
9979 // normal whitespace:
9980 "\u0009", "\u000B", "\u000C", "\u0020", "\u00A0", "\uFEFF",
9981
9982 // high-Unicode whitespace:
9983 "\u1680", "\u180E",
9984 "\u2000", "\u2001", "\u2002", "\u2003", "\u2004", "\u2005", "\u2006",
9985 "\u2007", "\u2008", "\u2009", "\u200A",
9986 "\u202F", "\u205F", "\u3000"
9987 ];
9988
9989 var whitespace = {};
9990 for (var i = 0; i < whitespaceChars.length; i++) {
9991 whitespace[whitespaceChars[i]] = true;
9992 }
9993
9994 // Operator and punctuator mapping from token to tree node type name.
9995 // NB: because the lexer doesn't backtrack, all token prefixes must themselves
9996 // be valid tokens (e.g. !== is acceptable because its prefixes are the valid
9997 // tokens != and !).
9998 var opTypeNames = {
9999 '\n': "NEWLINE",
10000 ';': "SEMICOLON",
10001 ',': "COMMA",
10002 '?': "HOOK",
10003 ':': "COLON",
10004 '||': "OR",
10005 '&&': "AND",
10006 '|': "BITWISE_OR",
10007 '^': "BITWISE_XOR",
10008 '&': "BITWISE_AND",
10009 '===': "STRICT_EQ",
10010 '==': "EQ",
10011 '=': "ASSIGN",
10012 '!==': "STRICT_NE",
10013 '!=': "NE",
10014 '<<': "LSH",
10015 '<=': "LE",
10016 '<': "LT",
10017 '>>>': "URSH",
10018 '>>': "RSH",
10019 '>=': "GE",
10020 '>': "GT",
10021 '++': "INCREMENT",
10022 '--': "DECREMENT",
10023 '+': "PLUS",
10024 '-': "MINUS",
10025 '*': "MUL",
10026 '/': "DIV",
10027 '%': "MOD",
10028 '!': "NOT",
10029 '~': "BITWISE_NOT",
10030 '.': "DOT",
10031 '[': "LEFT_BRACKET",
10032 ']': "RIGHT_BRACKET",
10033 '{': "LEFT_CURLY",
10034 '}': "RIGHT_CURLY",
10035 '(': "LEFT_PAREN",
10036 ')': "RIGHT_PAREN"
10037 };
10038
10039 // Hash of keyword identifier to tokens index. NB: we must null __proto__ to
10040 // avoid toString, etc. namespace pollution.
10041 var keywords = {__proto__: null};
10042 var mozillaKeywords = {__proto__: null};
10043
10044 // Define const END, etc., based on the token names. Also map name to index.
10045 var tokenIds = {};
10046
10047 var hostSupportsEvalConst = (function() {
10048 try {
10049 return eval("(function(s) { eval(s); return x })('const x = true;')");
10050 } catch (e) {
10051 return false;
10052 }
10053 })();
10054
10055 // Building up a string to be eval'd in different contexts.
10056 var consts = hostSupportsEvalConst ? "const " : "var ";
10057 for (var i = 0, j = tokens.length; i < j; i++) {
10058 if (i > 0)
10059 consts += ", ";
10060 var t = tokens[i];
10061 var name;
10062 if (/^[a-z]/.test(t)) {
10063 name = t.toUpperCase();
10064 if (name === "LET" || name === "YIELD")
10065 mozillaKeywords[name] = i;
10066 if (strictKeywords[name])
10067 strictKeywords[name] = i;
10068 keywords[t] = i;
10069 } else {
10070 name = (/^\W/.test(t) ? opTypeNames[t] : t);
10071 }
10072 consts += name + " = " + i;
10073 tokenIds[name] = i;
10074 tokens[t] = i;
10075 }
10076 consts += ";";
10077
10078 var isStatementStartCode = {__proto__: null};
10079 for (i = 0, j = statementStartTokens.length; i < j; i++)
10080 isStatementStartCode[keywords[statementStartTokens[i]]] = true;
10081
10082 // Map assignment operators to their indexes in the tokens array.
10083 var assignOps = ['|', '^', '&', '<<', '>>', '>>>', '+', '-', '*', '/', '%'];
10084
10085 for (i = 0, j = assignOps.length; i < j; i++) {
10086 t = assignOps[i];
10087 assignOps[t] = tokens[t];
10088 }
10089
10090 function defineGetter(obj, prop, fn, dontDelete, dontEnum) {
10091 Object.defineProperty(obj, prop,
10092 { get: fn, configurable: !dontDelete, enumerable: !dontEnum });
10093 }
10094
10095 function defineGetterSetter(obj, prop, getter, setter, dontDelete, dontEnum) {
10096 Object.defineProperty(obj, prop, {
10097 get: getter,
10098 set: setter,
10099 configurable: !dontDelete,
10100 enumerable: !dontEnum
10101 });
10102 }
10103
10104 function defineMemoGetter(obj, prop, fn, dontDelete, dontEnum) {
10105 Object.defineProperty(obj, prop, {
10106 get: function() {
10107 var val = fn();
10108 defineProperty(obj, prop, val, dontDelete, true, dontEnum);
10109 return val;
10110 },
10111 configurable: true,
10112 enumerable: !dontEnum
10113 });
10114 }
10115
10116 function defineProperty(obj, prop, val, dontDelete, readOnly, dontEnum) {
10117 Object.defineProperty(obj, prop,
10118 { value: val, writable: !readOnly, configurable: !dontDelete,
10119 enumerable: !dontEnum });
10120 }
10121
10122 // Returns true if fn is a native function. (Note: SpiderMonkey specific.)
10123 function isNativeCode(fn) {
10124 // Relies on the toString method to identify native code.
10125 return ((typeof fn) === "function") && fn.toString().match(/\[native code\]/);
10126 }
10127
10128 var Fpapply = Function.prototype.apply;
10129
10130 function apply(f, o, a) {
10131 return Fpapply.call(f, [o].concat(a));
10132 }
10133
10134 var applyNew;
10135
10136 // ES5's bind is a simpler way to implement applyNew
10137 if (Function.prototype.bind) {
10138 applyNew = function applyNew(f, a) {
10139 return new (f.bind.apply(f, [,].concat(Array.prototype.slice.call(a))))();
10140 };
10141 } else {
10142 applyNew = function applyNew(f, a) {
10143 switch (a.length) {
10144 case 0:
10145 return new f();
10146 case 1:
10147 return new f(a[0]);
10148 case 2:
10149 return new f(a[0], a[1]);
10150 case 3:
10151 return new f(a[0], a[1], a[2]);
10152 default:
10153 var argStr = "a[0]";
10154 for (var i = 1, n = a.length; i < n; i++)
10155 argStr += ",a[" + i + "]";
10156 return eval("new f(" + argStr + ")");
10157 }
10158 };
10159 }
10160
10161 function getPropertyDescriptor(obj, name) {
10162 while (obj) {
10163 if (({}).hasOwnProperty.call(obj, name))
10164 return Object.getOwnPropertyDescriptor(obj, name);
10165 obj = Object.getPrototypeOf(obj);
10166 }
10167 }
10168
10169 function getPropertyNames(obj) {
10170 var table = Object.create(null, {});
10171 while (obj) {
10172 var names = Object.getOwnPropertyNames(obj);
10173 for (var i = 0, n = names.length; i < n; i++)
10174 table[names[i]] = true;
10175 obj = Object.getPrototypeOf(obj);
10176 }
10177 return Object.keys(table);
10178 }
10179
10180 function getOwnProperties(obj) {
10181 var map = {};
10182 for (var name in Object.getOwnPropertyNames(obj))
10183 map[name] = Object.getOwnPropertyDescriptor(obj, name);
10184 return map;
10185 }
10186
10187 function blacklistHandler(target, blacklist) {
10188 var mask = Object.create(null, {});
10189 var redirect = Dict.create(blacklist).mapObject(function(name) { return mask; });
10190 return mixinHandler(redirect, target);
10191 }
10192
10193 function whitelistHandler(target, whitelist) {
10194 var catchall = Object.create(null, {});
10195 var redirect = Dict.create(whitelist).mapObject(function(name) { return target; });
10196 return mixinHandler(redirect, catchall);
10197 }
10198
10199 /*
10200 * Mixin proxies break the single-inheritance model of prototypes, so
10201 * the handler treats all properties as own-properties:
10202 *
10203 * X
10204 * |
10205 * +------------+------------+
10206 * | O |
10207 * | | |
10208 * | O O O |
10209 * | | | | |
10210 * | O O O O |
10211 * | | | | | |
10212 * | O O O O O |
10213 * | | | | | | |
10214 * +-(*)--(w)--(x)--(y)--(z)-+
10215 */
10216
10217 function mixinHandler(redirect, catchall) {
10218 function targetFor(name) {
10219 return hasOwn(redirect, name) ? redirect[name] : catchall;
10220 }
10221
10222 function getMuxPropertyDescriptor(name) {
10223 var desc = getPropertyDescriptor(targetFor(name), name);
10224 if (desc)
10225 desc.configurable = true;
10226 return desc;
10227 }
10228
10229 function getMuxPropertyNames() {
10230 var names1 = Object.getOwnPropertyNames(redirect).filter(function(name) {
10231 return name in redirect[name];
10232 });
10233 var names2 = getPropertyNames(catchall).filter(function(name) {
10234 return !hasOwn(redirect, name);
10235 });
10236 return names1.concat(names2);
10237 }
10238
10239 function enumerateMux() {
10240 var result = Object.getOwnPropertyNames(redirect).filter(function(name) {
10241 return name in redirect[name];
10242 });
10243 for (name in catchall) {
10244 if (!hasOwn(redirect, name))
10245 result.push(name);
10246 };
10247 return result;
10248 }
10249
10250 function hasMux(name) {
10251 return name in targetFor(name);
10252 }
10253
10254 return {
10255 getOwnPropertyDescriptor: getMuxPropertyDescriptor,
10256 getPropertyDescriptor: getMuxPropertyDescriptor,
10257 getOwnPropertyNames: getMuxPropertyNames,
10258 defineProperty: function(name, desc) {
10259 Object.defineProperty(targetFor(name), name, desc);
10260 },
10261 "delete": function(name) {
10262 var target = targetFor(name);
10263 return delete target[name];
10264 },
10265 // FIXME: ha ha ha
10266 fix: function() { },
10267 has: hasMux,
10268 hasOwn: hasMux,
10269 get: function(receiver, name) {
10270 var target = targetFor(name);
10271 return target[name];
10272 },
10273 set: function(receiver, name, val) {
10274 var target = targetFor(name);
10275 target[name] = val;
10276 return true;
10277 },
10278 enumerate: enumerateMux,
10279 keys: enumerateMux
10280 };
10281 }
10282
10283 function makePassthruHandler(obj) {
10284 // Handler copied from
10285 // http://wiki.ecmascript.org/doku.php?id=harmony:proxies&s=proxy%20object#examplea_no-op_forwarding_proxy
10286 return {
10287 getOwnPropertyDescriptor: function(name) {
10288 var desc = Object.getOwnPropertyDescriptor(obj, name);
10289
10290 // a trapping proxy's properties must always be configurable
10291 desc.configurable = true;
10292 return desc;
10293 },
10294 getPropertyDescriptor: function(name) {
10295 var desc = getPropertyDescriptor(obj, name);
10296
10297 // a trapping proxy's properties must always be configurable
10298 desc.configurable = true;
10299 return desc;
10300 },
10301 getOwnPropertyNames: function() {
10302 return Object.getOwnPropertyNames(obj);
10303 },
10304 defineProperty: function(name, desc) {
10305 Object.defineProperty(obj, name, desc);
10306 },
10307 "delete": function(name) { return delete obj[name]; },
10308 fix: function() {
10309 if (Object.isFrozen(obj)) {
10310 return getOwnProperties(obj);
10311 }
10312
10313 // As long as obj is not frozen, the proxy won't allow itself to be fixed.
10314 return undefined; // will cause a TypeError to be thrown
10315 },
10316
10317 has: function(name) { return name in obj; },
10318 hasOwn: function(name) { return ({}).hasOwnProperty.call(obj, name); },
10319 get: function(receiver, name) { return obj[name]; },
10320
10321 // bad behavior when set fails in non-strict mode
10322 set: function(receiver, name, val) { obj[name] = val; return true; },
10323 enumerate: function() {
10324 var result = [];
10325 for (name in obj) { result.push(name); };
10326 return result;
10327 },
10328 keys: function() { return Object.keys(obj); }
10329 };
10330 }
10331
10332 var hasOwnProperty = ({}).hasOwnProperty;
10333
10334 function hasOwn(obj, name) {
10335 return hasOwnProperty.call(obj, name);
10336 }
10337
10338 function Dict(table, size) {
10339 this.table = table || Object.create(null, {});
10340 this.size = size || 0;
10341 }
10342
10343 Dict.create = function(table) {
10344 var init = Object.create(null, {});
10345 var size = 0;
10346 var names = Object.getOwnPropertyNames(table);
10347 for (var i = 0, n = names.length; i < n; i++) {
10348 var name = names[i];
10349 init[name] = table[name];
10350 size++;
10351 }
10352 return new Dict(init, size);
10353 };
10354
10355 Dict.prototype = {
10356 has: function(x) { return hasOwnProperty.call(this.table, x); },
10357 set: function(x, v) {
10358 if (!hasOwnProperty.call(this.table, x))
10359 this.size++;
10360 this.table[x] = v;
10361 },
10362 get: function(x) { return this.table[x]; },
10363 getDef: function(x, thunk) {
10364 if (!hasOwnProperty.call(this.table, x)) {
10365 this.size++;
10366 this.table[x] = thunk();
10367 }
10368 return this.table[x];
10369 },
10370 forEach: function(f) {
10371 var table = this.table;
10372 for (var key in table)
10373 f.call(this, key, table[key]);
10374 },
10375 map: function(f) {
10376 var table1 = this.table;
10377 var table2 = Object.create(null, {});
10378 this.forEach(function(key, val) {
10379 table2[key] = f.call(this, val, key);
10380 });
10381 return new Dict(table2, this.size);
10382 },
10383 mapObject: function(f) {
10384 var table1 = this.table;
10385 var table2 = Object.create(null, {});
10386 this.forEach(function(key, val) {
10387 table2[key] = f.call(this, val, key);
10388 });
10389 return table2;
10390 },
10391 toObject: function() {
10392 return this.mapObject(function(val) { return val; });
10393 },
10394 choose: function() {
10395 return Object.getOwnPropertyNames(this.table)[0];
10396 },
10397 remove: function(x) {
10398 if (hasOwnProperty.call(this.table, x)) {
10399 this.size--;
10400 delete this.table[x];
10401 }
10402 },
10403 copy: function() {
10404 var table = Object.create(null, {});
10405 for (var key in this.table)
10406 table[key] = this.table[key];
10407 return new Dict(table, this.size);
10408 },
10409 keys: function() {
10410 return Object.keys(this.table);
10411 },
10412 toString: function() { return "[object Dict]" }
10413 };
10414
10415 var _WeakMap = typeof WeakMap === "function" ? WeakMap : (function() {
10416 // shim for ES6 WeakMap with poor asymptotics
10417 function WeakMap(array) {
10418 this.array = array || [];
10419 }
10420
10421 function searchMap(map, key, found, notFound) {
10422 var a = map.array;
10423 for (var i = 0, n = a.length; i < n; i++) {
10424 var pair = a[i];
10425 if (pair.key === key)
10426 return found(pair, i);
10427 }
10428 return notFound();
10429 }
10430
10431 WeakMap.prototype = {
10432 has: function(x) {
10433 return searchMap(this, x, function() { return true }, function() { return false });
10434 },
10435 set: function(x, v) {
10436 var a = this.array;
10437 searchMap(this, x,
10438 function(pair) { pair.value = v },
10439 function() { a.push({ key: x, value: v }) });
10440 },
10441 get: function(x) {
10442 return searchMap(this, x,
10443 function(pair) { return pair.value },
10444 function() { return null });
10445 },
10446 "delete": function(x) {
10447 var a = this.array;
10448 searchMap(this, x,
10449 function(pair, i) { a.splice(i, 1) },
10450 function() { });
10451 },
10452 toString: function() { return "[object WeakMap]" }
10453 };
10454
10455 return WeakMap;
10456 })();
10457
10458 // non-destructive stack
10459 function Stack(elts) {
10460 this.elts = elts || null;
10461 }
10462
10463 Stack.prototype = {
10464 push: function(x) {
10465 return new Stack({ top: x, rest: this.elts });
10466 },
10467 top: function() {
10468 if (!this.elts)
10469 throw new Error("empty stack");
10470 return this.elts.top;
10471 },
10472 isEmpty: function() {
10473 return this.top === null;
10474 },
10475 find: function(test) {
10476 for (var elts = this.elts; elts; elts = elts.rest) {
10477 if (test(elts.top))
10478 return elts.top;
10479 }
10480 return null;
10481 },
10482 has: function(x) {
10483 return Boolean(this.find(function(elt) { return elt === x }));
10484 },
10485 forEach: function(f) {
10486 for (var elts = this.elts; elts; elts = elts.rest) {
10487 f(elts.top);
10488 }
10489 }
10490 };
10491
10492 if (!Array.prototype.copy) {
10493 defineProperty(Array.prototype, "copy",
10494 function() {
10495 var result = [];
10496 for (var i = 0, n = this.length; i < n; i++)
10497 result[i] = this[i];
10498 return result;
10499 }, false, false, true);
10500 }
10501
10502 if (!Array.prototype.top) {
10503 defineProperty(Array.prototype, "top",
10504 function() {
10505 return this.length && this[this.length-1];
10506 }, false, false, true);
10507 }
10508
10509 exports.tokens = tokens;
10510 exports.whitespace = whitespace;
10511 exports.opTypeNames = opTypeNames;
10512 exports.keywords = keywords;
10513 exports.mozillaKeywords = mozillaKeywords;
10514 exports.strictKeywords = strictKeywords;
10515 exports.isStatementStartCode = isStatementStartCode;
10516 exports.tokenIds = tokenIds;
10517 exports.consts = consts;
10518 exports.assignOps = assignOps;
10519 exports.defineGetter = defineGetter;
10520 exports.defineGetterSetter = defineGetterSetter;
10521 exports.defineMemoGetter = defineMemoGetter;
10522 exports.defineProperty = defineProperty;
10523 exports.isNativeCode = isNativeCode;
10524 exports.apply = apply;
10525 exports.applyNew = applyNew;
10526 exports.mixinHandler = mixinHandler;
10527 exports.whitelistHandler = whitelistHandler;
10528 exports.blacklistHandler = blacklistHandler;
10529 exports.makePassthruHandler = makePassthruHandler;
10530 exports.Dict = Dict;
10531 exports.WeakMap = _WeakMap;
10532 exports.Stack = Stack;
10533
10534 });/* vim: set sw=4 ts=4 et tw=78: */
10535 /* ***** BEGIN LICENSE BLOCK *****
10536 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
10537 *
10538 * The contents of this file are subject to the Mozilla Public License Version
10539 * 1.1 (the "License"); you may not use this file except in compliance with
10540 * the License. You may obtain a copy of the License at
10541 * http://www.mozilla.org/MPL/
10542 *
10543 * Software distributed under the License is distributed on an "AS IS" basis,
10544 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
10545 * for the specific language governing rights and limitations under the
10546 * License.
10547 *
10548 * The Original Code is the Narcissus JavaScript engine.
10549 *
10550 * The Initial Developer of the Original Code is
10551 * Brendan Eich <brendan@mozilla.org>.
10552 * Portions created by the Initial Developer are Copyright (C) 2004
10553 * the Initial Developer. All Rights Reserved.
10554 *
10555 * Contributor(s):
10556 * Tom Austin <taustin@ucsc.edu>
10557 * Brendan Eich <brendan@mozilla.org>
10558 * Shu-Yu Guo <shu@rfrn.org>
10559 * Dave Herman <dherman@mozilla.com>
10560 * Dimitris Vardoulakis <dimvar@ccs.neu.edu>
10561 * Patrick Walton <pcwalton@mozilla.com>
10562 *
10563 * Alternatively, the contents of this file may be used under the terms of
10564 * either the GNU General Public License Version 2 or later (the "GPL"), or
10565 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
10566 * in which case the provisions of the GPL or the LGPL are applicable instead
10567 * of those above. If you wish to allow use of your version of this file only
10568 * under the terms of either the GPL or the LGPL, and not to allow others to
10569 * use your version of this file under the terms of the MPL, indicate your
10570 * decision by deleting the provisions above and replace them with the notice
10571 * and other provisions required by the GPL or the LGPL. If you do not delete
10572 * the provisions above, a recipient may use your version of this file under
10573 * the terms of any one of the MPL, the GPL or the LGPL.
10574 *
10575 * ***** END LICENSE BLOCK ***** */
10576
10577 define('ace/narcissus/options', ['require', 'exports', 'module' ], function(require, exports, module) {
10578
10579 // Global variables to hide from the interpreter
10580 exports.hiddenHostGlobals = { Narcissus: true };
10581
10582 // Desugar SpiderMonkey language extensions?
10583 exports.desugarExtensions = false;
10584
10585 // Allow HTML comments?
10586 exports.allowHTMLComments = false;
10587
10588 // Allow non-standard Mozilla extensions?
10589 exports.mozillaMode = true;
10590
10591 // Allow experimental paren-free mode?
10592 exports.parenFreeMode = false;
10593
10594 });