jslint-rb 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4551 @@
1
+ /*!
2
+ * JSHint, by JSHint Community.
3
+ *
4
+ * Licensed under the same slightly modified MIT license that JSLint is.
5
+ * It stops evil-doers everywhere.
6
+ *
7
+ * JSHint is a derivative work of JSLint:
8
+ *
9
+ * Copyright (c) 2002 Douglas Crockford (www.JSLint.com)
10
+ *
11
+ * Permission is hereby granted, free of charge, to any person obtaining
12
+ * a copy of this software and associated documentation files (the "Software"),
13
+ * to deal in the Software without restriction, including without limitation
14
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15
+ * and/or sell copies of the Software, and to permit persons to whom
16
+ * the Software is furnished to do so, subject to the following conditions:
17
+ *
18
+ * The above copyright notice and this permission notice shall be included
19
+ * in all copies or substantial portions of the Software.
20
+ *
21
+ * The Software shall be used for Good, not Evil.
22
+ *
23
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29
+ * DEALINGS IN THE SOFTWARE.
30
+ *
31
+ * JSHint was forked from 2010-12-16 edition of JSLint.
32
+ *
33
+ */
34
+
35
+ /*
36
+ JSHINT is a global function. It takes two parameters.
37
+
38
+ var myResult = JSHINT(source, option);
39
+
40
+ The first parameter is either a string or an array of strings. If it is a
41
+ string, it will be split on '\n' or '\r'. If it is an array of strings, it
42
+ is assumed that each string represents one line. The source can be a
43
+ JavaScript text or a JSON text.
44
+
45
+ The second parameter is an optional object of options which control the
46
+ operation of JSHINT. Most of the options are booleans: They are all
47
+ optional and have a default value of false. One of the options, predef,
48
+ can be an array of names, which will be used to declare global variables,
49
+ or an object whose keys are used as global names, with a boolean value
50
+ that determines if they are assignable.
51
+
52
+ If it checks out, JSHINT returns true. Otherwise, it returns false.
53
+
54
+ If false, you can inspect JSHINT.errors to find out the problems.
55
+ JSHINT.errors is an array of objects containing these members:
56
+
57
+ {
58
+ line : The line (relative to 0) at which the lint was found
59
+ character : The character (relative to 0) at which the lint was found
60
+ reason : The problem
61
+ evidence : The text line in which the problem occurred
62
+ raw : The raw message before the details were inserted
63
+ a : The first detail
64
+ b : The second detail
65
+ c : The third detail
66
+ d : The fourth detail
67
+ }
68
+
69
+ If a fatal error was found, a null will be the last element of the
70
+ JSHINT.errors array.
71
+
72
+ You can request a Function Report, which shows all of the functions
73
+ and the parameters and vars that they use. This can be used to find
74
+ implied global variables and other problems. The report is in HTML and
75
+ can be inserted in an HTML <body>.
76
+
77
+ var myReport = JSHINT.report(limited);
78
+
79
+ If limited is true, then the report will be limited to only errors.
80
+
81
+ You can request a data structure which contains JSHint's results.
82
+
83
+ var myData = JSHINT.data();
84
+
85
+ It returns a structure with this form:
86
+
87
+ {
88
+ errors: [
89
+ {
90
+ line: NUMBER,
91
+ character: NUMBER,
92
+ reason: STRING,
93
+ evidence: STRING
94
+ }
95
+ ],
96
+ functions: [
97
+ name: STRING,
98
+ line: NUMBER,
99
+ last: NUMBER,
100
+ param: [
101
+ STRING
102
+ ],
103
+ closure: [
104
+ STRING
105
+ ],
106
+ var: [
107
+ STRING
108
+ ],
109
+ exception: [
110
+ STRING
111
+ ],
112
+ outer: [
113
+ STRING
114
+ ],
115
+ unused: [
116
+ STRING
117
+ ],
118
+ global: [
119
+ STRING
120
+ ],
121
+ label: [
122
+ STRING
123
+ ]
124
+ ],
125
+ globals: [
126
+ STRING
127
+ ],
128
+ member: {
129
+ STRING: NUMBER
130
+ },
131
+ unused: [
132
+ {
133
+ name: STRING,
134
+ line: NUMBER
135
+ }
136
+ ],
137
+ implieds: [
138
+ {
139
+ name: STRING,
140
+ line: NUMBER
141
+ }
142
+ ],
143
+ urls: [
144
+ STRING
145
+ ],
146
+ json: BOOLEAN
147
+ }
148
+
149
+ Empty arrays will not be included.
150
+
151
+ */
152
+
153
+ /*jshint
154
+ evil: true, nomen: false, onevar: false, regexp: false, strict: true, boss: true,
155
+ undef: true, maxlen: 100, indent:4
156
+ */
157
+
158
+ /*members "\b", "\t", "\n", "\f", "\r", "!=", "!==", "\"", "%", "(begin)",
159
+ "(breakage)", "(context)", "(error)", "(global)", "(identifier)", "(last)",
160
+ "(line)", "(loopage)", "(name)", "(onevar)", "(params)", "(scope)",
161
+ "(statement)", "(verb)", "*", "+", "++", "-", "--", "\/", "<", "<=", "==",
162
+ "===", ">", ">=", $, $$, $A, $F, $H, $R, $break, $continue, $w, Abstract, Ajax,
163
+ __filename, __dirname, ActiveXObject, Array, ArrayBuffer, ArrayBufferView, Audio,
164
+ Autocompleter, Assets, Boolean, Builder, Buffer, Browser, COM, CScript, Canvas,
165
+ CustomAnimation, Class, Control, Chain, Color, Cookie, Core, DataView, Date,
166
+ Debug, Draggable, Draggables, Droppables, Document, DomReady, DOMReady, DOMParser, Drag,
167
+ E, Enumerator, Enumerable, Element, Elements, Error, Effect, EvalError, Event,
168
+ Events, FadeAnimation, Field, Flash, Float32Array, Float64Array, Form,
169
+ FormField, Frame, FormData, Function, Fx, GetObject, Group, Hash, HotKey,
170
+ HTMLElement, HTMLAnchorElement, HTMLBaseElement, HTMLBlockquoteElement,
171
+ HTMLBodyElement, HTMLBRElement, HTMLButtonElement, HTMLCanvasElement, HTMLDirectoryElement,
172
+ HTMLDivElement, HTMLDListElement, HTMLFieldSetElement,
173
+ HTMLFontElement, HTMLFormElement, HTMLFrameElement, HTMLFrameSetElement,
174
+ HTMLHeadElement, HTMLHeadingElement, HTMLHRElement, HTMLHtmlElement,
175
+ HTMLIFrameElement, HTMLImageElement, HTMLInputElement, HTMLIsIndexElement,
176
+ HTMLLabelElement, HTMLLayerElement, HTMLLegendElement, HTMLLIElement,
177
+ HTMLLinkElement, HTMLMapElement, HTMLMenuElement, HTMLMetaElement,
178
+ HTMLModElement, HTMLObjectElement, HTMLOListElement, HTMLOptGroupElement,
179
+ HTMLOptionElement, HTMLParagraphElement, HTMLParamElement, HTMLPreElement,
180
+ HTMLQuoteElement, HTMLScriptElement, HTMLSelectElement, HTMLStyleElement,
181
+ HtmlTable, HTMLTableCaptionElement, HTMLTableCellElement, HTMLTableColElement,
182
+ HTMLTableElement, HTMLTableRowElement, HTMLTableSectionElement,
183
+ HTMLTextAreaElement, HTMLTitleElement, HTMLUListElement, HTMLVideoElement,
184
+ Iframe, IframeShim, Image, Int16Array, Int32Array, Int8Array,
185
+ Insertion, InputValidator, JSON, Keyboard, Locale, LN10, LN2, LOG10E, LOG2E,
186
+ MAX_VALUE, MIN_VALUE, Mask, Math, MenuItem, MessageChannel, MessageEvent, MessagePort,
187
+ MoveAnimation, MooTools, Native, NEGATIVE_INFINITY, Number, Object, ObjectRange, Option,
188
+ Options, OverText, PI, POSITIVE_INFINITY, PeriodicalExecuter, Point, Position, Prototype,
189
+ RangeError, Rectangle, ReferenceError, RegExp, ResizeAnimation, Request, RotateAnimation,
190
+ SQRT1_2, SQRT2, ScrollBar, ScriptEngine, ScriptEngineBuildVersion,
191
+ ScriptEngineMajorVersion, ScriptEngineMinorVersion, Scriptaculous, Scroller,
192
+ Slick, Slider, Selector, SharedWorker, String, Style, SyntaxError, Sortable, Sortables,
193
+ SortableObserver, Sound, Spinner, System, Swiff, Text, TextArea, Template,
194
+ Timer, Tips, Type, TypeError, Toggle, Try, "use strict", unescape, URI, URIError, URL,
195
+ VBArray, WSH, WScript, XDomainRequest, Web, Window, XMLDOM, XMLHttpRequest, XMLSerializer,
196
+ XPathEvaluator, XPathException, XPathExpression, XPathNamespace, XPathNSResolver, XPathResult,
197
+ "\\", a, addEventListener, address, alert, apply, applicationCache, arguments, arity, asi, atob,
198
+ b, basic, basicToken, bitwise, block, blur, boolOptions, boss, browser, btoa, c, call, callee,
199
+ caller, camelcase, cases, charAt, charCodeAt, character, clearInterval, clearTimeout,
200
+ close, closed, closure, comment, condition, confirm, console, constructor,
201
+ content, couch, create, css, curly, d, data, datalist, dd, debug, decodeURI,
202
+ decodeURIComponent, defaultStatus, defineClass, deserialize, devel, document,
203
+ dojo, dijit, dojox, define, else, emit, encodeURI, encodeURIComponent,
204
+ entityify, eqeq, eqeqeq, eqnull, errors, es5, escape, esnext, eval, event, evidence, evil,
205
+ ex, exception, exec, exps, expr, exports, FileReader, first, floor, focus,
206
+ forin, fragment, frames, from, fromCharCode, fud, funcscope, funct, function, functions,
207
+ g, gc, getComputedStyle, getRow, getter, getterToken, GLOBAL, global, globals, globalstrict,
208
+ hasOwnProperty, help, history, i, id, identifier, immed, implieds, importPackage, include,
209
+ indent, indexOf, init, ins, instanceOf, isAlpha, isApplicationRunning, isArray,
210
+ isDigit, isFinite, isNaN, iterator, java, join, jshint,
211
+ JSHINT, json, jquery, jQuery, keys, label, labelled, last, lastsemic, laxbreak, laxcomma,
212
+ latedef, lbp, led, left, length, line, load, loadClass, localStorage, location,
213
+ log, loopfunc, m, match, maxerr, maxlen, member,message, meta, module, moveBy,
214
+ moveTo, mootools, multistr, name, navigator, new, newcap, noarg, node, noempty, nomen,
215
+ nonew, nonstandard, nud, onbeforeunload, onblur, onerror, onevar, onecase, onfocus,
216
+ onload, onresize, onunload, open, openDatabase, openURL, opener, opera, options, outer, param,
217
+ parent, parseFloat, parseInt, passfail, plusplus, predef, print, process, prompt,
218
+ proto, prototype, prototypejs, provides, push, quit, quotmark, range, raw, reach, reason, regexp,
219
+ readFile, readUrl, regexdash, removeEventListener, replace, report, require,
220
+ reserved, resizeBy, resizeTo, resolvePath, resumeUpdates, respond, rhino, right,
221
+ runCommand, scroll, screen, scripturl, scrollBy, scrollTo, scrollbar, search, seal,
222
+ send, serialize, sessionStorage, setInterval, setTimeout, setter, setterToken, shift, slice,
223
+ smarttabs, sort, spawn, split, stack, status, start, strict, sub, substr, supernew, shadow,
224
+ supplant, sum, sync, test, toLowerCase, toString, toUpperCase, toint32, token, top, trailing,
225
+ type, typeOf, Uint16Array, Uint32Array, Uint8Array, undef, undefs, unused, urls, validthis,
226
+ value, valueOf, var, vars, version, WebSocket, withstmt, white, window, windows, Worker, wsh*/
227
+
228
+ /*global exports: false */
229
+
230
+ // We build the application inside a function so that we produce only a single
231
+ // global variable. That function will be invoked immediately, and its return
232
+ // value is the JSHINT function itself.
233
+
234
+ var JSHINT = (function () {
235
+ "use strict";
236
+
237
+ var anonname, // The guessed name for anonymous functions.
238
+
239
+ // These are operators that should not be used with the ! operator.
240
+
241
+ bang = {
242
+ '<' : true,
243
+ '<=' : true,
244
+ '==' : true,
245
+ '===': true,
246
+ '!==': true,
247
+ '!=' : true,
248
+ '>' : true,
249
+ '>=' : true,
250
+ '+' : true,
251
+ '-' : true,
252
+ '*' : true,
253
+ '/' : true,
254
+ '%' : true
255
+ },
256
+
257
+ // These are the JSHint boolean options.
258
+ boolOptions = {
259
+ asi : true, // if automatic semicolon insertion should be tolerated
260
+ bitwise : true, // if bitwise operators should not be allowed
261
+ boss : true, // if advanced usage of assignments should be allowed
262
+ browser : true, // if the standard browser globals should be predefined
263
+ camelcase : true, // if identifiers should be required in camel case
264
+ couch : true, // if CouchDB globals should be predefined
265
+ curly : true, // if curly braces around all blocks should be required
266
+ debug : true, // if debugger statements should be allowed
267
+ devel : true, // if logging globals should be predefined (console,
268
+ // alert, etc.)
269
+ dojo : true, // if Dojo Toolkit globals should be predefined
270
+ eqeqeq : true, // if === should be required
271
+ eqnull : true, // if == null comparisons should be tolerated
272
+ es5 : true, // if ES5 syntax should be allowed
273
+ esnext : true, // if es.next specific syntax should be allowed
274
+ evil : true, // if eval should be allowed
275
+ expr : true, // if ExpressionStatement should be allowed as Programs
276
+ forin : true, // if for in statements must filter
277
+ funcscope : true, // if only function scope should be used for scope tests
278
+ globalstrict: true, // if global "use strict"; should be allowed (also
279
+ // enables 'strict')
280
+ immed : true, // if immediate invocations must be wrapped in parens
281
+ iterator : true, // if the `__iterator__` property should be allowed
282
+ jquery : true, // if jQuery globals should be predefined
283
+ lastsemic : true, // if semicolons may be ommitted for the trailing
284
+ // statements inside of a one-line blocks.
285
+ latedef : true, // if the use before definition should not be tolerated
286
+ laxbreak : true, // if line breaks should not be checked
287
+ laxcomma : true, // if line breaks should not be checked around commas
288
+ loopfunc : true, // if functions should be allowed to be defined within
289
+ // loops
290
+ mootools : true, // if MooTools globals should be predefined
291
+ multistr : true, // allow multiline strings
292
+ newcap : true, // if constructor names must be capitalized
293
+ noarg : true, // if arguments.caller and arguments.callee should be
294
+ // disallowed
295
+ node : true, // if the Node.js environment globals should be
296
+ // predefined
297
+ noempty : true, // if empty blocks should be disallowed
298
+ nonew : true, // if using `new` for side-effects should be disallowed
299
+ nonstandard : true, // if non-standard (but widely adopted) globals should
300
+ // be predefined
301
+ nomen : true, // if names should be checked
302
+ onevar : true, // if only one var statement per function should be
303
+ // allowed
304
+ onecase : true, // if one case switch statements should be allowed
305
+ passfail : true, // if the scan should stop on first error
306
+ plusplus : true, // if increment/decrement should not be allowed
307
+ proto : true, // if the `__proto__` property should be allowed
308
+ prototypejs : true, // if Prototype and Scriptaculous globals should be
309
+ // predefined
310
+ regexdash : true, // if unescaped first/last dash (-) inside brackets
311
+ // should be tolerated
312
+ regexp : true, // if the . should not be allowed in regexp literals
313
+ rhino : true, // if the Rhino environment globals should be predefined
314
+ undef : true, // if variables should be declared before used
315
+ scripturl : true, // if script-targeted URLs should be tolerated
316
+ shadow : true, // if variable shadowing should be tolerated
317
+ smarttabs : true, // if smarttabs should be tolerated
318
+ // (http://www.emacswiki.org/emacs/SmartTabs)
319
+ strict : true, // require the "use strict"; pragma
320
+ sub : true, // if all forms of subscript notation are tolerated
321
+ supernew : true, // if `new function () { ... };` and `new Object;`
322
+ // should be tolerated
323
+ trailing : true, // if trailing whitespace rules apply
324
+ validthis : true, // if 'this' inside a non-constructor function is valid.
325
+ // This is a function scoped option only.
326
+ withstmt : true, // if with statements should be allowed
327
+ white : true, // if strict whitespace rules apply
328
+ wsh : true // if the Windows Scripting Host environment globals
329
+ // should be predefined
330
+ },
331
+
332
+ // These are the JSHint options that can take any value
333
+ // (we use this object to detect invalid options)
334
+ valOptions = {
335
+ maxlen: false,
336
+ indent: false,
337
+ maxerr: false,
338
+ predef: false,
339
+ quotmark: false //'single'|'double'|true
340
+ },
341
+
342
+ // These are JSHint boolean options which are shared with JSLint
343
+ // where the definition in JSHint is opposite JSLint
344
+ invertedOptions = {
345
+ bitwise : true,
346
+ forin : true,
347
+ newcap : true,
348
+ nomen : true,
349
+ plusplus : true,
350
+ regexp : true,
351
+ undef : true,
352
+ white : true,
353
+
354
+ // Inverted and renamed, use JSHint name here
355
+ eqeqeq : true,
356
+ onevar : true
357
+ },
358
+
359
+ // These are JSHint boolean options which are shared with JSLint
360
+ // where the name has been changed but the effect is unchanged
361
+ renamedOptions = {
362
+ eqeq : "eqeqeq",
363
+ vars : "onevar",
364
+ windows : "wsh"
365
+ },
366
+
367
+
368
+ // browser contains a set of global names which are commonly provided by a
369
+ // web browser environment.
370
+ browser = {
371
+ ArrayBuffer : false,
372
+ ArrayBufferView : false,
373
+ Audio : false,
374
+ addEventListener : false,
375
+ applicationCache : false,
376
+ atob : false,
377
+ blur : false,
378
+ btoa : false,
379
+ clearInterval : false,
380
+ clearTimeout : false,
381
+ close : false,
382
+ closed : false,
383
+ DataView : false,
384
+ DOMParser : false,
385
+ defaultStatus : false,
386
+ document : false,
387
+ event : false,
388
+ FileReader : false,
389
+ Float32Array : false,
390
+ Float64Array : false,
391
+ FormData : false,
392
+ focus : false,
393
+ frames : false,
394
+ getComputedStyle : false,
395
+ HTMLElement : false,
396
+ HTMLAnchorElement : false,
397
+ HTMLBaseElement : false,
398
+ HTMLBlockquoteElement : false,
399
+ HTMLBodyElement : false,
400
+ HTMLBRElement : false,
401
+ HTMLButtonElement : false,
402
+ HTMLCanvasElement : false,
403
+ HTMLDirectoryElement : false,
404
+ HTMLDivElement : false,
405
+ HTMLDListElement : false,
406
+ HTMLFieldSetElement : false,
407
+ HTMLFontElement : false,
408
+ HTMLFormElement : false,
409
+ HTMLFrameElement : false,
410
+ HTMLFrameSetElement : false,
411
+ HTMLHeadElement : false,
412
+ HTMLHeadingElement : false,
413
+ HTMLHRElement : false,
414
+ HTMLHtmlElement : false,
415
+ HTMLIFrameElement : false,
416
+ HTMLImageElement : false,
417
+ HTMLInputElement : false,
418
+ HTMLIsIndexElement : false,
419
+ HTMLLabelElement : false,
420
+ HTMLLayerElement : false,
421
+ HTMLLegendElement : false,
422
+ HTMLLIElement : false,
423
+ HTMLLinkElement : false,
424
+ HTMLMapElement : false,
425
+ HTMLMenuElement : false,
426
+ HTMLMetaElement : false,
427
+ HTMLModElement : false,
428
+ HTMLObjectElement : false,
429
+ HTMLOListElement : false,
430
+ HTMLOptGroupElement : false,
431
+ HTMLOptionElement : false,
432
+ HTMLParagraphElement : false,
433
+ HTMLParamElement : false,
434
+ HTMLPreElement : false,
435
+ HTMLQuoteElement : false,
436
+ HTMLScriptElement : false,
437
+ HTMLSelectElement : false,
438
+ HTMLStyleElement : false,
439
+ HTMLTableCaptionElement : false,
440
+ HTMLTableCellElement : false,
441
+ HTMLTableColElement : false,
442
+ HTMLTableElement : false,
443
+ HTMLTableRowElement : false,
444
+ HTMLTableSectionElement : false,
445
+ HTMLTextAreaElement : false,
446
+ HTMLTitleElement : false,
447
+ HTMLUListElement : false,
448
+ HTMLVideoElement : false,
449
+ history : false,
450
+ Int16Array : false,
451
+ Int32Array : false,
452
+ Int8Array : false,
453
+ Image : false,
454
+ length : false,
455
+ localStorage : false,
456
+ location : false,
457
+ MessageChannel : false,
458
+ MessageEvent : false,
459
+ MessagePort : false,
460
+ moveBy : false,
461
+ moveTo : false,
462
+ name : false,
463
+ Node : false,
464
+ NodeFilter : false,
465
+ navigator : false,
466
+ onbeforeunload : true,
467
+ onblur : true,
468
+ onerror : true,
469
+ onfocus : true,
470
+ onload : true,
471
+ onresize : true,
472
+ onunload : true,
473
+ open : false,
474
+ openDatabase : false,
475
+ opener : false,
476
+ Option : false,
477
+ parent : false,
478
+ print : false,
479
+ removeEventListener : false,
480
+ resizeBy : false,
481
+ resizeTo : false,
482
+ screen : false,
483
+ scroll : false,
484
+ scrollBy : false,
485
+ scrollTo : false,
486
+ sessionStorage : false,
487
+ setInterval : false,
488
+ setTimeout : false,
489
+ SharedWorker : false,
490
+ status : false,
491
+ top : false,
492
+ Uint16Array : false,
493
+ Uint32Array : false,
494
+ Uint8Array : false,
495
+ WebSocket : false,
496
+ window : false,
497
+ Worker : false,
498
+ XMLHttpRequest : false,
499
+ XMLSerializer : false,
500
+ XPathEvaluator : false,
501
+ XPathException : false,
502
+ XPathExpression : false,
503
+ XPathNamespace : false,
504
+ XPathNSResolver : false,
505
+ XPathResult : false
506
+ },
507
+
508
+ couch = {
509
+ "require" : false,
510
+ respond : false,
511
+ getRow : false,
512
+ emit : false,
513
+ send : false,
514
+ start : false,
515
+ sum : false,
516
+ log : false,
517
+ exports : false,
518
+ module : false,
519
+ provides : false
520
+ },
521
+
522
+ devel = {
523
+ alert : false,
524
+ confirm : false,
525
+ console : false,
526
+ Debug : false,
527
+ opera : false,
528
+ prompt : false
529
+ },
530
+
531
+ dojo = {
532
+ dojo : false,
533
+ dijit : false,
534
+ dojox : false,
535
+ define : false,
536
+ "require" : false
537
+ },
538
+
539
+ escapes = {
540
+ '\b': '\\b',
541
+ '\t': '\\t',
542
+ '\n': '\\n',
543
+ '\f': '\\f',
544
+ '\r': '\\r',
545
+ '"' : '\\"',
546
+ '/' : '\\/',
547
+ '\\': '\\\\'
548
+ },
549
+
550
+ funct, // The current function
551
+
552
+ functionicity = [
553
+ 'closure', 'exception', 'global', 'label',
554
+ 'outer', 'unused', 'var'
555
+ ],
556
+
557
+ functions, // All of the functions
558
+
559
+ global, // The global scope
560
+ implied, // Implied globals
561
+ inblock,
562
+ indent,
563
+ jsonmode,
564
+
565
+ jquery = {
566
+ '$' : false,
567
+ jQuery : false
568
+ },
569
+
570
+ lines,
571
+ lookahead,
572
+ member,
573
+ membersOnly,
574
+
575
+ mootools = {
576
+ '$' : false,
577
+ '$$' : false,
578
+ Assets : false,
579
+ Browser : false,
580
+ Chain : false,
581
+ Class : false,
582
+ Color : false,
583
+ Cookie : false,
584
+ Core : false,
585
+ Document : false,
586
+ DomReady : false,
587
+ DOMReady : false,
588
+ Drag : false,
589
+ Element : false,
590
+ Elements : false,
591
+ Event : false,
592
+ Events : false,
593
+ Fx : false,
594
+ Group : false,
595
+ Hash : false,
596
+ HtmlTable : false,
597
+ Iframe : false,
598
+ IframeShim : false,
599
+ InputValidator : false,
600
+ instanceOf : false,
601
+ Keyboard : false,
602
+ Locale : false,
603
+ Mask : false,
604
+ MooTools : false,
605
+ Native : false,
606
+ Options : false,
607
+ OverText : false,
608
+ Request : false,
609
+ Scroller : false,
610
+ Slick : false,
611
+ Slider : false,
612
+ Sortables : false,
613
+ Spinner : false,
614
+ Swiff : false,
615
+ Tips : false,
616
+ Type : false,
617
+ typeOf : false,
618
+ URI : false,
619
+ Window : false
620
+ },
621
+
622
+ nexttoken,
623
+
624
+ node = {
625
+ __filename : false,
626
+ __dirname : false,
627
+ Buffer : false,
628
+ console : false,
629
+ exports : false,
630
+ GLOBAL : false,
631
+ global : false,
632
+ module : false,
633
+ process : false,
634
+ require : false,
635
+ setTimeout : false,
636
+ clearTimeout : false,
637
+ setInterval : false,
638
+ clearInterval : false
639
+ },
640
+
641
+ noreach,
642
+ option,
643
+ predefined, // Global variables defined by option
644
+ prereg,
645
+ prevtoken,
646
+
647
+ prototypejs = {
648
+ '$' : false,
649
+ '$$' : false,
650
+ '$A' : false,
651
+ '$F' : false,
652
+ '$H' : false,
653
+ '$R' : false,
654
+ '$break' : false,
655
+ '$continue' : false,
656
+ '$w' : false,
657
+ Abstract : false,
658
+ Ajax : false,
659
+ Class : false,
660
+ Enumerable : false,
661
+ Element : false,
662
+ Event : false,
663
+ Field : false,
664
+ Form : false,
665
+ Hash : false,
666
+ Insertion : false,
667
+ ObjectRange : false,
668
+ PeriodicalExecuter: false,
669
+ Position : false,
670
+ Prototype : false,
671
+ Selector : false,
672
+ Template : false,
673
+ Toggle : false,
674
+ Try : false,
675
+ Autocompleter : false,
676
+ Builder : false,
677
+ Control : false,
678
+ Draggable : false,
679
+ Draggables : false,
680
+ Droppables : false,
681
+ Effect : false,
682
+ Sortable : false,
683
+ SortableObserver : false,
684
+ Sound : false,
685
+ Scriptaculous : false
686
+ },
687
+
688
+ quotmark,
689
+
690
+ rhino = {
691
+ defineClass : false,
692
+ deserialize : false,
693
+ gc : false,
694
+ help : false,
695
+ importPackage: false,
696
+ "java" : false,
697
+ load : false,
698
+ loadClass : false,
699
+ print : false,
700
+ quit : false,
701
+ readFile : false,
702
+ readUrl : false,
703
+ runCommand : false,
704
+ seal : false,
705
+ serialize : false,
706
+ spawn : false,
707
+ sync : false,
708
+ toint32 : false,
709
+ version : false
710
+ },
711
+
712
+ scope, // The current scope
713
+ stack,
714
+
715
+ // standard contains the global names that are provided by the
716
+ // ECMAScript standard.
717
+ standard = {
718
+ Array : false,
719
+ Boolean : false,
720
+ Date : false,
721
+ decodeURI : false,
722
+ decodeURIComponent : false,
723
+ encodeURI : false,
724
+ encodeURIComponent : false,
725
+ Error : false,
726
+ 'eval' : false,
727
+ EvalError : false,
728
+ Function : false,
729
+ hasOwnProperty : false,
730
+ isFinite : false,
731
+ isNaN : false,
732
+ JSON : false,
733
+ Math : false,
734
+ Number : false,
735
+ Object : false,
736
+ parseInt : false,
737
+ parseFloat : false,
738
+ RangeError : false,
739
+ ReferenceError : false,
740
+ RegExp : false,
741
+ String : false,
742
+ SyntaxError : false,
743
+ TypeError : false,
744
+ URIError : false
745
+ },
746
+
747
+ // widely adopted global names that are not part of ECMAScript standard
748
+ nonstandard = {
749
+ escape : false,
750
+ unescape : false
751
+ },
752
+
753
+ standard_member = {
754
+ E : true,
755
+ LN2 : true,
756
+ LN10 : true,
757
+ LOG2E : true,
758
+ LOG10E : true,
759
+ MAX_VALUE : true,
760
+ MIN_VALUE : true,
761
+ NEGATIVE_INFINITY : true,
762
+ PI : true,
763
+ POSITIVE_INFINITY : true,
764
+ SQRT1_2 : true,
765
+ SQRT2 : true
766
+ },
767
+
768
+ directive,
769
+ syntax = {},
770
+ tab,
771
+ token,
772
+ urls,
773
+ useESNextSyntax,
774
+ warnings,
775
+
776
+ wsh = {
777
+ ActiveXObject : true,
778
+ Enumerator : true,
779
+ GetObject : true,
780
+ ScriptEngine : true,
781
+ ScriptEngineBuildVersion : true,
782
+ ScriptEngineMajorVersion : true,
783
+ ScriptEngineMinorVersion : true,
784
+ VBArray : true,
785
+ WSH : true,
786
+ WScript : true,
787
+ XDomainRequest : true
788
+ };
789
+
790
+ // Regular expressions. Some of these are stupidly long.
791
+ var ax, cx, tx, nx, nxg, lx, ix, jx, ft;
792
+ (function () {
793
+ /*jshint maxlen:300 */
794
+
795
+ // unsafe comment or string
796
+ ax = /@cc|<\/?|script|\]\s*\]|<\s*!|&lt/i;
797
+
798
+ // unsafe characters that are silently deleted by one or more browsers
799
+ cx = /[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/;
800
+
801
+ // token
802
+ 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]+)?)/;
803
+
804
+ // characters in strings that need escapement
805
+ nx = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/;
806
+ nxg = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
807
+
808
+ // star slash
809
+ lx = /\*\/|\/\*/;
810
+
811
+ // identifier
812
+ ix = /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/;
813
+
814
+ // javascript url
815
+ jx = /^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i;
816
+
817
+ // catches /* falls through */ comments
818
+ ft = /^\s*\/\*\s*falls\sthrough\s*\*\/\s*$/;
819
+ }());
820
+
821
+ function F() {} // Used by Object.create
822
+
823
+ function is_own(object, name) {
824
+
825
+ // The object.hasOwnProperty method fails when the property under consideration
826
+ // is named 'hasOwnProperty'. So we have to use this more convoluted form.
827
+
828
+ return Object.prototype.hasOwnProperty.call(object, name);
829
+ }
830
+
831
+ function checkOption(name, t) {
832
+ if (valOptions[name] === undefined && boolOptions[name] === undefined) {
833
+ warning("Bad option: '" + name + "'.", t);
834
+ }
835
+ }
836
+
837
+ // Provide critical ES5 functions to ES3.
838
+
839
+ if (typeof Array.isArray !== 'function') {
840
+ Array.isArray = function (o) {
841
+ return Object.prototype.toString.apply(o) === '[object Array]';
842
+ };
843
+ }
844
+
845
+ if (typeof Object.create !== 'function') {
846
+ Object.create = function (o) {
847
+ F.prototype = o;
848
+ return new F();
849
+ };
850
+ }
851
+
852
+ if (typeof Object.keys !== 'function') {
853
+ Object.keys = function (o) {
854
+ var a = [], k;
855
+ for (k in o) {
856
+ if (is_own(o, k)) {
857
+ a.push(k);
858
+ }
859
+ }
860
+ return a;
861
+ };
862
+ }
863
+
864
+ // Non standard methods
865
+
866
+ if (typeof String.prototype.entityify !== 'function') {
867
+ String.prototype.entityify = function () {
868
+ return this
869
+ .replace(/&/g, '&amp;')
870
+ .replace(/</g, '&lt;')
871
+ .replace(/>/g, '&gt;');
872
+ };
873
+ }
874
+
875
+ if (typeof String.prototype.isAlpha !== 'function') {
876
+ String.prototype.isAlpha = function () {
877
+ return (this >= 'a' && this <= 'z\uffff') ||
878
+ (this >= 'A' && this <= 'Z\uffff');
879
+ };
880
+ }
881
+
882
+ if (typeof String.prototype.isDigit !== 'function') {
883
+ String.prototype.isDigit = function () {
884
+ return (this >= '0' && this <= '9');
885
+ };
886
+ }
887
+
888
+ if (typeof String.prototype.supplant !== 'function') {
889
+ String.prototype.supplant = function (o) {
890
+ return this.replace(/\{([^{}]*)\}/g, function (a, b) {
891
+ var r = o[b];
892
+ return typeof r === 'string' || typeof r === 'number' ? r : a;
893
+ });
894
+ };
895
+ }
896
+
897
+ if (typeof String.prototype.name !== 'function') {
898
+ String.prototype.name = function () {
899
+
900
+ // If the string looks like an identifier, then we can return it as is.
901
+ // If the string contains no control characters, no quote characters, and no
902
+ // backslash characters, then we can simply slap some quotes around it.
903
+ // Otherwise we must also replace the offending characters with safe
904
+ // sequences.
905
+
906
+ if (ix.test(this)) {
907
+ return this;
908
+ }
909
+ if (nx.test(this)) {
910
+ return '"' + this.replace(nxg, function (a) {
911
+ var c = escapes[a];
912
+ if (c) {
913
+ return c;
914
+ }
915
+ return '\\u' + ('0000' + a.charCodeAt().toString(16)).slice(-4);
916
+ }) + '"';
917
+ }
918
+ return '"' + this + '"';
919
+ };
920
+ }
921
+
922
+
923
+ function combine(t, o) {
924
+ var n;
925
+ for (n in o) {
926
+ if (is_own(o, n)) {
927
+ t[n] = o[n];
928
+ }
929
+ }
930
+ }
931
+
932
+ function assume() {
933
+ if (option.couch) {
934
+ combine(predefined, couch);
935
+ }
936
+
937
+ if (option.rhino) {
938
+ combine(predefined, rhino);
939
+ }
940
+
941
+ if (option.prototypejs) {
942
+ combine(predefined, prototypejs);
943
+ }
944
+
945
+ if (option.node) {
946
+ combine(predefined, node);
947
+ option.globalstrict = true;
948
+ }
949
+
950
+ if (option.devel) {
951
+ combine(predefined, devel);
952
+ }
953
+
954
+ if (option.dojo) {
955
+ combine(predefined, dojo);
956
+ }
957
+
958
+ if (option.browser) {
959
+ combine(predefined, browser);
960
+ }
961
+
962
+ if (option.nonstandard) {
963
+ combine(predefined, nonstandard);
964
+ }
965
+
966
+ if (option.jquery) {
967
+ combine(predefined, jquery);
968
+ }
969
+
970
+ if (option.mootools) {
971
+ combine(predefined, mootools);
972
+ }
973
+
974
+ if (option.wsh) {
975
+ combine(predefined, wsh);
976
+ }
977
+
978
+ if (option.esnext) {
979
+ useESNextSyntax();
980
+ }
981
+
982
+ if (option.globalstrict && option.strict !== false) {
983
+ option.strict = true;
984
+ }
985
+ }
986
+
987
+
988
+ // Produce an error warning.
989
+ function quit(message, line, chr) {
990
+ var percentage = Math.floor((line / lines.length) * 100);
991
+
992
+ throw {
993
+ name: 'JSHintError',
994
+ line: line,
995
+ character: chr,
996
+ message: message + " (" + percentage + "% scanned).",
997
+ raw: message
998
+ };
999
+ }
1000
+
1001
+ function isundef(scope, m, t, a) {
1002
+ return JSHINT.undefs.push([scope, m, t, a]);
1003
+ }
1004
+
1005
+ function warning(m, t, a, b, c, d) {
1006
+ var ch, l, w;
1007
+ t = t || nexttoken;
1008
+ if (t.id === '(end)') { // `~
1009
+ t = token;
1010
+ }
1011
+ l = t.line || 0;
1012
+ ch = t.from || 0;
1013
+ w = {
1014
+ id: '(error)',
1015
+ raw: m,
1016
+ evidence: lines[l - 1] || '',
1017
+ line: l,
1018
+ character: ch,
1019
+ a: a,
1020
+ b: b,
1021
+ c: c,
1022
+ d: d
1023
+ };
1024
+ w.reason = m.supplant(w);
1025
+ JSHINT.errors.push(w);
1026
+ if (option.passfail) {
1027
+ quit('Stopping. ', l, ch);
1028
+ }
1029
+ warnings += 1;
1030
+ if (warnings >= option.maxerr) {
1031
+ quit("Too many errors.", l, ch);
1032
+ }
1033
+ return w;
1034
+ }
1035
+
1036
+ function warningAt(m, l, ch, a, b, c, d) {
1037
+ return warning(m, {
1038
+ line: l,
1039
+ from: ch
1040
+ }, a, b, c, d);
1041
+ }
1042
+
1043
+ function error(m, t, a, b, c, d) {
1044
+ var w = warning(m, t, a, b, c, d);
1045
+ }
1046
+
1047
+ function errorAt(m, l, ch, a, b, c, d) {
1048
+ return error(m, {
1049
+ line: l,
1050
+ from: ch
1051
+ }, a, b, c, d);
1052
+ }
1053
+
1054
+
1055
+
1056
+ // lexical analysis and token construction
1057
+
1058
+ var lex = (function lex() {
1059
+ var character, from, line, s;
1060
+
1061
+ // Private lex methods
1062
+
1063
+ function nextLine() {
1064
+ var at,
1065
+ tw; // trailing whitespace check
1066
+
1067
+ if (line >= lines.length)
1068
+ return false;
1069
+
1070
+ character = 1;
1071
+ s = lines[line];
1072
+ line += 1;
1073
+
1074
+ // If smarttabs option is used check for spaces followed by tabs only.
1075
+ // Otherwise check for any occurence of mixed tabs and spaces.
1076
+ // Tabs and one space followed by block comment is allowed.
1077
+ if (option.smarttabs)
1078
+ at = s.search(/ \t/);
1079
+ else
1080
+ at = s.search(/ \t|\t [^\*]/);
1081
+
1082
+ if (at >= 0)
1083
+ warningAt("Mixed spaces and tabs.", line, at + 1);
1084
+
1085
+ s = s.replace(/\t/g, tab);
1086
+ at = s.search(cx);
1087
+
1088
+ if (at >= 0)
1089
+ warningAt("Unsafe character.", line, at);
1090
+
1091
+ if (option.maxlen && option.maxlen < s.length)
1092
+ warningAt("Line too long.", line, s.length);
1093
+
1094
+ // Check for trailing whitespaces
1095
+ tw = option.trailing && s.match(/^(.*?)\s+$/);
1096
+ if (tw && !/^\s+$/.test(s)) {
1097
+ warningAt("Trailing whitespace.", line, tw[1].length + 1);
1098
+ }
1099
+ return true;
1100
+ }
1101
+
1102
+ // Produce a token object. The token inherits from a syntax symbol.
1103
+
1104
+ function it(type, value) {
1105
+ var i, t;
1106
+ if (type === '(color)' || type === '(range)') {
1107
+ t = {type: type};
1108
+ } else if (type === '(punctuator)' ||
1109
+ (type === '(identifier)' && is_own(syntax, value))) {
1110
+ t = syntax[value] || syntax['(error)'];
1111
+ } else {
1112
+ t = syntax[type];
1113
+ }
1114
+ t = Object.create(t);
1115
+ if (type === '(string)' || type === '(range)') {
1116
+ if (!option.scripturl && jx.test(value)) {
1117
+ warningAt("Script URL.", line, from);
1118
+ }
1119
+ }
1120
+ if (type === '(identifier)') {
1121
+ t.identifier = true;
1122
+ if (value === '__proto__' && !option.proto) {
1123
+ warningAt("The '{a}' property is deprecated.",
1124
+ line, from, value);
1125
+ } else if (value === '__iterator__' && !option.iterator) {
1126
+ warningAt("'{a}' is only available in JavaScript 1.7.",
1127
+ line, from, value);
1128
+ } else if (option.nomen && (value.charAt(0) === '_' ||
1129
+ value.charAt(value.length - 1) === '_')) {
1130
+ if (!option.node || token.id === '.' ||
1131
+ (value !== '__dirname' && value !== '__filename')) {
1132
+ warningAt("Unexpected {a} in '{b}'.", line, from, "dangling '_'", value);
1133
+ }
1134
+ } else if (option.camelcase && value.indexOf('_') > -1 &&
1135
+ !value.match(/^[A-Z0-9_]*$/)) {
1136
+ warningAt("Identifier '{a}' is not in camel case.",
1137
+ line, from, value);
1138
+ }
1139
+ }
1140
+ t.value = value;
1141
+ t.line = line;
1142
+ t.character = character;
1143
+ t.from = from;
1144
+ i = t.id;
1145
+ if (i !== '(endline)') {
1146
+ prereg = i &&
1147
+ (('(,=:[!&|?{};'.indexOf(i.charAt(i.length - 1)) >= 0) ||
1148
+ i === 'return' ||
1149
+ i === 'case');
1150
+ }
1151
+ return t;
1152
+ }
1153
+
1154
+ // Public lex methods
1155
+ return {
1156
+ init: function (source) {
1157
+ if (typeof source === 'string') {
1158
+ lines = source
1159
+ .replace(/\r\n/g, '\n')
1160
+ .replace(/\r/g, '\n')
1161
+ .split('\n');
1162
+ } else {
1163
+ lines = source;
1164
+ }
1165
+
1166
+ // If the first line is a shebang (#!), make it a blank and move on.
1167
+ // Shebangs are used by Node scripts.
1168
+ if (lines[0] && lines[0].substr(0, 2) === '#!')
1169
+ lines[0] = '';
1170
+
1171
+ line = 0;
1172
+ nextLine();
1173
+ from = 1;
1174
+ },
1175
+
1176
+ range: function (begin, end) {
1177
+ var c, value = '';
1178
+ from = character;
1179
+ if (s.charAt(0) !== begin) {
1180
+ errorAt("Expected '{a}' and instead saw '{b}'.",
1181
+ line, character, begin, s.charAt(0));
1182
+ }
1183
+ for (;;) {
1184
+ s = s.slice(1);
1185
+ character += 1;
1186
+ c = s.charAt(0);
1187
+ switch (c) {
1188
+ case '':
1189
+ errorAt("Missing '{a}'.", line, character, c);
1190
+ break;
1191
+ case end:
1192
+ s = s.slice(1);
1193
+ character += 1;
1194
+ return it('(range)', value);
1195
+ case '\\':
1196
+ warningAt("Unexpected '{a}'.", line, character, c);
1197
+ }
1198
+ value += c;
1199
+ }
1200
+
1201
+ },
1202
+
1203
+
1204
+ // token -- this is called by advance to get the next token
1205
+ token: function () {
1206
+ var b, c, captures, d, depth, high, i, l, low, q, t, isLiteral, isInRange, n;
1207
+
1208
+ function match(x) {
1209
+ var r = x.exec(s), r1;
1210
+ if (r) {
1211
+ l = r[0].length;
1212
+ r1 = r[1];
1213
+ c = r1.charAt(0);
1214
+ s = s.substr(l);
1215
+ from = character + l - r1.length;
1216
+ character += l;
1217
+ return r1;
1218
+ }
1219
+ }
1220
+
1221
+ function string(x) {
1222
+ var c, j, r = '', allowNewLine = false;
1223
+
1224
+ if (jsonmode && x !== '"') {
1225
+ warningAt("Strings must use doublequote.",
1226
+ line, character);
1227
+ }
1228
+
1229
+ if (option.quotmark) {
1230
+ if (option.quotmark === 'single' && x !== "'") {
1231
+ warningAt("Strings must use singlequote.",
1232
+ line, character);
1233
+ } else if (option.quotmark === 'double' && x !== '"') {
1234
+ warningAt("Strings must use doublequote.",
1235
+ line, character);
1236
+ } else if (option.quotmark === true) {
1237
+ quotmark = quotmark || x;
1238
+ if (quotmark !== x) {
1239
+ warningAt("Mixed double and single quotes.",
1240
+ line, character);
1241
+ }
1242
+ }
1243
+ }
1244
+
1245
+ function esc(n) {
1246
+ var i = parseInt(s.substr(j + 1, n), 16);
1247
+ j += n;
1248
+ if (i >= 32 && i <= 126 &&
1249
+ i !== 34 && i !== 92 && i !== 39) {
1250
+ warningAt("Unnecessary escapement.", line, character);
1251
+ }
1252
+ character += n;
1253
+ c = String.fromCharCode(i);
1254
+ }
1255
+ j = 0;
1256
+ unclosedString: for (;;) {
1257
+ while (j >= s.length) {
1258
+ j = 0;
1259
+
1260
+ var cl = line, cf = from;
1261
+ if (!nextLine()) {
1262
+ errorAt("Unclosed string.", cl, cf);
1263
+ break unclosedString;
1264
+ }
1265
+
1266
+ if (allowNewLine) {
1267
+ allowNewLine = false;
1268
+ } else {
1269
+ warningAt("Unclosed string.", cl, cf);
1270
+ }
1271
+ }
1272
+ c = s.charAt(j);
1273
+ if (c === x) {
1274
+ character += 1;
1275
+ s = s.substr(j + 1);
1276
+ return it('(string)', r, x);
1277
+ }
1278
+ if (c < ' ') {
1279
+ if (c === '\n' || c === '\r') {
1280
+ break;
1281
+ }
1282
+ warningAt("Control character in string: {a}.",
1283
+ line, character + j, s.slice(0, j));
1284
+ } else if (c === '\\') {
1285
+ j += 1;
1286
+ character += 1;
1287
+ c = s.charAt(j);
1288
+ n = s.charAt(j + 1);
1289
+ switch (c) {
1290
+ case '\\':
1291
+ case '"':
1292
+ case '/':
1293
+ break;
1294
+ case '\'':
1295
+ if (jsonmode) {
1296
+ warningAt("Avoid \\'.", line, character);
1297
+ }
1298
+ break;
1299
+ case 'b':
1300
+ c = '\b';
1301
+ break;
1302
+ case 'f':
1303
+ c = '\f';
1304
+ break;
1305
+ case 'n':
1306
+ c = '\n';
1307
+ break;
1308
+ case 'r':
1309
+ c = '\r';
1310
+ break;
1311
+ case 't':
1312
+ c = '\t';
1313
+ break;
1314
+ case '0':
1315
+ c = '\0';
1316
+ // Octal literals fail in strict mode
1317
+ // check if the number is between 00 and 07
1318
+ // where 'n' is the token next to 'c'
1319
+ if (n >= 0 && n <= 7 && directive["use strict"]) {
1320
+ warningAt(
1321
+ "Octal literals are not allowed in strict mode.",
1322
+ line, character);
1323
+ }
1324
+ break;
1325
+ case 'u':
1326
+ esc(4);
1327
+ break;
1328
+ case 'v':
1329
+ if (jsonmode) {
1330
+ warningAt("Avoid \\v.", line, character);
1331
+ }
1332
+ c = '\v';
1333
+ break;
1334
+ case 'x':
1335
+ if (jsonmode) {
1336
+ warningAt("Avoid \\x-.", line, character);
1337
+ }
1338
+ esc(2);
1339
+ break;
1340
+ case '':
1341
+ // last character is escape character
1342
+ // always allow new line if escaped, but show
1343
+ // warning if option is not set
1344
+ allowNewLine = true;
1345
+ if (option.multistr) {
1346
+ if (jsonmode) {
1347
+ warningAt("Avoid EOL escapement.", line, character);
1348
+ }
1349
+ c = '';
1350
+ character -= 1;
1351
+ break;
1352
+ }
1353
+ warningAt("Bad escapement of EOL. Use option multistr if needed.",
1354
+ line, character);
1355
+ break;
1356
+ default:
1357
+ warningAt("Bad escapement.", line, character);
1358
+ }
1359
+ }
1360
+ r += c;
1361
+ character += 1;
1362
+ j += 1;
1363
+ }
1364
+ }
1365
+
1366
+ for (;;) {
1367
+ if (!s) {
1368
+ return it(nextLine() ? '(endline)' : '(end)', '');
1369
+ }
1370
+ t = match(tx);
1371
+ if (!t) {
1372
+ t = '';
1373
+ c = '';
1374
+ while (s && s < '!') {
1375
+ s = s.substr(1);
1376
+ }
1377
+ if (s) {
1378
+ errorAt("Unexpected '{a}'.", line, character, s.substr(0, 1));
1379
+ s = '';
1380
+ }
1381
+ } else {
1382
+
1383
+ // identifier
1384
+
1385
+ if (c.isAlpha() || c === '_' || c === '$') {
1386
+ return it('(identifier)', t);
1387
+ }
1388
+
1389
+ // number
1390
+
1391
+ if (c.isDigit()) {
1392
+ if (!isFinite(Number(t))) {
1393
+ warningAt("Bad number '{a}'.",
1394
+ line, character, t);
1395
+ }
1396
+ if (s.substr(0, 1).isAlpha()) {
1397
+ warningAt("Missing space after '{a}'.",
1398
+ line, character, t);
1399
+ }
1400
+ if (c === '0') {
1401
+ d = t.substr(1, 1);
1402
+ if (d.isDigit()) {
1403
+ if (token.id !== '.') {
1404
+ warningAt("Don't use extra leading zeros '{a}'.",
1405
+ line, character, t);
1406
+ }
1407
+ } else if (jsonmode && (d === 'x' || d === 'X')) {
1408
+ warningAt("Avoid 0x-. '{a}'.",
1409
+ line, character, t);
1410
+ }
1411
+ }
1412
+ if (t.substr(t.length - 1) === '.') {
1413
+ warningAt(
1414
+ "A trailing decimal point can be confused with a dot '{a}'.", line, character, t);
1415
+ }
1416
+ return it('(number)', t);
1417
+ }
1418
+ switch (t) {
1419
+
1420
+ // string
1421
+
1422
+ case '"':
1423
+ case "'":
1424
+ return string(t);
1425
+
1426
+ // // comment
1427
+
1428
+ case '//':
1429
+ s = '';
1430
+ token.comment = true;
1431
+ break;
1432
+
1433
+ // /* comment
1434
+
1435
+ case '/*':
1436
+ for (;;) {
1437
+ i = s.search(lx);
1438
+ if (i >= 0) {
1439
+ break;
1440
+ }
1441
+ if (!nextLine()) {
1442
+ errorAt("Unclosed comment.", line, character);
1443
+ }
1444
+ }
1445
+ character += i + 2;
1446
+ if (s.substr(i, 1) === '/') {
1447
+ errorAt("Nested comment.", line, character);
1448
+ }
1449
+ s = s.substr(i + 2);
1450
+ token.comment = true;
1451
+ break;
1452
+
1453
+ // /*members /*jshint /*global
1454
+
1455
+ case '/*members':
1456
+ case '/*member':
1457
+ case '/*jshint':
1458
+ case '/*jslint':
1459
+ case '/*global':
1460
+ case '*/':
1461
+ return {
1462
+ value: t,
1463
+ type: 'special',
1464
+ line: line,
1465
+ character: character,
1466
+ from: from
1467
+ };
1468
+
1469
+ case '':
1470
+ break;
1471
+ // /
1472
+ case '/':
1473
+ if (token.id === '/=') {
1474
+ errorAt("A regular expression literal can be confused with '/='.",
1475
+ line, from);
1476
+ }
1477
+ if (prereg) {
1478
+ depth = 0;
1479
+ captures = 0;
1480
+ l = 0;
1481
+ for (;;) {
1482
+ b = true;
1483
+ c = s.charAt(l);
1484
+ l += 1;
1485
+ switch (c) {
1486
+ case '':
1487
+ errorAt("Unclosed regular expression.", line, from);
1488
+ return quit('Stopping.', line, from);
1489
+ case '/':
1490
+ if (depth > 0) {
1491
+ warningAt("{a} unterminated regular expression " +
1492
+ "group(s).", line, from + l, depth);
1493
+ }
1494
+ c = s.substr(0, l - 1);
1495
+ q = {
1496
+ g: true,
1497
+ i: true,
1498
+ m: true
1499
+ };
1500
+ while (q[s.charAt(l)] === true) {
1501
+ q[s.charAt(l)] = false;
1502
+ l += 1;
1503
+ }
1504
+ character += l;
1505
+ s = s.substr(l);
1506
+ q = s.charAt(0);
1507
+ if (q === '/' || q === '*') {
1508
+ errorAt("Confusing regular expression.",
1509
+ line, from);
1510
+ }
1511
+ return it('(regexp)', c);
1512
+ case '\\':
1513
+ c = s.charAt(l);
1514
+ if (c < ' ') {
1515
+ warningAt(
1516
+ "Unexpected control character in regular expression.", line, from + l);
1517
+ } else if (c === '<') {
1518
+ warningAt(
1519
+ "Unexpected escaped character '{a}' in regular expression.", line, from + l, c);
1520
+ }
1521
+ l += 1;
1522
+ break;
1523
+ case '(':
1524
+ depth += 1;
1525
+ b = false;
1526
+ if (s.charAt(l) === '?') {
1527
+ l += 1;
1528
+ switch (s.charAt(l)) {
1529
+ case ':':
1530
+ case '=':
1531
+ case '!':
1532
+ l += 1;
1533
+ break;
1534
+ default:
1535
+ warningAt(
1536
+ "Expected '{a}' and instead saw '{b}'.", line, from + l, ':', s.charAt(l));
1537
+ }
1538
+ } else {
1539
+ captures += 1;
1540
+ }
1541
+ break;
1542
+ case '|':
1543
+ b = false;
1544
+ break;
1545
+ case ')':
1546
+ if (depth === 0) {
1547
+ warningAt("Unescaped '{a}'.",
1548
+ line, from + l, ')');
1549
+ } else {
1550
+ depth -= 1;
1551
+ }
1552
+ break;
1553
+ case ' ':
1554
+ q = 1;
1555
+ while (s.charAt(l) === ' ') {
1556
+ l += 1;
1557
+ q += 1;
1558
+ }
1559
+ if (q > 1) {
1560
+ warningAt(
1561
+ "Spaces are hard to count. Use {{a}}.", line, from + l, q);
1562
+ }
1563
+ break;
1564
+ case '[':
1565
+ c = s.charAt(l);
1566
+ if (c === '^') {
1567
+ l += 1;
1568
+ if (option.regexp) {
1569
+ warningAt("Insecure '{a}'.",
1570
+ line, from + l, c);
1571
+ } else if (s.charAt(l) === ']') {
1572
+ errorAt("Unescaped '{a}'.",
1573
+ line, from + l, '^');
1574
+ }
1575
+ }
1576
+ if (c === ']') {
1577
+ warningAt("Empty class.", line,
1578
+ from + l - 1);
1579
+ }
1580
+ isLiteral = false;
1581
+ isInRange = false;
1582
+ klass: do {
1583
+ c = s.charAt(l);
1584
+ l += 1;
1585
+ switch (c) {
1586
+ case '[':
1587
+ case '^':
1588
+ warningAt("Unescaped '{a}'.",
1589
+ line, from + l, c);
1590
+ if (isInRange) {
1591
+ isInRange = false;
1592
+ } else {
1593
+ isLiteral = true;
1594
+ }
1595
+ break;
1596
+ case '-':
1597
+ if (isLiteral && !isInRange) {
1598
+ isLiteral = false;
1599
+ isInRange = true;
1600
+ } else if (isInRange) {
1601
+ isInRange = false;
1602
+ } else if (s.charAt(l) === ']') {
1603
+ isInRange = true;
1604
+ } else {
1605
+ if (option.regexdash !== (l === 2 || (l === 3 &&
1606
+ s.charAt(1) === '^'))) {
1607
+ warningAt("Unescaped '{a}'.",
1608
+ line, from + l - 1, '-');
1609
+ }
1610
+ isLiteral = true;
1611
+ }
1612
+ break;
1613
+ case ']':
1614
+ if (isInRange && !option.regexdash) {
1615
+ warningAt("Unescaped '{a}'.",
1616
+ line, from + l - 1, '-');
1617
+ }
1618
+ break klass;
1619
+ case '\\':
1620
+ c = s.charAt(l);
1621
+ if (c < ' ') {
1622
+ warningAt(
1623
+ "Unexpected control character in regular expression.", line, from + l);
1624
+ } else if (c === '<') {
1625
+ warningAt(
1626
+ "Unexpected escaped character '{a}' in regular expression.", line, from + l, c);
1627
+ }
1628
+ l += 1;
1629
+
1630
+ // \w, \s and \d are never part of a character range
1631
+ if (/[wsd]/i.test(c)) {
1632
+ if (isInRange) {
1633
+ warningAt("Unescaped '{a}'.",
1634
+ line, from + l, '-');
1635
+ isInRange = false;
1636
+ }
1637
+ isLiteral = false;
1638
+ } else if (isInRange) {
1639
+ isInRange = false;
1640
+ } else {
1641
+ isLiteral = true;
1642
+ }
1643
+ break;
1644
+ case '/':
1645
+ warningAt("Unescaped '{a}'.",
1646
+ line, from + l - 1, '/');
1647
+
1648
+ if (isInRange) {
1649
+ isInRange = false;
1650
+ } else {
1651
+ isLiteral = true;
1652
+ }
1653
+ break;
1654
+ case '<':
1655
+ if (isInRange) {
1656
+ isInRange = false;
1657
+ } else {
1658
+ isLiteral = true;
1659
+ }
1660
+ break;
1661
+ default:
1662
+ if (isInRange) {
1663
+ isInRange = false;
1664
+ } else {
1665
+ isLiteral = true;
1666
+ }
1667
+ }
1668
+ } while (c);
1669
+ break;
1670
+ case '.':
1671
+ if (option.regexp) {
1672
+ warningAt("Insecure '{a}'.", line,
1673
+ from + l, c);
1674
+ }
1675
+ break;
1676
+ case ']':
1677
+ case '?':
1678
+ case '{':
1679
+ case '}':
1680
+ case '+':
1681
+ case '*':
1682
+ warningAt("Unescaped '{a}'.", line,
1683
+ from + l, c);
1684
+ }
1685
+ if (b) {
1686
+ switch (s.charAt(l)) {
1687
+ case '?':
1688
+ case '+':
1689
+ case '*':
1690
+ l += 1;
1691
+ if (s.charAt(l) === '?') {
1692
+ l += 1;
1693
+ }
1694
+ break;
1695
+ case '{':
1696
+ l += 1;
1697
+ c = s.charAt(l);
1698
+ if (c < '0' || c > '9') {
1699
+ warningAt(
1700
+ "Expected a number and instead saw '{a}'.", line, from + l, c);
1701
+ }
1702
+ l += 1;
1703
+ low = +c;
1704
+ for (;;) {
1705
+ c = s.charAt(l);
1706
+ if (c < '0' || c > '9') {
1707
+ break;
1708
+ }
1709
+ l += 1;
1710
+ low = +c + (low * 10);
1711
+ }
1712
+ high = low;
1713
+ if (c === ',') {
1714
+ l += 1;
1715
+ high = Infinity;
1716
+ c = s.charAt(l);
1717
+ if (c >= '0' && c <= '9') {
1718
+ l += 1;
1719
+ high = +c;
1720
+ for (;;) {
1721
+ c = s.charAt(l);
1722
+ if (c < '0' || c > '9') {
1723
+ break;
1724
+ }
1725
+ l += 1;
1726
+ high = +c + (high * 10);
1727
+ }
1728
+ }
1729
+ }
1730
+ if (s.charAt(l) !== '}') {
1731
+ warningAt(
1732
+ "Expected '{a}' and instead saw '{b}'.", line, from + l, '}', c);
1733
+ } else {
1734
+ l += 1;
1735
+ }
1736
+ if (s.charAt(l) === '?') {
1737
+ l += 1;
1738
+ }
1739
+ if (low > high) {
1740
+ warningAt(
1741
+ "'{a}' should not be greater than '{b}'.", line, from + l, low, high);
1742
+ }
1743
+ }
1744
+ }
1745
+ }
1746
+ c = s.substr(0, l - 1);
1747
+ character += l;
1748
+ s = s.substr(l);
1749
+ return it('(regexp)', c);
1750
+ }
1751
+ return it('(punctuator)', t);
1752
+
1753
+ // punctuator
1754
+
1755
+ case '#':
1756
+ return it('(punctuator)', t);
1757
+ default:
1758
+ return it('(punctuator)', t);
1759
+ }
1760
+ }
1761
+ }
1762
+ }
1763
+ };
1764
+ }());
1765
+
1766
+
1767
+ function addlabel(t, type) {
1768
+
1769
+ if (t === 'hasOwnProperty') {
1770
+ warning("'hasOwnProperty' is a really bad name.");
1771
+ }
1772
+
1773
+ // Define t in the current function in the current scope.
1774
+ if (is_own(funct, t) && !funct['(global)']) {
1775
+ if (funct[t] === true) {
1776
+ if (option.latedef)
1777
+ warning("'{a}' was used before it was defined.", nexttoken, t);
1778
+ } else {
1779
+ if (!option.shadow && type !== "exception")
1780
+ warning("'{a}' is already defined.", nexttoken, t);
1781
+ }
1782
+ }
1783
+
1784
+ funct[t] = type;
1785
+ if (funct['(global)']) {
1786
+ global[t] = funct;
1787
+ if (is_own(implied, t)) {
1788
+ if (option.latedef)
1789
+ warning("'{a}' was used before it was defined.", nexttoken, t);
1790
+ delete implied[t];
1791
+ }
1792
+ } else {
1793
+ scope[t] = funct;
1794
+ }
1795
+ }
1796
+
1797
+
1798
+ function doOption() {
1799
+ var b, obj, filter, o = nexttoken.value, t, tn, v;
1800
+
1801
+ switch (o) {
1802
+ case '*/':
1803
+ error("Unbegun comment.");
1804
+ break;
1805
+ case '/*members':
1806
+ case '/*member':
1807
+ o = '/*members';
1808
+ if (!membersOnly) {
1809
+ membersOnly = {};
1810
+ }
1811
+ obj = membersOnly;
1812
+ break;
1813
+ case '/*jshint':
1814
+ case '/*jslint':
1815
+ obj = option;
1816
+ filter = boolOptions;
1817
+ break;
1818
+ case '/*global':
1819
+ obj = predefined;
1820
+ break;
1821
+ default:
1822
+ error("What?");
1823
+ }
1824
+
1825
+ t = lex.token();
1826
+ loop: for (;;) {
1827
+ for (;;) {
1828
+ if (t.type === 'special' && t.value === '*/') {
1829
+ break loop;
1830
+ }
1831
+ if (t.id !== '(endline)' && t.id !== ',') {
1832
+ break;
1833
+ }
1834
+ t = lex.token();
1835
+ }
1836
+ if (t.type !== '(string)' && t.type !== '(identifier)' &&
1837
+ o !== '/*members') {
1838
+ error("Bad option.", t);
1839
+ }
1840
+
1841
+ v = lex.token();
1842
+ if (v.id === ':') {
1843
+ v = lex.token();
1844
+
1845
+ if (obj === membersOnly) {
1846
+ error("Expected '{a}' and instead saw '{b}'.",
1847
+ t, '*/', ':');
1848
+ }
1849
+
1850
+ if (o === '/*jshint') {
1851
+ checkOption(t.value, t);
1852
+ }
1853
+
1854
+ if (t.value === 'indent' && (o === '/*jshint' || o === '/*jslint')) {
1855
+ b = +v.value;
1856
+ if (typeof b !== 'number' || !isFinite(b) || b <= 0 ||
1857
+ Math.floor(b) !== b) {
1858
+ error("Expected a small integer and instead saw '{a}'.",
1859
+ v, v.value);
1860
+ }
1861
+ obj.white = true;
1862
+ obj.indent = b;
1863
+ } else if (t.value === 'maxerr' && (o === '/*jshint' || o === '/*jslint')) {
1864
+ b = +v.value;
1865
+ if (typeof b !== 'number' || !isFinite(b) || b <= 0 ||
1866
+ Math.floor(b) !== b) {
1867
+ error("Expected a small integer and instead saw '{a}'.",
1868
+ v, v.value);
1869
+ }
1870
+ obj.maxerr = b;
1871
+ } else if (t.value === 'maxlen' && (o === '/*jshint' || o === '/*jslint')) {
1872
+ b = +v.value;
1873
+ if (typeof b !== 'number' || !isFinite(b) || b <= 0 ||
1874
+ Math.floor(b) !== b) {
1875
+ error("Expected a small integer and instead saw '{a}'.",
1876
+ v, v.value);
1877
+ }
1878
+ obj.maxlen = b;
1879
+ } else if (t.value === 'validthis') {
1880
+ if (funct['(global)']) {
1881
+ error("Option 'validthis' can't be used in a global scope.");
1882
+ } else {
1883
+ if (v.value === 'true' || v.value === 'false')
1884
+ obj[t.value] = v.value === 'true';
1885
+ else
1886
+ error("Bad option value.", v);
1887
+ }
1888
+ } else if (v.value === 'true' || v.value === 'false') {
1889
+ if (o === '/*jslint') {
1890
+ tn = renamedOptions[t.value] || t.value;
1891
+ obj[tn] = v.value === 'true';
1892
+ if (invertedOptions[tn] !== undefined) {
1893
+ obj[tn] = !obj[tn];
1894
+ }
1895
+ } else {
1896
+ obj[t.value] = v.value === 'true';
1897
+ }
1898
+ } else {
1899
+ error("Bad option value.", v);
1900
+ }
1901
+ t = lex.token();
1902
+ } else {
1903
+ if (o === '/*jshint' || o === '/*jslint') {
1904
+ error("Missing option value.", t);
1905
+ }
1906
+ obj[t.value] = false;
1907
+ t = v;
1908
+ }
1909
+ }
1910
+ if (filter) {
1911
+ assume();
1912
+ }
1913
+ }
1914
+
1915
+
1916
+ // We need a peek function. If it has an argument, it peeks that much farther
1917
+ // ahead. It is used to distinguish
1918
+ // for ( var i in ...
1919
+ // from
1920
+ // for ( var i = ...
1921
+
1922
+ function peek(p) {
1923
+ var i = p || 0, j = 0, t;
1924
+
1925
+ while (j <= i) {
1926
+ t = lookahead[j];
1927
+ if (!t) {
1928
+ t = lookahead[j] = lex.token();
1929
+ }
1930
+ j += 1;
1931
+ }
1932
+ return t;
1933
+ }
1934
+
1935
+
1936
+
1937
+ // Produce the next token. It looks for programming errors.
1938
+
1939
+ function advance(id, t) {
1940
+ switch (token.id) {
1941
+ case '(number)':
1942
+ if (nexttoken.id === '.') {
1943
+ warning("A dot following a number can be confused with a decimal point.", token);
1944
+ }
1945
+ break;
1946
+ case '-':
1947
+ if (nexttoken.id === '-' || nexttoken.id === '--') {
1948
+ warning("Confusing minusses.");
1949
+ }
1950
+ break;
1951
+ case '+':
1952
+ if (nexttoken.id === '+' || nexttoken.id === '++') {
1953
+ warning("Confusing plusses.");
1954
+ }
1955
+ break;
1956
+ }
1957
+
1958
+ if (token.type === '(string)' || token.identifier) {
1959
+ anonname = token.value;
1960
+ }
1961
+
1962
+ if (id && nexttoken.id !== id) {
1963
+ if (t) {
1964
+ if (nexttoken.id === '(end)') {
1965
+ warning("Unmatched '{a}'.", t, t.id);
1966
+ } else {
1967
+ warning("Expected '{a}' to match '{b}' from line {c} and instead saw '{d}'.",
1968
+ nexttoken, id, t.id, t.line, nexttoken.value);
1969
+ }
1970
+ } else if (nexttoken.type !== '(identifier)' ||
1971
+ nexttoken.value !== id) {
1972
+ warning("Expected '{a}' and instead saw '{b}'.",
1973
+ nexttoken, id, nexttoken.value);
1974
+ }
1975
+ }
1976
+
1977
+ prevtoken = token;
1978
+ token = nexttoken;
1979
+ for (;;) {
1980
+ nexttoken = lookahead.shift() || lex.token();
1981
+ if (nexttoken.id === '(end)' || nexttoken.id === '(error)') {
1982
+ return;
1983
+ }
1984
+ if (nexttoken.type === 'special') {
1985
+ doOption();
1986
+ } else {
1987
+ if (nexttoken.id !== '(endline)') {
1988
+ break;
1989
+ }
1990
+ }
1991
+ }
1992
+ }
1993
+
1994
+
1995
+ // This is the heart of JSHINT, the Pratt parser. In addition to parsing, it
1996
+ // is looking for ad hoc lint patterns. We add .fud to Pratt's model, which is
1997
+ // like .nud except that it is only used on the first token of a statement.
1998
+ // Having .fud makes it much easier to define statement-oriented languages like
1999
+ // JavaScript. I retained Pratt's nomenclature.
2000
+
2001
+ // .nud Null denotation
2002
+ // .fud First null denotation
2003
+ // .led Left denotation
2004
+ // lbp Left binding power
2005
+ // rbp Right binding power
2006
+
2007
+ // They are elements of the parsing method called Top Down Operator Precedence.
2008
+
2009
+ function expression(rbp, initial) {
2010
+ var left, isArray = false, isObject = false;
2011
+
2012
+ if (nexttoken.id === '(end)')
2013
+ error("Unexpected early end of program.", token);
2014
+
2015
+ advance();
2016
+ if (initial) {
2017
+ anonname = 'anonymous';
2018
+ funct['(verb)'] = token.value;
2019
+ }
2020
+ if (initial === true && token.fud) {
2021
+ left = token.fud();
2022
+ } else {
2023
+ if (token.nud) {
2024
+ left = token.nud();
2025
+ } else {
2026
+ if (nexttoken.type === '(number)' && token.id === '.') {
2027
+ warning("A leading decimal point can be confused with a dot: '.{a}'.",
2028
+ token, nexttoken.value);
2029
+ advance();
2030
+ return token;
2031
+ } else {
2032
+ error("Expected an identifier and instead saw '{a}'.",
2033
+ token, token.id);
2034
+ }
2035
+ }
2036
+ while (rbp < nexttoken.lbp) {
2037
+ isArray = token.value === 'Array';
2038
+ isObject = token.value === 'Object';
2039
+
2040
+ // #527, new Foo.Array(), Foo.Array(), new Foo.Object(), Foo.Object()
2041
+ // Line breaks in IfStatement heads exist to satisfy the checkJSHint
2042
+ // "Line too long." error.
2043
+ if (left && (left.value || (left.first && left.first.value))) {
2044
+ // If the left.value is not "new", or the left.first.value is a "."
2045
+ // then safely assume that this is not "new Array()" and possibly
2046
+ // not "new Object()"...
2047
+ if (left.value !== 'new' ||
2048
+ (left.first && left.first.value && left.first.value === '.')) {
2049
+ isArray = false;
2050
+ // ...In the case of Object, if the left.value and token.value
2051
+ // are not equal, then safely assume that this not "new Object()"
2052
+ if (left.value !== token.value) {
2053
+ isObject = false;
2054
+ }
2055
+ }
2056
+ }
2057
+
2058
+ advance();
2059
+ if (isArray && token.id === '(' && nexttoken.id === ')')
2060
+ warning("Use the array literal notation [].", token);
2061
+ if (isObject && token.id === '(' && nexttoken.id === ')')
2062
+ warning("Use the object literal notation {}.", token);
2063
+ if (token.led) {
2064
+ left = token.led(left);
2065
+ } else {
2066
+ error("Expected an operator and instead saw '{a}'.",
2067
+ token, token.id);
2068
+ }
2069
+ }
2070
+ }
2071
+ return left;
2072
+ }
2073
+
2074
+
2075
+ // Functions for conformance of style.
2076
+
2077
+ function adjacent(left, right) {
2078
+ left = left || token;
2079
+ right = right || nexttoken;
2080
+ if (option.white) {
2081
+ if (left.character !== right.from && left.line === right.line) {
2082
+ left.from += (left.character - left.from);
2083
+ warning("Unexpected space after '{a}'.", left, left.value);
2084
+ }
2085
+ }
2086
+ }
2087
+
2088
+ function nobreak(left, right) {
2089
+ left = left || token;
2090
+ right = right || nexttoken;
2091
+ if (option.white && (left.character !== right.from || left.line !== right.line)) {
2092
+ warning("Unexpected space before '{a}'.", right, right.value);
2093
+ }
2094
+ }
2095
+
2096
+ function nospace(left, right) {
2097
+ left = left || token;
2098
+ right = right || nexttoken;
2099
+ if (option.white && !left.comment) {
2100
+ if (left.line === right.line) {
2101
+ adjacent(left, right);
2102
+ }
2103
+ }
2104
+ }
2105
+
2106
+ function nonadjacent(left, right) {
2107
+ if (option.white) {
2108
+ left = left || token;
2109
+ right = right || nexttoken;
2110
+ if (left.line === right.line && left.character === right.from) {
2111
+ left.from += (left.character - left.from);
2112
+ warning("Missing space after '{a}'.",
2113
+ left, left.value);
2114
+ }
2115
+ }
2116
+ }
2117
+
2118
+ function nobreaknonadjacent(left, right) {
2119
+ left = left || token;
2120
+ right = right || nexttoken;
2121
+ if (!option.laxbreak && left.line !== right.line) {
2122
+ warning("Bad line breaking before '{a}'.", right, right.id);
2123
+ } else if (option.white) {
2124
+ left = left || token;
2125
+ right = right || nexttoken;
2126
+ if (left.character === right.from) {
2127
+ left.from += (left.character - left.from);
2128
+ warning("Missing space after '{a}'.",
2129
+ left, left.value);
2130
+ }
2131
+ }
2132
+ }
2133
+
2134
+ function indentation(bias) {
2135
+ var i;
2136
+ if (option.white && nexttoken.id !== '(end)') {
2137
+ i = indent + (bias || 0);
2138
+ if (nexttoken.from !== i) {
2139
+ warning(
2140
+ "Expected '{a}' to have an indentation at {b} instead at {c}.",
2141
+ nexttoken, nexttoken.value, i, nexttoken.from);
2142
+ }
2143
+ }
2144
+ }
2145
+
2146
+ function nolinebreak(t) {
2147
+ t = t || token;
2148
+ if (t.line !== nexttoken.line) {
2149
+ warning("Line breaking error '{a}'.", t, t.value);
2150
+ }
2151
+ }
2152
+
2153
+
2154
+ function comma() {
2155
+ if (token.line !== nexttoken.line) {
2156
+ if (!option.laxcomma) {
2157
+ if (comma.first) {
2158
+ warning("Comma warnings can be turned off with 'laxcomma'");
2159
+ comma.first = false;
2160
+ }
2161
+ warning("Bad line breaking before '{a}'.", token, nexttoken.id);
2162
+ }
2163
+ } else if (!token.comment && token.character !== nexttoken.from && option.white) {
2164
+ token.from += (token.character - token.from);
2165
+ warning("Unexpected space after '{a}'.", token, token.value);
2166
+ }
2167
+ advance(',');
2168
+ nonadjacent(token, nexttoken);
2169
+ }
2170
+
2171
+
2172
+ // Functional constructors for making the symbols that will be inherited by
2173
+ // tokens.
2174
+
2175
+ function symbol(s, p) {
2176
+ var x = syntax[s];
2177
+ if (!x || typeof x !== 'object') {
2178
+ syntax[s] = x = {
2179
+ id: s,
2180
+ lbp: p,
2181
+ value: s
2182
+ };
2183
+ }
2184
+ return x;
2185
+ }
2186
+
2187
+
2188
+ function delim(s) {
2189
+ return symbol(s, 0);
2190
+ }
2191
+
2192
+
2193
+ function stmt(s, f) {
2194
+ var x = delim(s);
2195
+ x.identifier = x.reserved = true;
2196
+ x.fud = f;
2197
+ return x;
2198
+ }
2199
+
2200
+
2201
+ function blockstmt(s, f) {
2202
+ var x = stmt(s, f);
2203
+ x.block = true;
2204
+ return x;
2205
+ }
2206
+
2207
+
2208
+ function reserveName(x) {
2209
+ var c = x.id.charAt(0);
2210
+ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
2211
+ x.identifier = x.reserved = true;
2212
+ }
2213
+ return x;
2214
+ }
2215
+
2216
+
2217
+ function prefix(s, f) {
2218
+ var x = symbol(s, 150);
2219
+ reserveName(x);
2220
+ x.nud = (typeof f === 'function') ? f : function () {
2221
+ this.right = expression(150);
2222
+ this.arity = 'unary';
2223
+ if (this.id === '++' || this.id === '--') {
2224
+ if (option.plusplus) {
2225
+ warning("Unexpected use of '{a}'.", this, this.id);
2226
+ } else if ((!this.right.identifier || this.right.reserved) &&
2227
+ this.right.id !== '.' && this.right.id !== '[') {
2228
+ warning("Bad operand.", this);
2229
+ }
2230
+ }
2231
+ return this;
2232
+ };
2233
+ return x;
2234
+ }
2235
+
2236
+
2237
+ function type(s, f) {
2238
+ var x = delim(s);
2239
+ x.type = s;
2240
+ x.nud = f;
2241
+ return x;
2242
+ }
2243
+
2244
+
2245
+ function reserve(s, f) {
2246
+ var x = type(s, f);
2247
+ x.identifier = x.reserved = true;
2248
+ return x;
2249
+ }
2250
+
2251
+
2252
+ function reservevar(s, v) {
2253
+ return reserve(s, function () {
2254
+ if (typeof v === 'function') {
2255
+ v(this);
2256
+ }
2257
+ return this;
2258
+ });
2259
+ }
2260
+
2261
+
2262
+ function infix(s, f, p, w) {
2263
+ var x = symbol(s, p);
2264
+ reserveName(x);
2265
+ x.led = function (left) {
2266
+ if (!w) {
2267
+ nobreaknonadjacent(prevtoken, token);
2268
+ nonadjacent(token, nexttoken);
2269
+ }
2270
+ if (s === "in" && left.id === "!") {
2271
+ warning("Confusing use of '{a}'.", left, '!');
2272
+ }
2273
+ if (typeof f === 'function') {
2274
+ return f(left, this);
2275
+ } else {
2276
+ this.left = left;
2277
+ this.right = expression(p);
2278
+ return this;
2279
+ }
2280
+ };
2281
+ return x;
2282
+ }
2283
+
2284
+
2285
+ function relation(s, f) {
2286
+ var x = symbol(s, 100);
2287
+ x.led = function (left) {
2288
+ nobreaknonadjacent(prevtoken, token);
2289
+ nonadjacent(token, nexttoken);
2290
+ var right = expression(100);
2291
+ if ((left && left.id === 'NaN') || (right && right.id === 'NaN')) {
2292
+ warning("Use the isNaN function to compare with NaN.", this);
2293
+ } else if (f) {
2294
+ f.apply(this, [left, right]);
2295
+ }
2296
+ if (left.id === '!') {
2297
+ warning("Confusing use of '{a}'.", left, '!');
2298
+ }
2299
+ if (right.id === '!') {
2300
+ warning("Confusing use of '{a}'.", right, '!');
2301
+ }
2302
+ this.left = left;
2303
+ this.right = right;
2304
+ return this;
2305
+ };
2306
+ return x;
2307
+ }
2308
+
2309
+
2310
+ function isPoorRelation(node) {
2311
+ return node &&
2312
+ ((node.type === '(number)' && +node.value === 0) ||
2313
+ (node.type === '(string)' && node.value === '') ||
2314
+ (node.type === 'null' && !option.eqnull) ||
2315
+ node.type === 'true' ||
2316
+ node.type === 'false' ||
2317
+ node.type === 'undefined');
2318
+ }
2319
+
2320
+
2321
+ function assignop(s, f) {
2322
+ symbol(s, 20).exps = true;
2323
+ return infix(s, function (left, that) {
2324
+ var l;
2325
+ that.left = left;
2326
+ if (predefined[left.value] === false &&
2327
+ scope[left.value]['(global)'] === true) {
2328
+ warning("Read only.", left);
2329
+ } else if (left['function']) {
2330
+ warning("'{a}' is a function.", left, left.value);
2331
+ }
2332
+ if (left) {
2333
+ if (option.esnext && funct[left.value] === 'const') {
2334
+ warning("Attempting to override '{a}' which is a constant", left, left.value);
2335
+ }
2336
+ if (left.id === '.' || left.id === '[') {
2337
+ if (!left.left || left.left.value === 'arguments') {
2338
+ warning('Bad assignment.', that);
2339
+ }
2340
+ that.right = expression(19);
2341
+ return that;
2342
+ } else if (left.identifier && !left.reserved) {
2343
+ if (funct[left.value] === 'exception') {
2344
+ warning("Do not assign to the exception parameter.", left);
2345
+ }
2346
+ that.right = expression(19);
2347
+ return that;
2348
+ }
2349
+ if (left === syntax['function']) {
2350
+ warning(
2351
+ "Expected an identifier in an assignment and instead saw a function invocation.",
2352
+ token);
2353
+ }
2354
+ }
2355
+ error("Bad assignment.", that);
2356
+ }, 20);
2357
+ }
2358
+
2359
+
2360
+ function bitwise(s, f, p) {
2361
+ var x = symbol(s, p);
2362
+ reserveName(x);
2363
+ x.led = (typeof f === 'function') ? f : function (left) {
2364
+ if (option.bitwise) {
2365
+ warning("Unexpected use of '{a}'.", this, this.id);
2366
+ }
2367
+ this.left = left;
2368
+ this.right = expression(p);
2369
+ return this;
2370
+ };
2371
+ return x;
2372
+ }
2373
+
2374
+
2375
+ function bitwiseassignop(s) {
2376
+ symbol(s, 20).exps = true;
2377
+ return infix(s, function (left, that) {
2378
+ if (option.bitwise) {
2379
+ warning("Unexpected use of '{a}'.", that, that.id);
2380
+ }
2381
+ nonadjacent(prevtoken, token);
2382
+ nonadjacent(token, nexttoken);
2383
+ if (left) {
2384
+ if (left.id === '.' || left.id === '[' ||
2385
+ (left.identifier && !left.reserved)) {
2386
+ expression(19);
2387
+ return that;
2388
+ }
2389
+ if (left === syntax['function']) {
2390
+ warning(
2391
+ "Expected an identifier in an assignment, and instead saw a function invocation.",
2392
+ token);
2393
+ }
2394
+ return that;
2395
+ }
2396
+ error("Bad assignment.", that);
2397
+ }, 20);
2398
+ }
2399
+
2400
+
2401
+ function suffix(s, f) {
2402
+ var x = symbol(s, 150);
2403
+ x.led = function (left) {
2404
+ if (option.plusplus) {
2405
+ warning("Unexpected use of '{a}'.", this, this.id);
2406
+ } else if ((!left.identifier || left.reserved) &&
2407
+ left.id !== '.' && left.id !== '[') {
2408
+ warning("Bad operand.", this);
2409
+ }
2410
+ this.left = left;
2411
+ return this;
2412
+ };
2413
+ return x;
2414
+ }
2415
+
2416
+
2417
+ // fnparam means that this identifier is being defined as a function
2418
+ // argument (see identifier())
2419
+ function optionalidentifier(fnparam) {
2420
+ if (nexttoken.identifier) {
2421
+ advance();
2422
+ if (token.reserved && !option.es5) {
2423
+ // `undefined` as a function param is a common pattern to protect
2424
+ // against the case when somebody does `undefined = true` and
2425
+ // help with minification. More info: https://gist.github.com/315916
2426
+ if (!fnparam || token.value !== 'undefined') {
2427
+ warning("Expected an identifier and instead saw '{a}' (a reserved word).",
2428
+ token, token.id);
2429
+ }
2430
+ }
2431
+ return token.value;
2432
+ }
2433
+ }
2434
+
2435
+ // fnparam means that this identifier is being defined as a function
2436
+ // argument
2437
+ function identifier(fnparam) {
2438
+ var i = optionalidentifier(fnparam);
2439
+ if (i) {
2440
+ return i;
2441
+ }
2442
+ if (token.id === 'function' && nexttoken.id === '(') {
2443
+ warning("Missing name in function declaration.");
2444
+ } else {
2445
+ error("Expected an identifier and instead saw '{a}'.",
2446
+ nexttoken, nexttoken.value);
2447
+ }
2448
+ }
2449
+
2450
+
2451
+ function reachable(s) {
2452
+ var i = 0, t;
2453
+ if (nexttoken.id !== ';' || noreach) {
2454
+ return;
2455
+ }
2456
+ for (;;) {
2457
+ t = peek(i);
2458
+ if (t.reach) {
2459
+ return;
2460
+ }
2461
+ if (t.id !== '(endline)') {
2462
+ if (t.id === 'function') {
2463
+ if (!option.latedef) {
2464
+ break;
2465
+ }
2466
+ warning(
2467
+ "Inner functions should be listed at the top of the outer function.", t);
2468
+ break;
2469
+ }
2470
+ warning("Unreachable '{a}' after '{b}'.", t, t.value, s);
2471
+ break;
2472
+ }
2473
+ i += 1;
2474
+ }
2475
+ }
2476
+
2477
+
2478
+ function statement(noindent) {
2479
+ var i = indent, r, s = scope, t = nexttoken;
2480
+
2481
+ if (t.id === ";") {
2482
+ advance(";");
2483
+ return;
2484
+ }
2485
+
2486
+ // Is this a labelled statement?
2487
+
2488
+ if (t.identifier && !t.reserved && peek().id === ':') {
2489
+ advance();
2490
+ advance(':');
2491
+ scope = Object.create(s);
2492
+ addlabel(t.value, 'label');
2493
+ if (!nexttoken.labelled) {
2494
+ warning("Label '{a}' on {b} statement.",
2495
+ nexttoken, t.value, nexttoken.value);
2496
+ }
2497
+ if (jx.test(t.value + ':')) {
2498
+ warning("Label '{a}' looks like a javascript url.",
2499
+ t, t.value);
2500
+ }
2501
+ nexttoken.label = t.value;
2502
+ t = nexttoken;
2503
+ }
2504
+
2505
+ // Parse the statement.
2506
+
2507
+ if (!noindent) {
2508
+ indentation();
2509
+ }
2510
+ r = expression(0, true);
2511
+
2512
+ // Look for the final semicolon.
2513
+ if (!t.block) {
2514
+ if (!option.expr && (!r || !r.exps)) {
2515
+ warning("Expected an assignment or function call and instead saw an expression.",
2516
+ token);
2517
+ } else if (option.nonew && r.id === '(' && r.left.id === 'new') {
2518
+ warning("Do not use 'new' for side effects.");
2519
+ }
2520
+
2521
+ if (nexttoken.id === ',') {
2522
+ return comma();
2523
+ }
2524
+
2525
+ if (nexttoken.id !== ';') {
2526
+ if (!option.asi) {
2527
+ // If this is the last statement in a block that ends on
2528
+ // the same line *and* option lastsemic is on, ignore the warning.
2529
+ // Otherwise, complain about missing semicolon.
2530
+ if (!option.lastsemic || nexttoken.id !== '}' ||
2531
+ nexttoken.line !== token.line) {
2532
+ warningAt("Missing semicolon.", token.line, token.character);
2533
+ }
2534
+ }
2535
+ } else {
2536
+ adjacent(token, nexttoken);
2537
+ advance(';');
2538
+ nonadjacent(token, nexttoken);
2539
+ }
2540
+ }
2541
+
2542
+ // Restore the indentation.
2543
+
2544
+ indent = i;
2545
+ scope = s;
2546
+ return r;
2547
+ }
2548
+
2549
+
2550
+ function statements(startLine) {
2551
+ var a = [], f, p;
2552
+
2553
+ while (!nexttoken.reach && nexttoken.id !== '(end)') {
2554
+ if (nexttoken.id === ';') {
2555
+ p = peek();
2556
+ if (!p || p.id !== "(") {
2557
+ warning("Unnecessary semicolon.");
2558
+ }
2559
+ advance(';');
2560
+ } else {
2561
+ a.push(statement(startLine === nexttoken.line));
2562
+ }
2563
+ }
2564
+ return a;
2565
+ }
2566
+
2567
+
2568
+ /*
2569
+ * read all directives
2570
+ * recognizes a simple form of asi, but always
2571
+ * warns, if it is used
2572
+ */
2573
+ function directives() {
2574
+ var i, p, pn;
2575
+
2576
+ for (;;) {
2577
+ if (nexttoken.id === "(string)") {
2578
+ p = peek(0);
2579
+ if (p.id === "(endline)") {
2580
+ i = 1;
2581
+ do {
2582
+ pn = peek(i);
2583
+ i = i + 1;
2584
+ } while (pn.id === "(endline)");
2585
+
2586
+ if (pn.id !== ";") {
2587
+ if (pn.id !== "(string)" && pn.id !== "(number)" &&
2588
+ pn.id !== "(regexp)" && pn.identifier !== true &&
2589
+ pn.id !== "}") {
2590
+ break;
2591
+ }
2592
+ warning("Missing semicolon.", nexttoken);
2593
+ } else {
2594
+ p = pn;
2595
+ }
2596
+ } else if (p.id === "}") {
2597
+ // directive with no other statements, warn about missing semicolon
2598
+ warning("Missing semicolon.", p);
2599
+ } else if (p.id !== ";") {
2600
+ break;
2601
+ }
2602
+
2603
+ indentation();
2604
+ advance();
2605
+ if (directive[token.value]) {
2606
+ warning("Unnecessary directive \"{a}\".", token, token.value);
2607
+ }
2608
+
2609
+ if (token.value === "use strict") {
2610
+ option.newcap = true;
2611
+ option.undef = true;
2612
+ }
2613
+
2614
+ // there's no directive negation, so always set to true
2615
+ directive[token.value] = true;
2616
+
2617
+ if (p.id === ";") {
2618
+ advance(";");
2619
+ }
2620
+ continue;
2621
+ }
2622
+ break;
2623
+ }
2624
+ }
2625
+
2626
+
2627
+ /*
2628
+ * Parses a single block. A block is a sequence of statements wrapped in
2629
+ * braces.
2630
+ *
2631
+ * ordinary - true for everything but function bodies and try blocks.
2632
+ * stmt - true if block can be a single statement (e.g. in if/for/while).
2633
+ * isfunc - true if block is a function body
2634
+ */
2635
+ function block(ordinary, stmt, isfunc) {
2636
+ var a,
2637
+ b = inblock,
2638
+ old_indent = indent,
2639
+ m,
2640
+ s = scope,
2641
+ t,
2642
+ line,
2643
+ d;
2644
+
2645
+ inblock = ordinary;
2646
+ if (!ordinary || !option.funcscope) scope = Object.create(scope);
2647
+ nonadjacent(token, nexttoken);
2648
+ t = nexttoken;
2649
+
2650
+ if (nexttoken.id === '{') {
2651
+ advance('{');
2652
+ line = token.line;
2653
+ if (nexttoken.id !== '}') {
2654
+ indent += option.indent;
2655
+ while (!ordinary && nexttoken.from > indent) {
2656
+ indent += option.indent;
2657
+ }
2658
+
2659
+ if (isfunc) {
2660
+ m = {};
2661
+ for (d in directive) {
2662
+ if (is_own(directive, d)) {
2663
+ m[d] = directive[d];
2664
+ }
2665
+ }
2666
+ directives();
2667
+
2668
+ if (option.strict && funct['(context)']['(global)']) {
2669
+ if (!m["use strict"] && !directive["use strict"]) {
2670
+ warning("Missing \"use strict\" statement.");
2671
+ }
2672
+ }
2673
+ }
2674
+
2675
+ a = statements(line);
2676
+
2677
+ if (isfunc) {
2678
+ directive = m;
2679
+ }
2680
+
2681
+ indent -= option.indent;
2682
+ if (line !== nexttoken.line) {
2683
+ indentation();
2684
+ }
2685
+ } else if (line !== nexttoken.line) {
2686
+ indentation();
2687
+ }
2688
+ advance('}', t);
2689
+ indent = old_indent;
2690
+ } else if (!ordinary) {
2691
+ error("Expected '{a}' and instead saw '{b}'.",
2692
+ nexttoken, '{', nexttoken.value);
2693
+ } else {
2694
+ if (!stmt || option.curly)
2695
+ warning("Expected '{a}' and instead saw '{b}'.",
2696
+ nexttoken, '{', nexttoken.value);
2697
+
2698
+ noreach = true;
2699
+ indent += option.indent;
2700
+ // test indentation only if statement is in new line
2701
+ a = [statement(nexttoken.line === token.line)];
2702
+ indent -= option.indent;
2703
+ noreach = false;
2704
+ }
2705
+ funct['(verb)'] = null;
2706
+ if (!ordinary || !option.funcscope) scope = s;
2707
+ inblock = b;
2708
+ if (ordinary && option.noempty && (!a || a.length === 0)) {
2709
+ warning("Empty block.");
2710
+ }
2711
+ return a;
2712
+ }
2713
+
2714
+
2715
+ function countMember(m) {
2716
+ if (membersOnly && typeof membersOnly[m] !== 'boolean') {
2717
+ warning("Unexpected /*member '{a}'.", token, m);
2718
+ }
2719
+ if (typeof member[m] === 'number') {
2720
+ member[m] += 1;
2721
+ } else {
2722
+ member[m] = 1;
2723
+ }
2724
+ }
2725
+
2726
+
2727
+ function note_implied(token) {
2728
+ var name = token.value, line = token.line, a = implied[name];
2729
+ if (typeof a === 'function') {
2730
+ a = false;
2731
+ }
2732
+
2733
+ if (!a) {
2734
+ a = [line];
2735
+ implied[name] = a;
2736
+ } else if (a[a.length - 1] !== line) {
2737
+ a.push(line);
2738
+ }
2739
+ }
2740
+
2741
+
2742
+ // Build the syntax table by declaring the syntactic elements of the language.
2743
+
2744
+ type('(number)', function () {
2745
+ return this;
2746
+ });
2747
+
2748
+ type('(string)', function () {
2749
+ return this;
2750
+ });
2751
+
2752
+ syntax['(identifier)'] = {
2753
+ type: '(identifier)',
2754
+ lbp: 0,
2755
+ identifier: true,
2756
+ nud: function () {
2757
+ var v = this.value,
2758
+ s = scope[v],
2759
+ f;
2760
+
2761
+ if (typeof s === 'function') {
2762
+ // Protection against accidental inheritance.
2763
+ s = undefined;
2764
+ } else if (typeof s === 'boolean') {
2765
+ f = funct;
2766
+ funct = functions[0];
2767
+ addlabel(v, 'var');
2768
+ s = funct;
2769
+ funct = f;
2770
+ }
2771
+
2772
+ // The name is in scope and defined in the current function.
2773
+ if (funct === s) {
2774
+ // Change 'unused' to 'var', and reject labels.
2775
+ switch (funct[v]) {
2776
+ case 'unused':
2777
+ funct[v] = 'var';
2778
+ break;
2779
+ case 'unction':
2780
+ funct[v] = 'function';
2781
+ this['function'] = true;
2782
+ break;
2783
+ case 'function':
2784
+ this['function'] = true;
2785
+ break;
2786
+ case 'label':
2787
+ warning("'{a}' is a statement label.", token, v);
2788
+ break;
2789
+ }
2790
+ } else if (funct['(global)']) {
2791
+ // The name is not defined in the function. If we are in the global
2792
+ // scope, then we have an undefined variable.
2793
+ //
2794
+ // Operators typeof and delete do not raise runtime errors even if
2795
+ // the base object of a reference is null so no need to display warning
2796
+ // if we're inside of typeof or delete.
2797
+
2798
+ if (option.undef && typeof predefined[v] !== 'boolean') {
2799
+ // Attempting to subscript a null reference will throw an
2800
+ // error, even within the typeof and delete operators
2801
+ if (!(anonname === 'typeof' || anonname === 'delete') ||
2802
+ (nexttoken && (nexttoken.value === '.' || nexttoken.value === '['))) {
2803
+
2804
+ isundef(funct, "'{a}' is not defined.", token, v);
2805
+ }
2806
+ }
2807
+ note_implied(token);
2808
+ } else {
2809
+ // If the name is already defined in the current
2810
+ // function, but not as outer, then there is a scope error.
2811
+
2812
+ switch (funct[v]) {
2813
+ case 'closure':
2814
+ case 'function':
2815
+ case 'var':
2816
+ case 'unused':
2817
+ warning("'{a}' used out of scope.", token, v);
2818
+ break;
2819
+ case 'label':
2820
+ warning("'{a}' is a statement label.", token, v);
2821
+ break;
2822
+ case 'outer':
2823
+ case 'global':
2824
+ break;
2825
+ default:
2826
+ // If the name is defined in an outer function, make an outer entry,
2827
+ // and if it was unused, make it var.
2828
+ if (s === true) {
2829
+ funct[v] = true;
2830
+ } else if (s === null) {
2831
+ warning("'{a}' is not allowed.", token, v);
2832
+ note_implied(token);
2833
+ } else if (typeof s !== 'object') {
2834
+ // Operators typeof and delete do not raise runtime errors even
2835
+ // if the base object of a reference is null so no need to
2836
+ // display warning if we're inside of typeof or delete.
2837
+ if (option.undef) {
2838
+ // Attempting to subscript a null reference will throw an
2839
+ // error, even within the typeof and delete operators
2840
+ if (!(anonname === 'typeof' || anonname === 'delete') ||
2841
+ (nexttoken &&
2842
+ (nexttoken.value === '.' || nexttoken.value === '['))) {
2843
+
2844
+ isundef(funct, "'{a}' is not defined.", token, v);
2845
+ }
2846
+ }
2847
+ funct[v] = true;
2848
+ note_implied(token);
2849
+ } else {
2850
+ switch (s[v]) {
2851
+ case 'function':
2852
+ case 'unction':
2853
+ this['function'] = true;
2854
+ s[v] = 'closure';
2855
+ funct[v] = s['(global)'] ? 'global' : 'outer';
2856
+ break;
2857
+ case 'var':
2858
+ case 'unused':
2859
+ s[v] = 'closure';
2860
+ funct[v] = s['(global)'] ? 'global' : 'outer';
2861
+ break;
2862
+ case 'closure':
2863
+ case 'parameter':
2864
+ funct[v] = s['(global)'] ? 'global' : 'outer';
2865
+ break;
2866
+ case 'label':
2867
+ warning("'{a}' is a statement label.", token, v);
2868
+ }
2869
+ }
2870
+ }
2871
+ }
2872
+ return this;
2873
+ },
2874
+ led: function () {
2875
+ error("Expected an operator and instead saw '{a}'.",
2876
+ nexttoken, nexttoken.value);
2877
+ }
2878
+ };
2879
+
2880
+ type('(regexp)', function () {
2881
+ return this;
2882
+ });
2883
+
2884
+
2885
+ // ECMAScript parser
2886
+
2887
+ delim('(endline)');
2888
+ delim('(begin)');
2889
+ delim('(end)').reach = true;
2890
+ delim('</').reach = true;
2891
+ delim('<!');
2892
+ delim('<!--');
2893
+ delim('-->');
2894
+ delim('(error)').reach = true;
2895
+ delim('}').reach = true;
2896
+ delim(')');
2897
+ delim(']');
2898
+ delim('"').reach = true;
2899
+ delim("'").reach = true;
2900
+ delim(';');
2901
+ delim(':').reach = true;
2902
+ delim(',');
2903
+ delim('#');
2904
+ delim('@');
2905
+ reserve('else');
2906
+ reserve('case').reach = true;
2907
+ reserve('catch');
2908
+ reserve('default').reach = true;
2909
+ reserve('finally');
2910
+ reservevar('arguments', function (x) {
2911
+ if (directive['use strict'] && funct['(global)']) {
2912
+ warning("Strict violation.", x);
2913
+ }
2914
+ });
2915
+ reservevar('eval');
2916
+ reservevar('false');
2917
+ reservevar('Infinity');
2918
+ reservevar('NaN');
2919
+ reservevar('null');
2920
+ reservevar('this', function (x) {
2921
+ if (directive['use strict'] && !option.validthis && ((funct['(statement)'] &&
2922
+ funct['(name)'].charAt(0) > 'Z') || funct['(global)'])) {
2923
+ warning("Possible strict violation.", x);
2924
+ }
2925
+ });
2926
+ reservevar('true');
2927
+ reservevar('undefined');
2928
+ assignop('=', 'assign', 20);
2929
+ assignop('+=', 'assignadd', 20);
2930
+ assignop('-=', 'assignsub', 20);
2931
+ assignop('*=', 'assignmult', 20);
2932
+ assignop('/=', 'assigndiv', 20).nud = function () {
2933
+ error("A regular expression literal can be confused with '/='.");
2934
+ };
2935
+ assignop('%=', 'assignmod', 20);
2936
+ bitwiseassignop('&=', 'assignbitand', 20);
2937
+ bitwiseassignop('|=', 'assignbitor', 20);
2938
+ bitwiseassignop('^=', 'assignbitxor', 20);
2939
+ bitwiseassignop('<<=', 'assignshiftleft', 20);
2940
+ bitwiseassignop('>>=', 'assignshiftright', 20);
2941
+ bitwiseassignop('>>>=', 'assignshiftrightunsigned', 20);
2942
+ infix('?', function (left, that) {
2943
+ that.left = left;
2944
+ that.right = expression(10);
2945
+ advance(':');
2946
+ that['else'] = expression(10);
2947
+ return that;
2948
+ }, 30);
2949
+
2950
+ infix('||', 'or', 40);
2951
+ infix('&&', 'and', 50);
2952
+ bitwise('|', 'bitor', 70);
2953
+ bitwise('^', 'bitxor', 80);
2954
+ bitwise('&', 'bitand', 90);
2955
+ relation('==', function (left, right) {
2956
+ var eqnull = option.eqnull && (left.value === 'null' || right.value === 'null');
2957
+
2958
+ if (!eqnull && option.eqeqeq)
2959
+ warning("Expected '{a}' and instead saw '{b}'.", this, '===', '==');
2960
+ else if (isPoorRelation(left))
2961
+ warning("Use '{a}' to compare with '{b}'.", this, '===', left.value);
2962
+ else if (isPoorRelation(right))
2963
+ warning("Use '{a}' to compare with '{b}'.", this, '===', right.value);
2964
+
2965
+ return this;
2966
+ });
2967
+ relation('===');
2968
+ relation('!=', function (left, right) {
2969
+ var eqnull = option.eqnull &&
2970
+ (left.value === 'null' || right.value === 'null');
2971
+
2972
+ if (!eqnull && option.eqeqeq) {
2973
+ warning("Expected '{a}' and instead saw '{b}'.",
2974
+ this, '!==', '!=');
2975
+ } else if (isPoorRelation(left)) {
2976
+ warning("Use '{a}' to compare with '{b}'.",
2977
+ this, '!==', left.value);
2978
+ } else if (isPoorRelation(right)) {
2979
+ warning("Use '{a}' to compare with '{b}'.",
2980
+ this, '!==', right.value);
2981
+ }
2982
+ return this;
2983
+ });
2984
+ relation('!==');
2985
+ relation('<');
2986
+ relation('>');
2987
+ relation('<=');
2988
+ relation('>=');
2989
+ bitwise('<<', 'shiftleft', 120);
2990
+ bitwise('>>', 'shiftright', 120);
2991
+ bitwise('>>>', 'shiftrightunsigned', 120);
2992
+ infix('in', 'in', 120);
2993
+ infix('instanceof', 'instanceof', 120);
2994
+ infix('+', function (left, that) {
2995
+ var right = expression(130);
2996
+ if (left && right && left.id === '(string)' && right.id === '(string)') {
2997
+ left.value += right.value;
2998
+ left.character = right.character;
2999
+ if (!option.scripturl && jx.test(left.value)) {
3000
+ warning("JavaScript URL.", left);
3001
+ }
3002
+ return left;
3003
+ }
3004
+ that.left = left;
3005
+ that.right = right;
3006
+ return that;
3007
+ }, 130);
3008
+ prefix('+', 'num');
3009
+ prefix('+++', function () {
3010
+ warning("Confusing pluses.");
3011
+ this.right = expression(150);
3012
+ this.arity = 'unary';
3013
+ return this;
3014
+ });
3015
+ infix('+++', function (left) {
3016
+ warning("Confusing pluses.");
3017
+ this.left = left;
3018
+ this.right = expression(130);
3019
+ return this;
3020
+ }, 130);
3021
+ infix('-', 'sub', 130);
3022
+ prefix('-', 'neg');
3023
+ prefix('---', function () {
3024
+ warning("Confusing minuses.");
3025
+ this.right = expression(150);
3026
+ this.arity = 'unary';
3027
+ return this;
3028
+ });
3029
+ infix('---', function (left) {
3030
+ warning("Confusing minuses.");
3031
+ this.left = left;
3032
+ this.right = expression(130);
3033
+ return this;
3034
+ }, 130);
3035
+ infix('*', 'mult', 140);
3036
+ infix('/', 'div', 140);
3037
+ infix('%', 'mod', 140);
3038
+
3039
+ suffix('++', 'postinc');
3040
+ prefix('++', 'preinc');
3041
+ syntax['++'].exps = true;
3042
+
3043
+ suffix('--', 'postdec');
3044
+ prefix('--', 'predec');
3045
+ syntax['--'].exps = true;
3046
+ prefix('delete', function () {
3047
+ var p = expression(0);
3048
+ if (!p || (p.id !== '.' && p.id !== '[')) {
3049
+ warning("Variables should not be deleted.");
3050
+ }
3051
+ this.first = p;
3052
+ return this;
3053
+ }).exps = true;
3054
+
3055
+ prefix('~', function () {
3056
+ if (option.bitwise) {
3057
+ warning("Unexpected '{a}'.", this, '~');
3058
+ }
3059
+ expression(150);
3060
+ return this;
3061
+ });
3062
+
3063
+ prefix('!', function () {
3064
+ this.right = expression(150);
3065
+ this.arity = 'unary';
3066
+ if (bang[this.right.id] === true) {
3067
+ warning("Confusing use of '{a}'.", this, '!');
3068
+ }
3069
+ return this;
3070
+ });
3071
+ prefix('typeof', 'typeof');
3072
+ prefix('new', function () {
3073
+ var c = expression(155), i;
3074
+ if (c && c.id !== 'function') {
3075
+ if (c.identifier) {
3076
+ c['new'] = true;
3077
+ switch (c.value) {
3078
+ case 'Number':
3079
+ case 'String':
3080
+ case 'Boolean':
3081
+ case 'Math':
3082
+ case 'JSON':
3083
+ warning("Do not use {a} as a constructor.", token, c.value);
3084
+ break;
3085
+ case 'Function':
3086
+ if (!option.evil) {
3087
+ warning("The Function constructor is eval.");
3088
+ }
3089
+ break;
3090
+ case 'Date':
3091
+ case 'RegExp':
3092
+ break;
3093
+ default:
3094
+ if (c.id !== 'function') {
3095
+ i = c.value.substr(0, 1);
3096
+ if (option.newcap && (i < 'A' || i > 'Z')) {
3097
+ warning("A constructor name should start with an uppercase letter.",
3098
+ token);
3099
+ }
3100
+ }
3101
+ }
3102
+ } else {
3103
+ if (c.id !== '.' && c.id !== '[' && c.id !== '(') {
3104
+ warning("Bad constructor.", token);
3105
+ }
3106
+ }
3107
+ } else {
3108
+ if (!option.supernew)
3109
+ warning("Weird construction. Delete 'new'.", this);
3110
+ }
3111
+ adjacent(token, nexttoken);
3112
+ if (nexttoken.id !== '(' && !option.supernew) {
3113
+ warning("Missing '()' invoking a constructor.");
3114
+ }
3115
+ this.first = c;
3116
+ return this;
3117
+ });
3118
+ syntax['new'].exps = true;
3119
+
3120
+ prefix('void').exps = true;
3121
+
3122
+ infix('.', function (left, that) {
3123
+ adjacent(prevtoken, token);
3124
+ nobreak();
3125
+ var m = identifier();
3126
+ if (typeof m === 'string') {
3127
+ countMember(m);
3128
+ }
3129
+ that.left = left;
3130
+ that.right = m;
3131
+ if (left && left.value === 'arguments' && (m === 'callee' || m === 'caller')) {
3132
+ if (option.noarg)
3133
+ warning("Avoid arguments.{a}.", left, m);
3134
+ else if (directive['use strict'])
3135
+ error('Strict violation.');
3136
+ } else if (!option.evil && left && left.value === 'document' &&
3137
+ (m === 'write' || m === 'writeln')) {
3138
+ warning("document.write can be a form of eval.", left);
3139
+ }
3140
+ if (!option.evil && (m === 'eval' || m === 'execScript')) {
3141
+ warning('eval is evil.');
3142
+ }
3143
+ return that;
3144
+ }, 160, true);
3145
+
3146
+ infix('(', function (left, that) {
3147
+ if (prevtoken.id !== '}' && prevtoken.id !== ')') {
3148
+ nobreak(prevtoken, token);
3149
+ }
3150
+ nospace();
3151
+ if (option.immed && !left.immed && left.id === 'function') {
3152
+ warning("Wrap an immediate function invocation in parentheses " +
3153
+ "to assist the reader in understanding that the expression " +
3154
+ "is the result of a function, and not the function itself.");
3155
+ }
3156
+ var n = 0,
3157
+ p = [];
3158
+ if (left) {
3159
+ if (left.type === '(identifier)') {
3160
+ if (left.value.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)) {
3161
+ if (left.value !== 'Number' && left.value !== 'String' &&
3162
+ left.value !== 'Boolean' &&
3163
+ left.value !== 'Date') {
3164
+ if (left.value === 'Math') {
3165
+ warning("Math is not a function.", left);
3166
+ } else if (option.newcap) {
3167
+ warning(
3168
+ "Missing 'new' prefix when invoking a constructor.", left);
3169
+ }
3170
+ }
3171
+ }
3172
+ }
3173
+ }
3174
+ if (nexttoken.id !== ')') {
3175
+ for (;;) {
3176
+ p[p.length] = expression(10);
3177
+ n += 1;
3178
+ if (nexttoken.id !== ',') {
3179
+ break;
3180
+ }
3181
+ comma();
3182
+ }
3183
+ }
3184
+ advance(')');
3185
+ nospace(prevtoken, token);
3186
+ if (typeof left === 'object') {
3187
+ if (left.value === 'parseInt' && n === 1) {
3188
+ warning("Missing radix parameter.", left);
3189
+ }
3190
+ if (!option.evil) {
3191
+ if (left.value === 'eval' || left.value === 'Function' ||
3192
+ left.value === 'execScript') {
3193
+ warning("eval is evil.", left);
3194
+ } else if (p[0] && p[0].id === '(string)' &&
3195
+ (left.value === 'setTimeout' ||
3196
+ left.value === 'setInterval')) {
3197
+ warning(
3198
+ "Implied eval is evil. Pass a function instead of a string.", left);
3199
+ }
3200
+ }
3201
+ if (!left.identifier && left.id !== '.' && left.id !== '[' &&
3202
+ left.id !== '(' && left.id !== '&&' && left.id !== '||' &&
3203
+ left.id !== '?') {
3204
+ warning("Bad invocation.", left);
3205
+ }
3206
+ }
3207
+ that.left = left;
3208
+ return that;
3209
+ }, 155, true).exps = true;
3210
+
3211
+ prefix('(', function () {
3212
+ nospace();
3213
+ if (nexttoken.id === 'function') {
3214
+ nexttoken.immed = true;
3215
+ }
3216
+ var v = expression(0);
3217
+ advance(')', this);
3218
+ nospace(prevtoken, token);
3219
+ if (option.immed && v.id === 'function') {
3220
+ if (nexttoken.id === '(' ||
3221
+ (nexttoken.id === '.' && (peek().value === 'call' || peek().value === 'apply'))) {
3222
+ warning(
3223
+ "Move the invocation into the parens that contain the function.", nexttoken);
3224
+ } else {
3225
+ warning(
3226
+ "Do not wrap function literals in parens unless they are to be immediately invoked.",
3227
+ this);
3228
+ }
3229
+ }
3230
+ return v;
3231
+ });
3232
+
3233
+ infix('[', function (left, that) {
3234
+ nobreak(prevtoken, token);
3235
+ nospace();
3236
+ var e = expression(0), s;
3237
+ if (e && e.type === '(string)') {
3238
+ if (!option.evil && (e.value === 'eval' || e.value === 'execScript')) {
3239
+ warning("eval is evil.", that);
3240
+ }
3241
+ countMember(e.value);
3242
+ if (!option.sub && ix.test(e.value)) {
3243
+ s = syntax[e.value];
3244
+ if (!s || !s.reserved) {
3245
+ warning("['{a}'] is better written in dot notation.",
3246
+ e, e.value);
3247
+ }
3248
+ }
3249
+ }
3250
+ advance(']', that);
3251
+ nospace(prevtoken, token);
3252
+ that.left = left;
3253
+ that.right = e;
3254
+ return that;
3255
+ }, 160, true);
3256
+
3257
+ prefix('[', function () {
3258
+ var b = token.line !== nexttoken.line;
3259
+ this.first = [];
3260
+ if (b) {
3261
+ indent += option.indent;
3262
+ if (nexttoken.from === indent + option.indent) {
3263
+ indent += option.indent;
3264
+ }
3265
+ }
3266
+ while (nexttoken.id !== '(end)') {
3267
+ while (nexttoken.id === ',') {
3268
+ warning("Extra comma.");
3269
+ advance(',');
3270
+ }
3271
+ if (nexttoken.id === ']') {
3272
+ break;
3273
+ }
3274
+ if (b && token.line !== nexttoken.line) {
3275
+ indentation();
3276
+ }
3277
+ this.first.push(expression(10));
3278
+ if (nexttoken.id === ',') {
3279
+ comma();
3280
+ if (nexttoken.id === ']' && !option.es5) {
3281
+ warning("Extra comma.", token);
3282
+ break;
3283
+ }
3284
+ } else {
3285
+ break;
3286
+ }
3287
+ }
3288
+ if (b) {
3289
+ indent -= option.indent;
3290
+ indentation();
3291
+ }
3292
+ advance(']', this);
3293
+ return this;
3294
+ }, 160);
3295
+
3296
+
3297
+ function property_name() {
3298
+ var id = optionalidentifier(true);
3299
+ if (!id) {
3300
+ if (nexttoken.id === '(string)') {
3301
+ id = nexttoken.value;
3302
+ advance();
3303
+ } else if (nexttoken.id === '(number)') {
3304
+ id = nexttoken.value.toString();
3305
+ advance();
3306
+ }
3307
+ }
3308
+ return id;
3309
+ }
3310
+
3311
+
3312
+ function functionparams() {
3313
+ var i, t = nexttoken, p = [];
3314
+ advance('(');
3315
+ nospace();
3316
+ if (nexttoken.id === ')') {
3317
+ advance(')');
3318
+ return;
3319
+ }
3320
+ for (;;) {
3321
+ i = identifier(true);
3322
+ p.push(i);
3323
+ addlabel(i, 'parameter');
3324
+ if (nexttoken.id === ',') {
3325
+ comma();
3326
+ } else {
3327
+ advance(')', t);
3328
+ nospace(prevtoken, token);
3329
+ return p;
3330
+ }
3331
+ }
3332
+ }
3333
+
3334
+
3335
+ function doFunction(i, statement) {
3336
+ var f,
3337
+ oldOption = option,
3338
+ oldScope = scope;
3339
+
3340
+ option = Object.create(option);
3341
+ scope = Object.create(scope);
3342
+
3343
+ funct = {
3344
+ '(name)' : i || '"' + anonname + '"',
3345
+ '(line)' : nexttoken.line,
3346
+ '(context)' : funct,
3347
+ '(breakage)' : 0,
3348
+ '(loopage)' : 0,
3349
+ '(scope)' : scope,
3350
+ '(statement)': statement
3351
+ };
3352
+ f = funct;
3353
+ token.funct = funct;
3354
+ functions.push(funct);
3355
+ if (i) {
3356
+ addlabel(i, 'function');
3357
+ }
3358
+ funct['(params)'] = functionparams();
3359
+
3360
+ block(false, false, true);
3361
+ scope = oldScope;
3362
+ option = oldOption;
3363
+ funct['(last)'] = token.line;
3364
+ funct = funct['(context)'];
3365
+ return f;
3366
+ }
3367
+
3368
+
3369
+ (function (x) {
3370
+ x.nud = function () {
3371
+ var b, f, i, j, p, t;
3372
+ var props = {}; // All properties, including accessors
3373
+
3374
+ function saveProperty(name, token) {
3375
+ if (props[name] && is_own(props, name))
3376
+ warning("Duplicate member '{a}'.", nexttoken, i);
3377
+ else
3378
+ props[name] = {};
3379
+
3380
+ props[name].basic = true;
3381
+ props[name].basicToken = token;
3382
+ }
3383
+
3384
+ function saveSetter(name, token) {
3385
+ if (props[name] && is_own(props, name)) {
3386
+ if (props[name].basic || props[name].setter)
3387
+ warning("Duplicate member '{a}'.", nexttoken, i);
3388
+ } else {
3389
+ props[name] = {};
3390
+ }
3391
+
3392
+ props[name].setter = true;
3393
+ props[name].setterToken = token;
3394
+ }
3395
+
3396
+ function saveGetter(name) {
3397
+ if (props[name] && is_own(props, name)) {
3398
+ if (props[name].basic || props[name].getter)
3399
+ warning("Duplicate member '{a}'.", nexttoken, i);
3400
+ } else {
3401
+ props[name] = {};
3402
+ }
3403
+
3404
+ props[name].getter = true;
3405
+ props[name].getterToken = token;
3406
+ }
3407
+
3408
+ b = token.line !== nexttoken.line;
3409
+ if (b) {
3410
+ indent += option.indent;
3411
+ if (nexttoken.from === indent + option.indent) {
3412
+ indent += option.indent;
3413
+ }
3414
+ }
3415
+ for (;;) {
3416
+ if (nexttoken.id === '}') {
3417
+ break;
3418
+ }
3419
+ if (b) {
3420
+ indentation();
3421
+ }
3422
+ if (nexttoken.value === 'get' && peek().id !== ':') {
3423
+ advance('get');
3424
+ if (!option.es5) {
3425
+ error("get/set are ES5 features.");
3426
+ }
3427
+ i = property_name();
3428
+ if (!i) {
3429
+ error("Missing property name.");
3430
+ }
3431
+ saveGetter(i);
3432
+ t = nexttoken;
3433
+ adjacent(token, nexttoken);
3434
+ f = doFunction();
3435
+ p = f['(params)'];
3436
+ if (p) {
3437
+ warning("Unexpected parameter '{a}' in get {b} function.", t, p[0], i);
3438
+ }
3439
+ adjacent(token, nexttoken);
3440
+ } else if (nexttoken.value === 'set' && peek().id !== ':') {
3441
+ advance('set');
3442
+ if (!option.es5) {
3443
+ error("get/set are ES5 features.");
3444
+ }
3445
+ i = property_name();
3446
+ if (!i) {
3447
+ error("Missing property name.");
3448
+ }
3449
+ saveSetter(i, nexttoken);
3450
+ t = nexttoken;
3451
+ adjacent(token, nexttoken);
3452
+ f = doFunction();
3453
+ p = f['(params)'];
3454
+ if (!p || p.length !== 1) {
3455
+ warning("Expected a single parameter in set {a} function.", t, i);
3456
+ }
3457
+ } else {
3458
+ i = property_name();
3459
+ saveProperty(i, nexttoken);
3460
+ if (typeof i !== 'string') {
3461
+ break;
3462
+ }
3463
+ advance(':');
3464
+ nonadjacent(token, nexttoken);
3465
+ expression(10);
3466
+ }
3467
+
3468
+ countMember(i);
3469
+ if (nexttoken.id === ',') {
3470
+ comma();
3471
+ if (nexttoken.id === ',') {
3472
+ warning("Extra comma.", token);
3473
+ } else if (nexttoken.id === '}' && !option.es5) {
3474
+ warning("Extra comma.", token);
3475
+ }
3476
+ } else {
3477
+ break;
3478
+ }
3479
+ }
3480
+ if (b) {
3481
+ indent -= option.indent;
3482
+ indentation();
3483
+ }
3484
+ advance('}', this);
3485
+
3486
+ // Check for lonely setters if in the ES5 mode.
3487
+ if (option.es5) {
3488
+ for (var name in props) {
3489
+ if (is_own(props, name) && props[name].setter && !props[name].getter) {
3490
+ warning("Setter is defined without getter.", props[name].setterToken);
3491
+ }
3492
+ }
3493
+ }
3494
+ return this;
3495
+ };
3496
+ x.fud = function () {
3497
+ error("Expected to see a statement and instead saw a block.", token);
3498
+ };
3499
+ }(delim('{')));
3500
+
3501
+ // This Function is called when esnext option is set to true
3502
+ // it adds the `const` statement to JSHINT
3503
+
3504
+ useESNextSyntax = function () {
3505
+ var conststatement = stmt('const', function (prefix) {
3506
+ var id, name, value;
3507
+
3508
+ this.first = [];
3509
+ for (;;) {
3510
+ nonadjacent(token, nexttoken);
3511
+ id = identifier();
3512
+ if (funct[id] === "const") {
3513
+ warning("const '" + id + "' has already been declared");
3514
+ }
3515
+ if (funct['(global)'] && predefined[id] === false) {
3516
+ warning("Redefinition of '{a}'.", token, id);
3517
+ }
3518
+ addlabel(id, 'const');
3519
+ if (prefix) {
3520
+ break;
3521
+ }
3522
+ name = token;
3523
+ this.first.push(token);
3524
+
3525
+ if (nexttoken.id !== "=") {
3526
+ warning("const " +
3527
+ "'{a}' is initialized to 'undefined'.", token, id);
3528
+ }
3529
+
3530
+ if (nexttoken.id === '=') {
3531
+ nonadjacent(token, nexttoken);
3532
+ advance('=');
3533
+ nonadjacent(token, nexttoken);
3534
+ if (nexttoken.id === 'undefined') {
3535
+ warning("It is not necessary to initialize " +
3536
+ "'{a}' to 'undefined'.", token, id);
3537
+ }
3538
+ if (peek(0).id === '=' && nexttoken.identifier) {
3539
+ error("Constant {a} was not declared correctly.",
3540
+ nexttoken, nexttoken.value);
3541
+ }
3542
+ value = expression(0);
3543
+ name.first = value;
3544
+ }
3545
+
3546
+ if (nexttoken.id !== ',') {
3547
+ break;
3548
+ }
3549
+ comma();
3550
+ }
3551
+ return this;
3552
+ });
3553
+ conststatement.exps = true;
3554
+ };
3555
+
3556
+ var varstatement = stmt('var', function (prefix) {
3557
+ // JavaScript does not have block scope. It only has function scope. So,
3558
+ // declaring a variable in a block can have unexpected consequences.
3559
+ var id, name, value;
3560
+
3561
+ if (funct['(onevar)'] && option.onevar) {
3562
+ warning("Too many var statements.");
3563
+ } else if (!funct['(global)']) {
3564
+ funct['(onevar)'] = true;
3565
+ }
3566
+ this.first = [];
3567
+ for (;;) {
3568
+ nonadjacent(token, nexttoken);
3569
+ id = identifier();
3570
+ if (option.esnext && funct[id] === "const") {
3571
+ warning("const '" + id + "' has already been declared");
3572
+ }
3573
+ if (funct['(global)'] && predefined[id] === false) {
3574
+ warning("Redefinition of '{a}'.", token, id);
3575
+ }
3576
+ addlabel(id, 'unused');
3577
+ if (prefix) {
3578
+ break;
3579
+ }
3580
+ name = token;
3581
+ this.first.push(token);
3582
+ if (nexttoken.id === '=') {
3583
+ nonadjacent(token, nexttoken);
3584
+ advance('=');
3585
+ nonadjacent(token, nexttoken);
3586
+ if (nexttoken.id === 'undefined') {
3587
+ warning("It is not necessary to initialize '{a}' to 'undefined'.", token, id);
3588
+ }
3589
+ if (peek(0).id === '=' && nexttoken.identifier) {
3590
+ error("Variable {a} was not declared correctly.",
3591
+ nexttoken, nexttoken.value);
3592
+ }
3593
+ value = expression(0);
3594
+ name.first = value;
3595
+ }
3596
+ if (nexttoken.id !== ',') {
3597
+ break;
3598
+ }
3599
+ comma();
3600
+ }
3601
+ return this;
3602
+ });
3603
+ varstatement.exps = true;
3604
+
3605
+ blockstmt('function', function () {
3606
+ if (inblock) {
3607
+ warning("Function declarations should not be placed in blocks. " +
3608
+ "Use a function expression or move the statement to the top of " +
3609
+ "the outer function.", token);
3610
+
3611
+ }
3612
+ var i = identifier();
3613
+ if (option.esnext && funct[i] === "const") {
3614
+ warning("const '" + i + "' has already been declared");
3615
+ }
3616
+ adjacent(token, nexttoken);
3617
+ addlabel(i, 'unction');
3618
+ doFunction(i, true);
3619
+ if (nexttoken.id === '(' && nexttoken.line === token.line) {
3620
+ error(
3621
+ "Function declarations are not invocable. Wrap the whole function invocation in parens.");
3622
+ }
3623
+ return this;
3624
+ });
3625
+
3626
+ prefix('function', function () {
3627
+ var i = optionalidentifier();
3628
+ if (i) {
3629
+ adjacent(token, nexttoken);
3630
+ } else {
3631
+ nonadjacent(token, nexttoken);
3632
+ }
3633
+ doFunction(i);
3634
+ if (!option.loopfunc && funct['(loopage)']) {
3635
+ warning("Don't make functions within a loop.");
3636
+ }
3637
+ return this;
3638
+ });
3639
+
3640
+ blockstmt('if', function () {
3641
+ var t = nexttoken;
3642
+ advance('(');
3643
+ nonadjacent(this, t);
3644
+ nospace();
3645
+ expression(20);
3646
+ if (nexttoken.id === '=') {
3647
+ if (!option.boss)
3648
+ warning("Expected a conditional expression and instead saw an assignment.");
3649
+ advance('=');
3650
+ expression(20);
3651
+ }
3652
+ advance(')', t);
3653
+ nospace(prevtoken, token);
3654
+ block(true, true);
3655
+ if (nexttoken.id === 'else') {
3656
+ nonadjacent(token, nexttoken);
3657
+ advance('else');
3658
+ if (nexttoken.id === 'if' || nexttoken.id === 'switch') {
3659
+ statement(true);
3660
+ } else {
3661
+ block(true, true);
3662
+ }
3663
+ }
3664
+ return this;
3665
+ });
3666
+
3667
+ blockstmt('try', function () {
3668
+ var b, e, s;
3669
+
3670
+ block(false);
3671
+ if (nexttoken.id === 'catch') {
3672
+ advance('catch');
3673
+ nonadjacent(token, nexttoken);
3674
+ advance('(');
3675
+ s = scope;
3676
+ scope = Object.create(s);
3677
+ e = nexttoken.value;
3678
+ if (nexttoken.type !== '(identifier)') {
3679
+ warning("Expected an identifier and instead saw '{a}'.",
3680
+ nexttoken, e);
3681
+ } else {
3682
+ addlabel(e, 'exception');
3683
+ }
3684
+ advance();
3685
+ advance(')');
3686
+ block(false);
3687
+ b = true;
3688
+ scope = s;
3689
+ }
3690
+ if (nexttoken.id === 'finally') {
3691
+ advance('finally');
3692
+ block(false);
3693
+ return;
3694
+ } else if (!b) {
3695
+ error("Expected '{a}' and instead saw '{b}'.",
3696
+ nexttoken, 'catch', nexttoken.value);
3697
+ }
3698
+ return this;
3699
+ });
3700
+
3701
+ blockstmt('while', function () {
3702
+ var t = nexttoken;
3703
+ funct['(breakage)'] += 1;
3704
+ funct['(loopage)'] += 1;
3705
+ advance('(');
3706
+ nonadjacent(this, t);
3707
+ nospace();
3708
+ expression(20);
3709
+ if (nexttoken.id === '=') {
3710
+ if (!option.boss)
3711
+ warning("Expected a conditional expression and instead saw an assignment.");
3712
+ advance('=');
3713
+ expression(20);
3714
+ }
3715
+ advance(')', t);
3716
+ nospace(prevtoken, token);
3717
+ block(true, true);
3718
+ funct['(breakage)'] -= 1;
3719
+ funct['(loopage)'] -= 1;
3720
+ return this;
3721
+ }).labelled = true;
3722
+
3723
+ blockstmt('with', function () {
3724
+ var t = nexttoken;
3725
+ if (directive['use strict']) {
3726
+ error("'with' is not allowed in strict mode.", token);
3727
+ } else if (!option.withstmt) {
3728
+ warning("Don't use 'with'.", token);
3729
+ }
3730
+
3731
+ advance('(');
3732
+ nonadjacent(this, t);
3733
+ nospace();
3734
+ expression(0);
3735
+ advance(')', t);
3736
+ nospace(prevtoken, token);
3737
+ block(true, true);
3738
+
3739
+ return this;
3740
+ });
3741
+
3742
+ blockstmt('switch', function () {
3743
+ var t = nexttoken,
3744
+ g = false;
3745
+ funct['(breakage)'] += 1;
3746
+ advance('(');
3747
+ nonadjacent(this, t);
3748
+ nospace();
3749
+ this.condition = expression(20);
3750
+ advance(')', t);
3751
+ nospace(prevtoken, token);
3752
+ nonadjacent(token, nexttoken);
3753
+ t = nexttoken;
3754
+ advance('{');
3755
+ nonadjacent(token, nexttoken);
3756
+ indent += option.indent;
3757
+ this.cases = [];
3758
+ for (;;) {
3759
+ switch (nexttoken.id) {
3760
+ case 'case':
3761
+ switch (funct['(verb)']) {
3762
+ case 'break':
3763
+ case 'case':
3764
+ case 'continue':
3765
+ case 'return':
3766
+ case 'switch':
3767
+ case 'throw':
3768
+ break;
3769
+ default:
3770
+ // You can tell JSHint that you don't use break intentionally by
3771
+ // adding a comment /* falls through */ on a line just before
3772
+ // the next `case`.
3773
+ if (!ft.test(lines[nexttoken.line - 2])) {
3774
+ warning(
3775
+ "Expected a 'break' statement before 'case'.",
3776
+ token);
3777
+ }
3778
+ }
3779
+ indentation(-option.indent);
3780
+ advance('case');
3781
+ this.cases.push(expression(20));
3782
+ g = true;
3783
+ advance(':');
3784
+ funct['(verb)'] = 'case';
3785
+ break;
3786
+ case 'default':
3787
+ switch (funct['(verb)']) {
3788
+ case 'break':
3789
+ case 'continue':
3790
+ case 'return':
3791
+ case 'throw':
3792
+ break;
3793
+ default:
3794
+ if (!ft.test(lines[nexttoken.line - 2])) {
3795
+ warning(
3796
+ "Expected a 'break' statement before 'default'.",
3797
+ token);
3798
+ }
3799
+ }
3800
+ indentation(-option.indent);
3801
+ advance('default');
3802
+ g = true;
3803
+ advance(':');
3804
+ break;
3805
+ case '}':
3806
+ indent -= option.indent;
3807
+ indentation();
3808
+ advance('}', t);
3809
+ if (this.cases.length === 1 || this.condition.id === 'true' ||
3810
+ this.condition.id === 'false') {
3811
+ if (!option.onecase)
3812
+ warning("This 'switch' should be an 'if'.", this);
3813
+ }
3814
+ funct['(breakage)'] -= 1;
3815
+ funct['(verb)'] = undefined;
3816
+ return;
3817
+ case '(end)':
3818
+ error("Missing '{a}'.", nexttoken, '}');
3819
+ return;
3820
+ default:
3821
+ if (g) {
3822
+ switch (token.id) {
3823
+ case ',':
3824
+ error("Each value should have its own case label.");
3825
+ return;
3826
+ case ':':
3827
+ g = false;
3828
+ statements();
3829
+ break;
3830
+ default:
3831
+ error("Missing ':' on a case clause.", token);
3832
+ return;
3833
+ }
3834
+ } else {
3835
+ if (token.id === ':') {
3836
+ advance(':');
3837
+ error("Unexpected '{a}'.", token, ':');
3838
+ statements();
3839
+ } else {
3840
+ error("Expected '{a}' and instead saw '{b}'.",
3841
+ nexttoken, 'case', nexttoken.value);
3842
+ return;
3843
+ }
3844
+ }
3845
+ }
3846
+ }
3847
+ }).labelled = true;
3848
+
3849
+ stmt('debugger', function () {
3850
+ if (!option.debug) {
3851
+ warning("All 'debugger' statements should be removed.");
3852
+ }
3853
+ return this;
3854
+ }).exps = true;
3855
+
3856
+ (function () {
3857
+ var x = stmt('do', function () {
3858
+ funct['(breakage)'] += 1;
3859
+ funct['(loopage)'] += 1;
3860
+ this.first = block(true);
3861
+ advance('while');
3862
+ var t = nexttoken;
3863
+ nonadjacent(token, t);
3864
+ advance('(');
3865
+ nospace();
3866
+ expression(20);
3867
+ if (nexttoken.id === '=') {
3868
+ if (!option.boss)
3869
+ warning("Expected a conditional expression and instead saw an assignment.");
3870
+ advance('=');
3871
+ expression(20);
3872
+ }
3873
+ advance(')', t);
3874
+ nospace(prevtoken, token);
3875
+ funct['(breakage)'] -= 1;
3876
+ funct['(loopage)'] -= 1;
3877
+ return this;
3878
+ });
3879
+ x.labelled = true;
3880
+ x.exps = true;
3881
+ }());
3882
+
3883
+ blockstmt('for', function () {
3884
+ var s, t = nexttoken;
3885
+ funct['(breakage)'] += 1;
3886
+ funct['(loopage)'] += 1;
3887
+ advance('(');
3888
+ nonadjacent(this, t);
3889
+ nospace();
3890
+ if (peek(nexttoken.id === 'var' ? 1 : 0).id === 'in') {
3891
+ if (nexttoken.id === 'var') {
3892
+ advance('var');
3893
+ varstatement.fud.call(varstatement, true);
3894
+ } else {
3895
+ switch (funct[nexttoken.value]) {
3896
+ case 'unused':
3897
+ funct[nexttoken.value] = 'var';
3898
+ break;
3899
+ case 'var':
3900
+ break;
3901
+ default:
3902
+ warning("Bad for in variable '{a}'.",
3903
+ nexttoken, nexttoken.value);
3904
+ }
3905
+ advance();
3906
+ }
3907
+ advance('in');
3908
+ expression(20);
3909
+ advance(')', t);
3910
+ s = block(true, true);
3911
+ if (option.forin && s && (s.length > 1 || typeof s[0] !== 'object' ||
3912
+ s[0].value !== 'if')) {
3913
+ warning("The body of a for in should be wrapped in an if statement to filter " +
3914
+ "unwanted properties from the prototype.", this);
3915
+ }
3916
+ funct['(breakage)'] -= 1;
3917
+ funct['(loopage)'] -= 1;
3918
+ return this;
3919
+ } else {
3920
+ if (nexttoken.id !== ';') {
3921
+ if (nexttoken.id === 'var') {
3922
+ advance('var');
3923
+ varstatement.fud.call(varstatement);
3924
+ } else {
3925
+ for (;;) {
3926
+ expression(0, 'for');
3927
+ if (nexttoken.id !== ',') {
3928
+ break;
3929
+ }
3930
+ comma();
3931
+ }
3932
+ }
3933
+ }
3934
+ nolinebreak(token);
3935
+ advance(';');
3936
+ if (nexttoken.id !== ';') {
3937
+ expression(20);
3938
+ if (nexttoken.id === '=') {
3939
+ if (!option.boss)
3940
+ warning("Expected a conditional expression and instead saw an assignment.");
3941
+ advance('=');
3942
+ expression(20);
3943
+ }
3944
+ }
3945
+ nolinebreak(token);
3946
+ advance(';');
3947
+ if (nexttoken.id === ';') {
3948
+ error("Expected '{a}' and instead saw '{b}'.",
3949
+ nexttoken, ')', ';');
3950
+ }
3951
+ if (nexttoken.id !== ')') {
3952
+ for (;;) {
3953
+ expression(0, 'for');
3954
+ if (nexttoken.id !== ',') {
3955
+ break;
3956
+ }
3957
+ comma();
3958
+ }
3959
+ }
3960
+ advance(')', t);
3961
+ nospace(prevtoken, token);
3962
+ block(true, true);
3963
+ funct['(breakage)'] -= 1;
3964
+ funct['(loopage)'] -= 1;
3965
+ return this;
3966
+ }
3967
+ }).labelled = true;
3968
+
3969
+
3970
+ stmt('break', function () {
3971
+ var v = nexttoken.value;
3972
+
3973
+ if (funct['(breakage)'] === 0)
3974
+ warning("Unexpected '{a}'.", nexttoken, this.value);
3975
+
3976
+ if (!option.asi)
3977
+ nolinebreak(this);
3978
+
3979
+ if (nexttoken.id !== ';') {
3980
+ if (token.line === nexttoken.line) {
3981
+ if (funct[v] !== 'label') {
3982
+ warning("'{a}' is not a statement label.", nexttoken, v);
3983
+ } else if (scope[v] !== funct) {
3984
+ warning("'{a}' is out of scope.", nexttoken, v);
3985
+ }
3986
+ this.first = nexttoken;
3987
+ advance();
3988
+ }
3989
+ }
3990
+ reachable('break');
3991
+ return this;
3992
+ }).exps = true;
3993
+
3994
+
3995
+ stmt('continue', function () {
3996
+ var v = nexttoken.value;
3997
+
3998
+ if (funct['(breakage)'] === 0)
3999
+ warning("Unexpected '{a}'.", nexttoken, this.value);
4000
+
4001
+ if (!option.asi)
4002
+ nolinebreak(this);
4003
+
4004
+ if (nexttoken.id !== ';') {
4005
+ if (token.line === nexttoken.line) {
4006
+ if (funct[v] !== 'label') {
4007
+ warning("'{a}' is not a statement label.", nexttoken, v);
4008
+ } else if (scope[v] !== funct) {
4009
+ warning("'{a}' is out of scope.", nexttoken, v);
4010
+ }
4011
+ this.first = nexttoken;
4012
+ advance();
4013
+ }
4014
+ } else if (!funct['(loopage)']) {
4015
+ warning("Unexpected '{a}'.", nexttoken, this.value);
4016
+ }
4017
+ reachable('continue');
4018
+ return this;
4019
+ }).exps = true;
4020
+
4021
+
4022
+ stmt('return', function () {
4023
+ if (this.line === nexttoken.line) {
4024
+ if (nexttoken.id === '(regexp)')
4025
+ warning("Wrap the /regexp/ literal in parens to disambiguate the slash operator.");
4026
+
4027
+ if (nexttoken.id !== ';' && !nexttoken.reach) {
4028
+ nonadjacent(token, nexttoken);
4029
+ if (peek().value === "=" && !option.boss) {
4030
+ warningAt("Did you mean to return a conditional instead of an assignment?",
4031
+ token.line, token.character + 1);
4032
+ }
4033
+ this.first = expression(0);
4034
+ }
4035
+ } else if (!option.asi) {
4036
+ nolinebreak(this); // always warn (Line breaking error)
4037
+ }
4038
+ reachable('return');
4039
+ return this;
4040
+ }).exps = true;
4041
+
4042
+
4043
+ stmt('throw', function () {
4044
+ nolinebreak(this);
4045
+ nonadjacent(token, nexttoken);
4046
+ this.first = expression(20);
4047
+ reachable('throw');
4048
+ return this;
4049
+ }).exps = true;
4050
+
4051
+ // Superfluous reserved words
4052
+
4053
+ reserve('class');
4054
+ reserve('const');
4055
+ reserve('enum');
4056
+ reserve('export');
4057
+ reserve('extends');
4058
+ reserve('import');
4059
+ reserve('super');
4060
+
4061
+ reserve('let');
4062
+ reserve('yield');
4063
+ reserve('implements');
4064
+ reserve('interface');
4065
+ reserve('package');
4066
+ reserve('private');
4067
+ reserve('protected');
4068
+ reserve('public');
4069
+ reserve('static');
4070
+
4071
+
4072
+ // Parse JSON
4073
+
4074
+ function jsonValue() {
4075
+
4076
+ function jsonObject() {
4077
+ var o = {}, t = nexttoken;
4078
+ advance('{');
4079
+ if (nexttoken.id !== '}') {
4080
+ for (;;) {
4081
+ if (nexttoken.id === '(end)') {
4082
+ error("Missing '}' to match '{' from line {a}.",
4083
+ nexttoken, t.line);
4084
+ } else if (nexttoken.id === '}') {
4085
+ warning("Unexpected comma.", token);
4086
+ break;
4087
+ } else if (nexttoken.id === ',') {
4088
+ error("Unexpected comma.", nexttoken);
4089
+ } else if (nexttoken.id !== '(string)') {
4090
+ warning("Expected a string and instead saw {a}.",
4091
+ nexttoken, nexttoken.value);
4092
+ }
4093
+ if (o[nexttoken.value] === true) {
4094
+ warning("Duplicate key '{a}'.",
4095
+ nexttoken, nexttoken.value);
4096
+ } else if ((nexttoken.value === '__proto__' &&
4097
+ !option.proto) || (nexttoken.value === '__iterator__' &&
4098
+ !option.iterator)) {
4099
+ warning("The '{a}' key may produce unexpected results.",
4100
+ nexttoken, nexttoken.value);
4101
+ } else {
4102
+ o[nexttoken.value] = true;
4103
+ }
4104
+ advance();
4105
+ advance(':');
4106
+ jsonValue();
4107
+ if (nexttoken.id !== ',') {
4108
+ break;
4109
+ }
4110
+ advance(',');
4111
+ }
4112
+ }
4113
+ advance('}');
4114
+ }
4115
+
4116
+ function jsonArray() {
4117
+ var t = nexttoken;
4118
+ advance('[');
4119
+ if (nexttoken.id !== ']') {
4120
+ for (;;) {
4121
+ if (nexttoken.id === '(end)') {
4122
+ error("Missing ']' to match '[' from line {a}.",
4123
+ nexttoken, t.line);
4124
+ } else if (nexttoken.id === ']') {
4125
+ warning("Unexpected comma.", token);
4126
+ break;
4127
+ } else if (nexttoken.id === ',') {
4128
+ error("Unexpected comma.", nexttoken);
4129
+ }
4130
+ jsonValue();
4131
+ if (nexttoken.id !== ',') {
4132
+ break;
4133
+ }
4134
+ advance(',');
4135
+ }
4136
+ }
4137
+ advance(']');
4138
+ }
4139
+
4140
+ switch (nexttoken.id) {
4141
+ case '{':
4142
+ jsonObject();
4143
+ break;
4144
+ case '[':
4145
+ jsonArray();
4146
+ break;
4147
+ case 'true':
4148
+ case 'false':
4149
+ case 'null':
4150
+ case '(number)':
4151
+ case '(string)':
4152
+ advance();
4153
+ break;
4154
+ case '-':
4155
+ advance('-');
4156
+ if (token.character !== nexttoken.from) {
4157
+ warning("Unexpected space after '-'.", token);
4158
+ }
4159
+ adjacent(token, nexttoken);
4160
+ advance('(number)');
4161
+ break;
4162
+ default:
4163
+ error("Expected a JSON value.", nexttoken);
4164
+ }
4165
+ }
4166
+
4167
+
4168
+ // The actual JSHINT function itself.
4169
+
4170
+ var itself = function (s, o, g) {
4171
+ var a, i, k, x,
4172
+ optionKeys,
4173
+ newOptionObj = {};
4174
+
4175
+ JSHINT.errors = [];
4176
+ JSHINT.undefs = [];
4177
+ predefined = Object.create(standard);
4178
+ combine(predefined, g || {});
4179
+ if (o) {
4180
+ a = o.predef;
4181
+ if (a) {
4182
+ if (Array.isArray(a)) {
4183
+ for (i = 0; i < a.length; i += 1) {
4184
+ predefined[a[i]] = true;
4185
+ }
4186
+ } else if (typeof a === 'object') {
4187
+ k = Object.keys(a);
4188
+ for (i = 0; i < k.length; i += 1) {
4189
+ predefined[k[i]] = !!a[k[i]];
4190
+ }
4191
+ }
4192
+ }
4193
+ optionKeys = Object.keys(o);
4194
+ for (x = 0; x < optionKeys.length; x++) {
4195
+ newOptionObj[optionKeys[x]] = o[optionKeys[x]];
4196
+ }
4197
+ }
4198
+
4199
+ option = newOptionObj;
4200
+
4201
+ option.indent = option.indent || 4;
4202
+ option.maxerr = option.maxerr || 50;
4203
+
4204
+ tab = '';
4205
+ for (i = 0; i < option.indent; i += 1) {
4206
+ tab += ' ';
4207
+ }
4208
+ indent = 1;
4209
+ global = Object.create(predefined);
4210
+ scope = global;
4211
+ funct = {
4212
+ '(global)': true,
4213
+ '(name)': '(global)',
4214
+ '(scope)': scope,
4215
+ '(breakage)': 0,
4216
+ '(loopage)': 0
4217
+ };
4218
+ functions = [funct];
4219
+ urls = [];
4220
+ stack = null;
4221
+ member = {};
4222
+ membersOnly = null;
4223
+ implied = {};
4224
+ inblock = false;
4225
+ lookahead = [];
4226
+ jsonmode = false;
4227
+ warnings = 0;
4228
+ lex.init(s);
4229
+ prereg = true;
4230
+ directive = {};
4231
+
4232
+ prevtoken = token = nexttoken = syntax['(begin)'];
4233
+
4234
+ // Check options
4235
+ for (var name in o) {
4236
+ if (is_own(o, name)) {
4237
+ checkOption(name, token);
4238
+ }
4239
+ }
4240
+
4241
+ assume();
4242
+
4243
+ // combine the passed globals after we've assumed all our options
4244
+ combine(predefined, g || {});
4245
+
4246
+ //reset values
4247
+ comma.first = true;
4248
+ quotmark = undefined;
4249
+
4250
+ try {
4251
+ advance();
4252
+ switch (nexttoken.id) {
4253
+ case '{':
4254
+ case '[':
4255
+ option.laxbreak = true;
4256
+ jsonmode = true;
4257
+ jsonValue();
4258
+ break;
4259
+ default:
4260
+ directives();
4261
+ if (directive["use strict"] && !option.globalstrict) {
4262
+ warning("Use the function form of \"use strict\".", prevtoken);
4263
+ }
4264
+
4265
+ statements();
4266
+ }
4267
+ advance((nexttoken && nexttoken.value !== '.') ? '(end)' : undefined);
4268
+
4269
+ var markDefined = function (name, context) {
4270
+ do {
4271
+ if (typeof context[name] === 'string') {
4272
+ // JSHINT marks unused variables as 'unused' and
4273
+ // unused function declaration as 'unction'. This
4274
+ // code changes such instances back 'var' and
4275
+ // 'closure' so that the code in JSHINT.data()
4276
+ // doesn't think they're unused.
4277
+
4278
+ if (context[name] === 'unused')
4279
+ context[name] = 'var';
4280
+ else if (context[name] === 'unction')
4281
+ context[name] = 'closure';
4282
+
4283
+ return true;
4284
+ }
4285
+
4286
+ context = context['(context)'];
4287
+ } while (context);
4288
+
4289
+ return false;
4290
+ };
4291
+
4292
+ var clearImplied = function (name, line) {
4293
+ if (!implied[name])
4294
+ return;
4295
+
4296
+ var newImplied = [];
4297
+ for (var i = 0; i < implied[name].length; i += 1) {
4298
+ if (implied[name][i] !== line)
4299
+ newImplied.push(implied[name][i]);
4300
+ }
4301
+
4302
+ if (newImplied.length === 0)
4303
+ delete implied[name];
4304
+ else
4305
+ implied[name] = newImplied;
4306
+ };
4307
+
4308
+ // Check queued 'x is not defined' instances to see if they're still undefined.
4309
+ for (i = 0; i < JSHINT.undefs.length; i += 1) {
4310
+ k = JSHINT.undefs[i].slice(0);
4311
+
4312
+ if (markDefined(k[2].value, k[0])) {
4313
+ clearImplied(k[2].value, k[2].line);
4314
+ } else {
4315
+ warning.apply(warning, k.slice(1));
4316
+ }
4317
+ }
4318
+ } catch (e) {
4319
+ if (e) {
4320
+ var nt = nexttoken || {};
4321
+ JSHINT.errors.push({
4322
+ raw : e.raw,
4323
+ reason : e.message,
4324
+ line : e.line || nt.line,
4325
+ character : e.character || nt.from
4326
+ }, null);
4327
+ }
4328
+ }
4329
+
4330
+ return JSHINT.errors.length === 0;
4331
+ };
4332
+
4333
+ // Data summary.
4334
+ itself.data = function () {
4335
+
4336
+ var data = { functions: [], options: option }, fu, globals, implieds = [], f, i, j,
4337
+ members = [], n, unused = [], v;
4338
+ if (itself.errors.length) {
4339
+ data.errors = itself.errors;
4340
+ }
4341
+
4342
+ if (jsonmode) {
4343
+ data.json = true;
4344
+ }
4345
+
4346
+ for (n in implied) {
4347
+ if (is_own(implied, n)) {
4348
+ implieds.push({
4349
+ name: n,
4350
+ line: implied[n]
4351
+ });
4352
+ }
4353
+ }
4354
+ if (implieds.length > 0) {
4355
+ data.implieds = implieds;
4356
+ }
4357
+
4358
+ if (urls.length > 0) {
4359
+ data.urls = urls;
4360
+ }
4361
+
4362
+ globals = Object.keys(scope);
4363
+ if (globals.length > 0) {
4364
+ data.globals = globals;
4365
+ }
4366
+ for (i = 1; i < functions.length; i += 1) {
4367
+ f = functions[i];
4368
+ fu = {};
4369
+ for (j = 0; j < functionicity.length; j += 1) {
4370
+ fu[functionicity[j]] = [];
4371
+ }
4372
+ for (n in f) {
4373
+ if (is_own(f, n) && n.charAt(0) !== '(') {
4374
+ v = f[n];
4375
+ if (v === 'unction') {
4376
+ v = 'unused';
4377
+ }
4378
+ if (Array.isArray(fu[v])) {
4379
+ fu[v].push(n);
4380
+ if (v === 'unused') {
4381
+ unused.push({
4382
+ name: n,
4383
+ line: f['(line)'],
4384
+ 'function': f['(name)']
4385
+ });
4386
+ }
4387
+ }
4388
+ }
4389
+ }
4390
+ for (j = 0; j < functionicity.length; j += 1) {
4391
+ if (fu[functionicity[j]].length === 0) {
4392
+ delete fu[functionicity[j]];
4393
+ }
4394
+ }
4395
+ fu.name = f['(name)'];
4396
+ fu.param = f['(params)'];
4397
+ fu.line = f['(line)'];
4398
+ fu.last = f['(last)'];
4399
+ data.functions.push(fu);
4400
+ }
4401
+
4402
+ if (unused.length > 0) {
4403
+ data.unused = unused;
4404
+ }
4405
+
4406
+ members = [];
4407
+ for (n in member) {
4408
+ if (typeof member[n] === 'number') {
4409
+ data.member = member;
4410
+ break;
4411
+ }
4412
+ }
4413
+
4414
+ return data;
4415
+ };
4416
+
4417
+ itself.report = function (option) {
4418
+ var data = itself.data();
4419
+
4420
+ var a = [], c, e, err, f, i, k, l, m = '', n, o = [], s;
4421
+
4422
+ function detail(h, array) {
4423
+ var b, i, singularity;
4424
+ if (array) {
4425
+ o.push('<div><i>' + h + '</i> ');
4426
+ array = array.sort();
4427
+ for (i = 0; i < array.length; i += 1) {
4428
+ if (array[i] !== singularity) {
4429
+ singularity = array[i];
4430
+ o.push((b ? ', ' : '') + singularity);
4431
+ b = true;
4432
+ }
4433
+ }
4434
+ o.push('</div>');
4435
+ }
4436
+ }
4437
+
4438
+
4439
+ if (data.errors || data.implieds || data.unused) {
4440
+ err = true;
4441
+ o.push('<div id=errors><i>Error:</i>');
4442
+ if (data.errors) {
4443
+ for (i = 0; i < data.errors.length; i += 1) {
4444
+ c = data.errors[i];
4445
+ if (c) {
4446
+ e = c.evidence || '';
4447
+ o.push('<p>Problem' + (isFinite(c.line) ? ' at line ' +
4448
+ c.line + ' character ' + c.character : '') +
4449
+ ': ' + c.reason.entityify() +
4450
+ '</p><p class=evidence>' +
4451
+ (e && (e.length > 80 ? e.slice(0, 77) + '...' :
4452
+ e).entityify()) + '</p>');
4453
+ }
4454
+ }
4455
+ }
4456
+
4457
+ if (data.implieds) {
4458
+ s = [];
4459
+ for (i = 0; i < data.implieds.length; i += 1) {
4460
+ s[i] = '<code>' + data.implieds[i].name + '</code>&nbsp;<i>' +
4461
+ data.implieds[i].line + '</i>';
4462
+ }
4463
+ o.push('<p><i>Implied global:</i> ' + s.join(', ') + '</p>');
4464
+ }
4465
+
4466
+ if (data.unused) {
4467
+ s = [];
4468
+ for (i = 0; i < data.unused.length; i += 1) {
4469
+ s[i] = '<code><u>' + data.unused[i].name + '</u></code>&nbsp;<i>' +
4470
+ data.unused[i].line + '</i> <code>' +
4471
+ data.unused[i]['function'] + '</code>';
4472
+ }
4473
+ o.push('<p><i>Unused variable:</i> ' + s.join(', ') + '</p>');
4474
+ }
4475
+ if (data.json) {
4476
+ o.push('<p>JSON: bad.</p>');
4477
+ }
4478
+ o.push('</div>');
4479
+ }
4480
+
4481
+ if (!option) {
4482
+
4483
+ o.push('<br><div id=functions>');
4484
+
4485
+ if (data.urls) {
4486
+ detail("URLs<br>", data.urls, '<br>');
4487
+ }
4488
+
4489
+ if (data.json && !err) {
4490
+ o.push('<p>JSON: good.</p>');
4491
+ } else if (data.globals) {
4492
+ o.push('<div><i>Global</i> ' +
4493
+ data.globals.sort().join(', ') + '</div>');
4494
+ } else {
4495
+ o.push('<div><i>No new global variables introduced.</i></div>');
4496
+ }
4497
+
4498
+ for (i = 0; i < data.functions.length; i += 1) {
4499
+ f = data.functions[i];
4500
+
4501
+ o.push('<br><div class=function><i>' + f.line + '-' +
4502
+ f.last + '</i> ' + (f.name || '') + '(' +
4503
+ (f.param ? f.param.join(', ') : '') + ')</div>');
4504
+ detail('<big><b>Unused</b></big>', f.unused);
4505
+ detail('Closure', f.closure);
4506
+ detail('Variable', f['var']);
4507
+ detail('Exception', f.exception);
4508
+ detail('Outer', f.outer);
4509
+ detail('Global', f.global);
4510
+ detail('Label', f.label);
4511
+ }
4512
+
4513
+ if (data.member) {
4514
+ a = Object.keys(data.member);
4515
+ if (a.length) {
4516
+ a = a.sort();
4517
+ m = '<br><pre id=members>/*members ';
4518
+ l = 10;
4519
+ for (i = 0; i < a.length; i += 1) {
4520
+ k = a[i];
4521
+ n = k.name();
4522
+ if (l + n.length > 72) {
4523
+ o.push(m + '<br>');
4524
+ m = ' ';
4525
+ l = 1;
4526
+ }
4527
+ l += n.length + 2;
4528
+ if (data.member[k] === 1) {
4529
+ n = '<i>' + n + '</i>';
4530
+ }
4531
+ if (i < a.length - 1) {
4532
+ n += ', ';
4533
+ }
4534
+ m += n;
4535
+ }
4536
+ o.push(m + '<br>*/</pre>');
4537
+ }
4538
+ o.push('</div>');
4539
+ }
4540
+ }
4541
+ return o.join('');
4542
+ };
4543
+
4544
+ itself.jshint = itself;
4545
+
4546
+ return itself;
4547
+ }());
4548
+
4549
+ // Make JSHINT a Node module, if possible.
4550
+ if (typeof exports === 'object' && exports)
4551
+ exports.JSHINT = JSHINT;