Projet

Général

Profil

Paste
Télécharger (167 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / jquery_update / replace / ui / external / jshint.js @ 503b3f7b

1
/*!
2
 * JSHint, by JSHint Community.
3
 *
4
 * This file (and this file only) is licensed under the same slightly modified
5
 * MIT license that JSLint is. 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
 */
32

    
33
/*
34
 JSHINT is a global function. It takes two parameters.
35

36
     var myResult = JSHINT(source, option);
37

38
 The first parameter is either a string or an array of strings. If it is a
39
 string, it will be split on '\n' or '\r'. If it is an array of strings, it
40
 is assumed that each string represents one line. The source can be a
41
 JavaScript text or a JSON text.
42

43
 The second parameter is an optional object of options which control the
44
 operation of JSHINT. Most of the options are booleans: They are all
45
 optional and have a default value of false. One of the options, predef,
46
 can be an array of names, which will be used to declare global variables,
47
 or an object whose keys are used as global names, with a boolean value
48
 that determines if they are assignable.
49

50
 If it checks out, JSHINT returns true. Otherwise, it returns false.
51

52
 If false, you can inspect JSHINT.errors to find out the problems.
53
 JSHINT.errors is an array of objects containing these members:
54

55
 {
56
     line      : The line (relative to 1) at which the lint was found
57
     character : The character (relative to 1) at which the lint was found
58
     reason    : The problem
59
     evidence  : The text line in which the problem occurred
60
     raw       : The raw message before the details were inserted
61
     a         : The first detail
62
     b         : The second detail
63
     c         : The third detail
64
     d         : The fourth detail
65
 }
66

67
 If a fatal error was found, a null will be the last element of the
68
 JSHINT.errors array.
69

70
 You can request a data structure which contains JSHint's results.
71

72
     var myData = JSHINT.data();
73

74
 It returns a structure with this form:
75

76
 {
77
     errors: [
78
         {
79
             line: NUMBER,
80
             character: NUMBER,
81
             reason: STRING,
82
             evidence: STRING
83
         }
84
     ],
85
     functions: [
86
         name: STRING,
87
         line: NUMBER,
88
         character: NUMBER,
89
         last: NUMBER,
90
         lastcharacter: NUMBER,
91
         param: [
92
             STRING
93
         ],
94
         closure: [
95
             STRING
96
         ],
97
         var: [
98
             STRING
99
         ],
100
         exception: [
101
             STRING
102
         ],
103
         outer: [
104
             STRING
105
         ],
106
         unused: [
107
             STRING
108
         ],
109
         global: [
110
             STRING
111
         ],
112
         label: [
113
             STRING
114
         ]
115
     ],
116
     globals: [
117
         STRING
118
     ],
119
     member: {
120
         STRING: NUMBER
121
     },
122
     unused: [
123
         {
124
             name: STRING,
125
             line: NUMBER
126
         }
127
     ],
128
     implieds: [
129
         {
130
             name: STRING,
131
             line: NUMBER
132
         }
133
     ],
134
     urls: [
135
         STRING
136
     ],
137
     json: BOOLEAN
138
 }
139

140
 Empty arrays will not be included.
141

142
*/
143

    
144
/*jshint
145
 evil: true, nomen: false, onevar: false, regexp: false, strict: true, boss: true,
146
 undef: true, maxlen: 100, indent: 4, quotmark: double, unused: true
147
*/
148

    
149
/*members "\b", "\t", "\n", "\f", "\r", "!=", "!==", "\"", "%", "(begin)",
150
 "(breakage)", "(character)", "(context)", "(error)", "(explicitNewcap)", "(global)",
151
 "(identifier)", "(last)", "(lastcharacter)", "(line)", "(loopage)", "(metrics)",
152
 "(name)", "(onevar)", "(params)", "(scope)", "(statement)", "(verb)", "(tokens)", "(catch)",
153
 "*", "+", "++", "-", "--", "\/", "<", "<=", "==",
154
 "===", ">", ">=", $, $$, $A, $F, $H, $R, $break, $continue, $w, Abstract, Ajax,
155
 __filename, __dirname, ActiveXObject, Array, ArrayBuffer, ArrayBufferView, Audio,
156
 Autocompleter, Asset, Boolean, Builder, Buffer, Browser, Blob, COM, CScript, Canvas,
157
 CustomAnimation, Class, Control, ComplexityCount, Chain, Color, Cookie, Core, DataView, Date,
158
 Debug, Draggable, Draggables, Droppables, Document, DomReady, DOMEvent, DOMReady, DOMParser,
159
 Drag, E, Enumerator, Enumerable, Element, Elements, Error, Effect, EvalError, Event,
160
 Events, FadeAnimation, Field, Flash, Float32Array, Float64Array, Form,
161
 FormField, Frame, FormData, Function, Fx, GetObject, Group, Hash, HotKey,
162
 HTMLElement, HTMLAnchorElement, HTMLBaseElement, HTMLBlockquoteElement,
163
 HTMLBodyElement, HTMLBRElement, HTMLButtonElement, HTMLCanvasElement, HTMLDirectoryElement,
164
 HTMLDivElement, HTMLDListElement, HTMLFieldSetElement,
165
 HTMLFontElement, HTMLFormElement, HTMLFrameElement, HTMLFrameSetElement,
166
 HTMLHeadElement, HTMLHeadingElement, HTMLHRElement, HTMLHtmlElement,
167
 HTMLIFrameElement, HTMLImageElement, HTMLInputElement, HTMLIsIndexElement,
168
 HTMLLabelElement, HTMLLayerElement, HTMLLegendElement, HTMLLIElement,
169
 HTMLLinkElement, HTMLMapElement, HTMLMenuElement, HTMLMetaElement,
170
 HTMLModElement, HTMLObjectElement, HTMLOListElement, HTMLOptGroupElement,
171
 HTMLOptionElement, HTMLParagraphElement, HTMLParamElement, HTMLPreElement,
172
 HTMLQuoteElement, HTMLScriptElement, HTMLSelectElement, HTMLStyleElement,
173
 HtmlTable, HTMLTableCaptionElement, HTMLTableCellElement, HTMLTableColElement,
174
 HTMLTableElement, HTMLTableRowElement, HTMLTableSectionElement,
175
 HTMLTextAreaElement, HTMLTitleElement, HTMLUListElement, HTMLVideoElement,
176
 Iframe, IframeShim, Image, importScripts, Int16Array, Int32Array, Int8Array,
177
 Insertion, InputValidator, JSON, Keyboard, Locale, LN10, LN2, LOG10E, LOG2E,
178
 MAX_VALUE, MIN_VALUE, Map, Mask, Math, MenuItem, MessageChannel, MessageEvent, MessagePort,
179
 MoveAnimation, MooTools, MutationObserver, NaN, Native, NEGATIVE_INFINITY, Node, NodeFilter,
180
 Number, Object, ObjectRange,
181
 Option, Options, OverText, PI, POSITIVE_INFINITY, PeriodicalExecuter, Point, Position, Prototype,
182
 RangeError, Rectangle, ReferenceError, RegExp, ResizeAnimation, Request, RotateAnimation, Set,
183
 SQRT1_2, SQRT2, ScrollBar, ScriptEngine, ScriptEngineBuildVersion,
184
 ScriptEngineMajorVersion, ScriptEngineMinorVersion, Scriptaculous, Scroller,
185
 Slick, Slider, Selector, SharedWorker, String, Style, SyntaxError, Sortable, Sortables,
186
 SortableObserver, Sound, Spinner, System, Swiff, Text, TextArea, Template,
187
 Timer, Tips, Type, TypeError, Toggle, Try, "use strict", unescape, URI, URIError, URL,
188
 VBArray, WeakMap, WSH, WScript, XDomainRequest, Web, Window, XMLDOM, XMLHttpRequest, XMLSerializer,
189
 XPathEvaluator, XPathException, XPathExpression, XPathNamespace, XPathNSResolver, XPathResult,
190
 "\\", a, abs, addEventListener, address, alert, apply, applicationCache, arguments, arity,
191
 asi, atob, b, basic, basicToken, bitwise, blacklist, block, blur, boolOptions, boss,
192
 browser, btoa, c, call, callee, caller, camelcase, cases, charAt, charCodeAt, character,
193
 clearInterval, clearTimeout, close, closed, closure, comment, complexityCount, condition,
194
 confirm, console, constructor, content, couch, create, css, curly, d, data, datalist, dd, debug,
195
 decodeURI, decodeURIComponent, defaultStatus, defineClass, deserialize, devel, document,
196
 dojo, dijit, dojox, define, else, emit, encodeURI, encodeURIComponent, elem,
197
 eqeq, eqeqeq, eqnull, errors, es5, escape, esnext, eval, event, evidence, evil,
198
 ex, exception, exec, exps, expr, exports, FileReader, first, floor, focus, forEach,
199
 forin, fragment, frames, from, fromCharCode, fud, funcscope, funct, function, functions,
200
 g, gc, getComputedStyle, getRow, getter, getterToken, GLOBAL, global, globals, globalstrict,
201
 hasOwnProperty, help, history, i, id, identifier, immed, implieds, importPackage, include,
202
 indent, indexOf, init, ins, internals, instanceOf, isAlpha, isApplicationRunning, isArray,
203
 isDigit, isFinite, isNaN, iterator, java, join, jshint,
204
 JSHINT, json, jquery, jQuery, keys, label, labelled, last, lastcharacter, lastsemic, laxbreak,
205
 laxcomma, latedef, lbp, led, left, length, line, load, loadClass, localStorage, location,
206
 log, loopfunc, m, match, max, maxcomplexity, maxdepth, maxerr, maxlen, maxstatements, maxparams,
207
 member, message, meta, module, moveBy, moveTo, mootools, multistr, name, navigator, new, newcap,
208
 nestedBlockDepth, noarg, node, noempty, nomen, nonew, nonstandard, nud, onbeforeunload, onblur,
209
 onerror, onevar, onecase, onfocus, onload, onresize, onunload, open, openDatabase, openURL,
210
 opener, opera, options, outer, param, parent, parseFloat, parseInt, passfail, plusplus,
211
 postMessage, pop, predef, print, process, prompt, proto, prototype, prototypejs, provides, push,
212
 quit, quotmark, range, raw, reach, reason, regexp, readFile, readUrl, regexdash,
213
 removeEventListener, replace, report, require, reserved, resizeBy, resizeTo, resolvePath,
214
 resumeUpdates, respond, rhino, right, runCommand, scroll, scope, screen, scripturl, scrollBy,
215
 scrollTo, scrollbar, search, seal, self, send, serialize, sessionStorage, setInterval, setTimeout,
216
 setter, setterToken, shift, slice, smarttabs, sort, spawn, split, statement, statementCount, stack,
217
 status, start, strict, sub, substr, supernew, shadow, supplant, sum, sync, test, toLowerCase,
218
 toString, toUpperCase, toint32, token, tokens, top, trailing, type, typeOf, Uint16Array,
219
 Uint32Array, Uint8Array, undef, undefs, unused, urls, validthis, value, valueOf, var, vars,
220
 version, verifyMaxParametersPerFunction, verifyMaxStatementsPerFunction,
221
 verifyMaxComplexityPerFunction, verifyMaxNestedBlockDepthPerFunction, WebSocket, withstmt, white,
222
 window, windows, Worker, worker, wsh, yui, YUI, Y, YUI_config*/
223

    
224
/*global exports: false */
225

    
226
// We build the application inside a function so that we produce only a single
227
// global variable. That function will be invoked immediately, and its return
228
// value is the JSHINT function itself.
229

    
230
var JSHINT = (function () {
231
    "use strict";
232

    
233
    var anonname,       // The guessed name for anonymous functions.
234

    
235
// These are operators that should not be used with the ! operator.
236

    
237
        bang = {
238
            "<"  : true,
239
            "<=" : true,
240
            "==" : true,
241
            "===": true,
242
            "!==": true,
243
            "!=" : true,
244
            ">"  : true,
245
            ">=" : true,
246
            "+"  : true,
247
            "-"  : true,
248
            "*"  : true,
249
            "/"  : true,
250
            "%"  : true
251
        },
252

    
253
        // These are the JSHint boolean options.
254
        boolOptions = {
255
            asi         : true, // if automatic semicolon insertion should be tolerated
256
            bitwise     : true, // if bitwise operators should not be allowed
257
            boss        : true, // if advanced usage of assignments should be allowed
258
            browser     : true, // if the standard browser globals should be predefined
259
            camelcase   : true, // if identifiers should be required in camel case
260
            couch       : true, // if CouchDB globals should be predefined
261
            curly       : true, // if curly braces around all blocks should be required
262
            debug       : true, // if debugger statements should be allowed
263
            devel       : true, // if logging globals should be predefined (console,
264
                                // alert, etc.)
265
            dojo        : true, // if Dojo Toolkit globals should be predefined
266
            eqeqeq      : true, // if === should be required
267
            eqnull      : true, // if == null comparisons should be tolerated
268
            es5         : true, // if ES5 syntax should be allowed
269
            esnext      : true, // if es.next specific syntax should be allowed
270
            evil        : true, // if eval should be allowed
271
            expr        : true, // if ExpressionStatement should be allowed as Programs
272
            forin       : true, // if for in statements must filter
273
            funcscope   : true, // if only function scope should be used for scope tests
274
            globalstrict: true, // if global "use strict"; should be allowed (also
275
                                // enables 'strict')
276
            immed       : true, // if immediate invocations must be wrapped in parens
277
            iterator    : true, // if the `__iterator__` property should be allowed
278
            jquery      : true, // if jQuery globals should be predefined
279
            lastsemic   : true, // if semicolons may be ommitted for the trailing
280
                                // statements inside of a one-line blocks.
281
            latedef     : true, // if the use before definition should not be tolerated
282
            laxbreak    : true, // if line breaks should not be checked
283
            laxcomma    : true, // if line breaks should not be checked around commas
284
            loopfunc    : true, // if functions should be allowed to be defined within
285
                                // loops
286
            mootools    : true, // if MooTools globals should be predefined
287
            multistr    : true, // allow multiline strings
288
            newcap      : true, // if constructor names must be capitalized
289
            noarg       : true, // if arguments.caller and arguments.callee should be
290
                                // disallowed
291
            node        : true, // if the Node.js environment globals should be
292
                                // predefined
293
            noempty     : true, // if empty blocks should be disallowed
294
            nonew       : true, // if using `new` for side-effects should be disallowed
295
            nonstandard : true, // if non-standard (but widely adopted) globals should
296
                                // be predefined
297
            nomen       : true, // if names should be checked
298
            onevar      : true, // if only one var statement per function should be
299
                                // allowed
300
            onecase     : true, // if one case switch statements should be allowed
301
            passfail    : true, // if the scan should stop on first error
302
            plusplus    : true, // if increment/decrement should not be allowed
303
            proto       : true, // if the `__proto__` property should be allowed
304
            prototypejs : true, // if Prototype and Scriptaculous globals should be
305
                                // predefined
306
            regexdash   : true, // if unescaped first/last dash (-) inside brackets
307
                                // should be tolerated
308
            regexp      : true, // if the . should not be allowed in regexp literals
309
            rhino       : true, // if the Rhino environment globals should be predefined
310
            undef       : true, // if variables should be declared before used
311
            unused      : true, // if variables should be always used
312
            scripturl   : true, // if script-targeted URLs should be tolerated
313
            shadow      : true, // if variable shadowing should be tolerated
314
            smarttabs   : true, // if smarttabs should be tolerated
315
                                // (http://www.emacswiki.org/emacs/SmartTabs)
316
            strict      : true, // require the "use strict"; pragma
317
            sub         : true, // if all forms of subscript notation are tolerated
318
            supernew    : true, // if `new function () { ... };` and `new Object;`
319
                                // should be tolerated
320
            trailing    : true, // if trailing whitespace rules apply
321
            validthis   : true, // if 'this' inside a non-constructor function is valid.
322
                                // This is a function scoped option only.
323
            withstmt    : true, // if with statements should be allowed
324
            white       : true, // if strict whitespace rules apply
325
            worker      : true, // if Web Worker script symbols should be allowed
326
            wsh         : true, // if the Windows Scripting Host environment globals
327
                                // should be predefined
328
            yui         : true  // YUI variables should be predefined
329
        },
330

    
331
        // These are the JSHint options that can take any value
332
        // (we use this object to detect invalid options)
333
        valOptions = {
334
            maxlen       : false,
335
            indent       : false,
336
            maxerr       : false,
337
            predef       : false,
338
            quotmark     : false, //'single'|'double'|true
339
            scope        : false,
340
            maxstatements: false, // {int} max statements per function
341
            maxdepth     : false, // {int} max nested block depth per function
342
            maxparams    : false, // {int} max params per function
343
            maxcomplexity: false  // {int} max cyclomatic complexity per function
344
        },
345

    
346
        // These are JSHint boolean options which are shared with JSLint
347
        // where the definition in JSHint is opposite JSLint
348
        invertedOptions = {
349
            bitwise     : true,
350
            forin       : true,
351
            newcap      : true,
352
            nomen       : true,
353
            plusplus    : true,
354
            regexp      : true,
355
            undef       : true,
356
            white       : true,
357

    
358
            // Inverted and renamed, use JSHint name here
359
            eqeqeq      : true,
360
            onevar      : true
361
        },
362

    
363
        // These are JSHint boolean options which are shared with JSLint
364
        // where the name has been changed but the effect is unchanged
365
        renamedOptions = {
366
            eqeq        : "eqeqeq",
367
            vars        : "onevar",
368
            windows     : "wsh"
369
        },
370

    
371

    
372
        // browser contains a set of global names which are commonly provided by a
373
        // web browser environment.
374
        browser = {
375
            ArrayBuffer              :  false,
376
            ArrayBufferView          :  false,
377
            Audio                    :  false,
378
            Blob                     :  false,
379
            addEventListener         :  false,
380
            applicationCache         :  false,
381
            atob                     :  false,
382
            blur                     :  false,
383
            btoa                     :  false,
384
            clearInterval            :  false,
385
            clearTimeout             :  false,
386
            close                    :  false,
387
            closed                   :  false,
388
            DataView                 :  false,
389
            DOMParser                :  false,
390
            defaultStatus            :  false,
391
            document                 :  false,
392
            event                    :  false,
393
            FileReader               :  false,
394
            Float32Array             :  false,
395
            Float64Array             :  false,
396
            FormData                 :  false,
397
            focus                    :  false,
398
            frames                   :  false,
399
            getComputedStyle         :  false,
400
            HTMLElement              :  false,
401
            HTMLAnchorElement        :  false,
402
            HTMLBaseElement          :  false,
403
            HTMLBlockquoteElement    :  false,
404
            HTMLBodyElement          :  false,
405
            HTMLBRElement            :  false,
406
            HTMLButtonElement        :  false,
407
            HTMLCanvasElement        :  false,
408
            HTMLDirectoryElement     :  false,
409
            HTMLDivElement           :  false,
410
            HTMLDListElement         :  false,
411
            HTMLFieldSetElement      :  false,
412
            HTMLFontElement          :  false,
413
            HTMLFormElement          :  false,
414
            HTMLFrameElement         :  false,
415
            HTMLFrameSetElement      :  false,
416
            HTMLHeadElement          :  false,
417
            HTMLHeadingElement       :  false,
418
            HTMLHRElement            :  false,
419
            HTMLHtmlElement          :  false,
420
            HTMLIFrameElement        :  false,
421
            HTMLImageElement         :  false,
422
            HTMLInputElement         :  false,
423
            HTMLIsIndexElement       :  false,
424
            HTMLLabelElement         :  false,
425
            HTMLLayerElement         :  false,
426
            HTMLLegendElement        :  false,
427
            HTMLLIElement            :  false,
428
            HTMLLinkElement          :  false,
429
            HTMLMapElement           :  false,
430
            HTMLMenuElement          :  false,
431
            HTMLMetaElement          :  false,
432
            HTMLModElement           :  false,
433
            HTMLObjectElement        :  false,
434
            HTMLOListElement         :  false,
435
            HTMLOptGroupElement      :  false,
436
            HTMLOptionElement        :  false,
437
            HTMLParagraphElement     :  false,
438
            HTMLParamElement         :  false,
439
            HTMLPreElement           :  false,
440
            HTMLQuoteElement         :  false,
441
            HTMLScriptElement        :  false,
442
            HTMLSelectElement        :  false,
443
            HTMLStyleElement         :  false,
444
            HTMLTableCaptionElement  :  false,
445
            HTMLTableCellElement     :  false,
446
            HTMLTableColElement      :  false,
447
            HTMLTableElement         :  false,
448
            HTMLTableRowElement      :  false,
449
            HTMLTableSectionElement  :  false,
450
            HTMLTextAreaElement      :  false,
451
            HTMLTitleElement         :  false,
452
            HTMLUListElement         :  false,
453
            HTMLVideoElement         :  false,
454
            history                  :  false,
455
            Int16Array               :  false,
456
            Int32Array               :  false,
457
            Int8Array                :  false,
458
            Image                    :  false,
459
            length                   :  false,
460
            localStorage             :  false,
461
            location                 :  false,
462
            MessageChannel           :  false,
463
            MessageEvent             :  false,
464
            MessagePort              :  false,
465
            moveBy                   :  false,
466
            moveTo                   :  false,
467
            MutationObserver         :  false,
468
            name                     :  false,
469
            Node                     :  false,
470
            NodeFilter               :  false,
471
            navigator                :  false,
472
            onbeforeunload           :  true,
473
            onblur                   :  true,
474
            onerror                  :  true,
475
            onfocus                  :  true,
476
            onload                   :  true,
477
            onresize                 :  true,
478
            onunload                 :  true,
479
            open                     :  false,
480
            openDatabase             :  false,
481
            opener                   :  false,
482
            Option                   :  false,
483
            parent                   :  false,
484
            print                    :  false,
485
            removeEventListener      :  false,
486
            resizeBy                 :  false,
487
            resizeTo                 :  false,
488
            screen                   :  false,
489
            scroll                   :  false,
490
            scrollBy                 :  false,
491
            scrollTo                 :  false,
492
            sessionStorage           :  false,
493
            setInterval              :  false,
494
            setTimeout               :  false,
495
            SharedWorker             :  false,
496
            status                   :  false,
497
            top                      :  false,
498
            Uint16Array              :  false,
499
            Uint32Array              :  false,
500
            Uint8Array               :  false,
501
            WebSocket                :  false,
502
            window                   :  false,
503
            Worker                   :  false,
504
            XMLHttpRequest           :  false,
505
            XMLSerializer            :  false,
506
            XPathEvaluator           :  false,
507
            XPathException           :  false,
508
            XPathExpression          :  false,
509
            XPathNamespace           :  false,
510
            XPathNSResolver          :  false,
511
            XPathResult              :  false
512
        },
513

    
514
        couch = {
515
            "require" : false,
516
            respond   : false,
517
            getRow    : false,
518
            emit      : false,
519
            send      : false,
520
            start     : false,
521
            sum       : false,
522
            log       : false,
523
            exports   : false,
524
            module    : false,
525
            provides  : false
526
        },
527

    
528
        declared, // Globals that were declared using /*global ... */ syntax.
529

    
530
        devel = {
531
            alert   : false,
532
            confirm : false,
533
            console : false,
534
            Debug   : false,
535
            opera   : false,
536
            prompt  : false
537
        },
538

    
539
        dojo = {
540
            dojo      : false,
541
            dijit     : false,
542
            dojox     : false,
543
            define    : false,
544
            "require" : false
545
        },
546

    
547
        funct,          // The current function
548

    
549
        functionicity = [
550
            "closure", "exception", "global", "label",
551
            "outer", "unused", "var"
552
        ],
553

    
554
        functions,      // All of the functions
555

    
556
        global,         // The global scope
557
        implied,        // Implied globals
558
        inblock,
559
        indent,
560
        jsonmode,
561

    
562
        jquery = {
563
            "$"    : false,
564
            jQuery : false
565
        },
566

    
567
        lines,
568
        lookahead,
569
        member,
570
        membersOnly,
571

    
572
        mootools = {
573
            "$"             : false,
574
            "$$"            : false,
575
            Asset           : false,
576
            Browser         : false,
577
            Chain           : false,
578
            Class           : false,
579
            Color           : false,
580
            Cookie          : false,
581
            Core            : false,
582
            Document        : false,
583
            DomReady        : false,
584
            DOMEvent        : false,
585
            DOMReady        : false,
586
            Drag            : false,
587
            Element         : false,
588
            Elements        : false,
589
            Event           : false,
590
            Events          : false,
591
            Fx              : false,
592
            Group           : false,
593
            Hash            : false,
594
            HtmlTable       : false,
595
            Iframe          : false,
596
            IframeShim      : false,
597
            InputValidator  : false,
598
            instanceOf      : false,
599
            Keyboard        : false,
600
            Locale          : false,
601
            Mask            : false,
602
            MooTools        : false,
603
            Native          : false,
604
            Options         : false,
605
            OverText        : false,
606
            Request         : false,
607
            Scroller        : false,
608
            Slick           : false,
609
            Slider          : false,
610
            Sortables       : false,
611
            Spinner         : false,
612
            Swiff           : false,
613
            Tips            : false,
614
            Type            : false,
615
            typeOf          : false,
616
            URI             : false,
617
            Window          : false
618
        },
619

    
620
        nexttoken,
621

    
622
        node = {
623
            __filename    : false,
624
            __dirname     : false,
625
            Buffer        : false,
626
            console       : false,
627
            exports       : true,  // In Node it is ok to exports = module.exports = foo();
628
            GLOBAL        : false,
629
            global        : false,
630
            module        : false,
631
            process       : false,
632
            require       : false,
633
            setTimeout    : false,
634
            clearTimeout  : false,
635
            setInterval   : false,
636
            clearInterval : false
637
        },
638

    
639
        noreach,
640
        option,
641
        predefined,     // Global variables defined by option
642
        prereg,
643
        prevtoken,
644

    
645
        prototypejs = {
646
            "$"               : false,
647
            "$$"              : false,
648
            "$A"              : false,
649
            "$F"              : false,
650
            "$H"              : false,
651
            "$R"              : false,
652
            "$break"          : false,
653
            "$continue"       : false,
654
            "$w"              : false,
655
            Abstract          : false,
656
            Ajax              : false,
657
            Class             : false,
658
            Enumerable        : false,
659
            Element           : false,
660
            Event             : false,
661
            Field             : false,
662
            Form              : false,
663
            Hash              : false,
664
            Insertion         : false,
665
            ObjectRange       : false,
666
            PeriodicalExecuter: false,
667
            Position          : false,
668
            Prototype         : false,
669
            Selector          : false,
670
            Template          : false,
671
            Toggle            : false,
672
            Try               : false,
673
            Autocompleter     : false,
674
            Builder           : false,
675
            Control           : false,
676
            Draggable         : false,
677
            Draggables        : false,
678
            Droppables        : false,
679
            Effect            : false,
680
            Sortable          : false,
681
            SortableObserver  : false,
682
            Sound             : false,
683
            Scriptaculous     : false
684
        },
685

    
686
        quotmark,
687

    
688
        rhino = {
689
            defineClass  : false,
690
            deserialize  : false,
691
            gc           : false,
692
            help         : false,
693
            importPackage: false,
694
            "java"       : false,
695
            load         : false,
696
            loadClass    : false,
697
            print        : false,
698
            quit         : false,
699
            readFile     : false,
700
            readUrl      : false,
701
            runCommand   : false,
702
            seal         : false,
703
            serialize    : false,
704
            spawn        : false,
705
            sync         : false,
706
            toint32      : false,
707
            version      : false
708
        },
709

    
710
        scope,      // The current scope
711
        stack,
712

    
713
        // standard contains the global names that are provided by the
714
        // ECMAScript standard.
715
        standard = {
716
            Array               : false,
717
            Boolean             : false,
718
            Date                : false,
719
            decodeURI           : false,
720
            decodeURIComponent  : false,
721
            encodeURI           : false,
722
            encodeURIComponent  : false,
723
            Error               : false,
724
            "eval"              : false,
725
            EvalError           : false,
726
            Function            : false,
727
            hasOwnProperty      : false,
728
            isFinite            : false,
729
            isNaN               : false,
730
            JSON                : false,
731
            Map                 : false,
732
            Math                : false,
733
            NaN                 : false,
734
            Number              : false,
735
            Object              : false,
736
            parseInt            : false,
737
            parseFloat          : false,
738
            RangeError          : false,
739
            ReferenceError      : false,
740
            RegExp              : false,
741
            Set                 : false,
742
            String              : false,
743
            SyntaxError         : false,
744
            TypeError           : false,
745
            URIError            : false,
746
            WeakMap             : false
747
        },
748

    
749
        // widely adopted global names that are not part of ECMAScript standard
750
        nonstandard = {
751
            escape              : false,
752
            unescape            : false
753
        },
754

    
755
        directive,
756
        syntax = {},
757
        tab,
758
        token,
759
        unuseds,
760
        urls,
761
        useESNextSyntax,
762
        warnings,
763

    
764
        worker = {
765
            importScripts       : true,
766
            postMessage         : true,
767
            self                : true
768
        },
769

    
770
        wsh = {
771
            ActiveXObject             : true,
772
            Enumerator                : true,
773
            GetObject                 : true,
774
            ScriptEngine              : true,
775
            ScriptEngineBuildVersion  : true,
776
            ScriptEngineMajorVersion  : true,
777
            ScriptEngineMinorVersion  : true,
778
            VBArray                   : true,
779
            WSH                       : true,
780
            WScript                   : true,
781
            XDomainRequest            : true
782
        },
783

    
784
        yui = {
785
            YUI             : false,
786
            Y               : false,
787
            YUI_config      : false
788
        };
789
    // Regular expressions. Some of these are stupidly long.
790
    var ax, cx, tx, nx, nxg, lx, ix, jx, ft;
791
    (function () {
792
        /*jshint maxlen:300 */
793

    
794
        // unsafe comment or string
795
        ax = /@cc|<\/?|script|\]\s*\]|<\s*!|&lt/i;
796

    
797
        // unsafe characters that are silently deleted by one or more browsers
798
        cx = /[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/;
799

    
800
        // token
801
        tx = /^\s*([(){}\[.,:;'"~\?\]#@]|==?=?|\/=(?!(\S*\/[gim]?))|\/(\*(jshint|jslint|members?|global)?|\/)?|\*[\/=]?|\+(?:=|\++)?|-(?:=|-+)?|%=?|&[&=]?|\|[|=]?|>>?>?=?|<([\/=!]|\!(\[|--)?|<=?)?|\^=?|\!=?=?|[a-zA-Z_$][a-zA-Z0-9_$]*|[0-9]+([xX][0-9a-fA-F]+|\.[0-9]*)?([eE][+\-]?[0-9]+)?)/;
802

    
803
        // characters in strings that need escapement
804
        nx = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/;
805
        nxg = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
806

    
807
        // star slash
808
        lx = /\*\//;
809

    
810
        // identifier
811
        ix = /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/;
812

    
813
        // javascript url
814
        jx = /^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i;
815

    
816
        // catches /* falls through */ comments
817
        ft = /^\s*\/\*\s*falls\sthrough\s*\*\/\s*$/;
818
    }());
819

    
820
    function F() {}     // Used by Object.create
821

    
822
    function is_own(object, name) {
823
        // The object.hasOwnProperty method fails when the property under consideration
824
        // is named 'hasOwnProperty'. So we have to use this more convoluted form.
825
        return Object.prototype.hasOwnProperty.call(object, name);
826
    }
827

    
828
    function checkOption(name, t) {
829
        if (valOptions[name] === undefined && boolOptions[name] === undefined) {
830
            warning("Bad option: '" + name + "'.", t);
831
        }
832
    }
833

    
834
    function isString(obj) {
835
        return Object.prototype.toString.call(obj) === "[object String]";
836
    }
837

    
838
    // Provide critical ES5 functions to ES3.
839

    
840
    if (typeof Array.isArray !== "function") {
841
        Array.isArray = function (o) {
842
            return Object.prototype.toString.apply(o) === "[object Array]";
843
        };
844
    }
845

    
846
    if (!Array.prototype.forEach) {
847
        Array.prototype.forEach = function (fn, scope) {
848
            var len = this.length;
849

    
850
            for (var i = 0; i < len; i++) {
851
                fn.call(scope || this, this[i], i, this);
852
            }
853
        };
854
    }
855

    
856
    if (!Array.prototype.indexOf) {
857
        Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
858
            if (this === null || this === undefined) {
859
                throw new TypeError();
860
            }
861

    
862
            var t = new Object(this);
863
            var len = t.length >>> 0;
864

    
865
            if (len === 0) {
866
                return -1;
867
            }
868

    
869
            var n = 0;
870
            if (arguments.length > 0) {
871
                n = Number(arguments[1]);
872
                if (n != n) { // shortcut for verifying if it's NaN
873
                    n = 0;
874
                } else if (n !== 0 && n != Infinity && n != -Infinity) {
875
                    n = (n > 0 || -1) * Math.floor(Math.abs(n));
876
                }
877
            }
878

    
879
            if (n >= len) {
880
                return -1;
881
            }
882

    
883
            var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
884
            for (; k < len; k++) {
885
                if (k in t && t[k] === searchElement) {
886
                    return k;
887
                }
888
            }
889

    
890
            return -1;
891
        };
892
    }
893

    
894
    if (typeof Object.create !== "function") {
895
        Object.create = function (o) {
896
            F.prototype = o;
897
            return new F();
898
        };
899
    }
900

    
901
    if (typeof Object.keys !== "function") {
902
        Object.keys = function (o) {
903
            var a = [], k;
904
            for (k in o) {
905
                if (is_own(o, k)) {
906
                    a.push(k);
907
                }
908
            }
909
            return a;
910
        };
911
    }
912

    
913
    // Non standard methods
914

    
915
    function isAlpha(str) {
916
        return (str >= "a" && str <= "z\uffff") ||
917
            (str >= "A" && str <= "Z\uffff");
918
    }
919

    
920
    function isDigit(str) {
921
        return (str >= "0" && str <= "9");
922
    }
923

    
924
    function isIdentifier(token, value) {
925
        if (!token)
926
            return false;
927

    
928
        if (!token.identifier || token.value !== value)
929
            return false;
930

    
931
        return true;
932
    }
933

    
934
    function supplant(str, data) {
935
        return str.replace(/\{([^{}]*)\}/g, function (a, b) {
936
            var r = data[b];
937
            return typeof r === "string" || typeof r === "number" ? r : a;
938
        });
939
    }
940

    
941
    function combine(t, o) {
942
        var n;
943
        for (n in o) {
944
            if (is_own(o, n) && !is_own(JSHINT.blacklist, n)) {
945
                t[n] = o[n];
946
            }
947
        }
948
    }
949

    
950
    function updatePredefined() {
951
        Object.keys(JSHINT.blacklist).forEach(function (key) {
952
            delete predefined[key];
953
        });
954
    }
955

    
956
    function assume() {
957
        if (option.couch) {
958
            combine(predefined, couch);
959
        }
960

    
961
        if (option.rhino) {
962
            combine(predefined, rhino);
963
        }
964

    
965
        if (option.prototypejs) {
966
            combine(predefined, prototypejs);
967
        }
968

    
969
        if (option.node) {
970
            combine(predefined, node);
971
            option.globalstrict = true;
972
        }
973

    
974
        if (option.devel) {
975
            combine(predefined, devel);
976
        }
977

    
978
        if (option.dojo) {
979
            combine(predefined, dojo);
980
        }
981

    
982
        if (option.browser) {
983
            combine(predefined, browser);
984
        }
985

    
986
        if (option.nonstandard) {
987
            combine(predefined, nonstandard);
988
        }
989

    
990
        if (option.jquery) {
991
            combine(predefined, jquery);
992
        }
993

    
994
        if (option.mootools) {
995
            combine(predefined, mootools);
996
        }
997

    
998
        if (option.worker) {
999
            combine(predefined, worker);
1000
        }
1001

    
1002
        if (option.wsh) {
1003
            combine(predefined, wsh);
1004
        }
1005

    
1006
        if (option.esnext) {
1007
            useESNextSyntax();
1008
        }
1009

    
1010
        if (option.globalstrict && option.strict !== false) {
1011
            option.strict = true;
1012
        }
1013

    
1014
        if (option.yui) {
1015
            combine(predefined, yui);
1016
        }
1017
    }
1018

    
1019

    
1020
    // Produce an error warning.
1021
    function quit(message, line, chr) {
1022
        var percentage = Math.floor((line / lines.length) * 100);
1023

    
1024
        throw {
1025
            name: "JSHintError",
1026
            line: line,
1027
            character: chr,
1028
            message: message + " (" + percentage + "% scanned).",
1029
            raw: message
1030
        };
1031
    }
1032

    
1033
    function isundef(scope, m, t, a) {
1034
        return JSHINT.undefs.push([scope, m, t, a]);
1035
    }
1036

    
1037
    function warning(m, t, a, b, c, d) {
1038
        var ch, l, w;
1039
        t = t || nexttoken;
1040
        if (t.id === "(end)") {  // `~
1041
            t = token;
1042
        }
1043
        l = t.line || 0;
1044
        ch = t.from || 0;
1045
        w = {
1046
            id: "(error)",
1047
            raw: m,
1048
            evidence: lines[l - 1] || "",
1049
            line: l,
1050
            character: ch,
1051
            scope: JSHINT.scope,
1052
            a: a,
1053
            b: b,
1054
            c: c,
1055
            d: d
1056
        };
1057
        w.reason = supplant(m, w);
1058
        JSHINT.errors.push(w);
1059
        if (option.passfail) {
1060
            quit("Stopping. ", l, ch);
1061
        }
1062
        warnings += 1;
1063
        if (warnings >= option.maxerr) {
1064
            quit("Too many errors.", l, ch);
1065
        }
1066
        return w;
1067
    }
1068

    
1069
    function warningAt(m, l, ch, a, b, c, d) {
1070
        return warning(m, {
1071
            line: l,
1072
            from: ch
1073
        }, a, b, c, d);
1074
    }
1075

    
1076
    function error(m, t, a, b, c, d) {
1077
        warning(m, t, a, b, c, d);
1078
    }
1079

    
1080
    function errorAt(m, l, ch, a, b, c, d) {
1081
        return error(m, {
1082
            line: l,
1083
            from: ch
1084
        }, a, b, c, d);
1085
    }
1086

    
1087
    // Tracking of "internal" scripts, like eval containing a static string
1088
    function addInternalSrc(elem, src) {
1089
        var i;
1090
        i = {
1091
            id: "(internal)",
1092
            elem: elem,
1093
            value: src
1094
        };
1095
        JSHINT.internals.push(i);
1096
        return i;
1097
    }
1098

    
1099

    
1100
// lexical analysis and token construction
1101

    
1102
    var lex = (function lex() {
1103
        var character, from, line, s;
1104

    
1105
// Private lex methods
1106

    
1107
        function nextLine() {
1108
            var at,
1109
                match,
1110
                tw; // trailing whitespace check
1111

    
1112
            if (line >= lines.length)
1113
                return false;
1114

    
1115
            character = 1;
1116
            s = lines[line];
1117
            line += 1;
1118

    
1119
            // If smarttabs option is used check for spaces followed by tabs only.
1120
            // Otherwise check for any occurence of mixed tabs and spaces.
1121
            // Tabs and one space followed by block comment is allowed.
1122
            if (option.smarttabs) {
1123
                // negative look-behind for "//"
1124
                match = s.match(/(\/\/)? \t/);
1125
                at = match && !match[1] ? 0 : -1;
1126
            } else {
1127
                at = s.search(/ \t|\t [^\*]/);
1128
            }
1129

    
1130
            if (at >= 0)
1131
                warningAt("Mixed spaces and tabs.", line, at + 1);
1132

    
1133
            s = s.replace(/\t/g, tab);
1134
            at = s.search(cx);
1135

    
1136
            if (at >= 0)
1137
                warningAt("Unsafe character.", line, at);
1138

    
1139
            if (option.maxlen && option.maxlen < s.length)
1140
                warningAt("Line too long.", line, s.length);
1141

    
1142
            // Check for trailing whitespaces
1143
            tw = option.trailing && s.match(/^(.*?)\s+$/);
1144
            if (tw && !/^\s+$/.test(s)) {
1145
                warningAt("Trailing whitespace.", line, tw[1].length + 1);
1146
            }
1147
            return true;
1148
        }
1149

    
1150
// Produce a token object.  The token inherits from a syntax symbol.
1151

    
1152
        function it(type, value) {
1153
            var i, t;
1154

    
1155
            function checkName(name) {
1156
                if (!option.proto && name === "__proto__") {
1157
                    warningAt("The '{a}' property is deprecated.", line, from, name);
1158
                    return;
1159
                }
1160

    
1161
                if (!option.iterator && name === "__iterator__") {
1162
                    warningAt("'{a}' is only available in JavaScript 1.7.", line, from, name);
1163
                    return;
1164
                }
1165

    
1166
                // Check for dangling underscores unless we're in Node
1167
                // environment and this identifier represents built-in
1168
                // Node globals with underscores.
1169

    
1170
                var hasDangling = /^(_+.*|.*_+)$/.test(name);
1171

    
1172
                if (option.nomen && hasDangling && name !== "_") {
1173
                    if (option.node && token.id !== "." && /^(__dirname|__filename)$/.test(name))
1174
                        return;
1175

    
1176
                    warningAt("Unexpected {a} in '{b}'.", line, from, "dangling '_'", name);
1177
                    return;
1178
                }
1179

    
1180
                // Check for non-camelcase names. Names like MY_VAR and
1181
                // _myVar are okay though.
1182

    
1183
                if (option.camelcase) {
1184
                    if (name.replace(/^_+/, "").indexOf("_") > -1 && !name.match(/^[A-Z0-9_]*$/)) {
1185
                        warningAt("Identifier '{a}' is not in camel case.", line, from, value);
1186
                    }
1187
                }
1188
            }
1189

    
1190
            if (type === "(color)" || type === "(range)") {
1191
                t = {type: type};
1192
            } else if (type === "(punctuator)" ||
1193
                    (type === "(identifier)" && is_own(syntax, value))) {
1194
                t = syntax[value] || syntax["(error)"];
1195
            } else {
1196
                t = syntax[type];
1197
            }
1198

    
1199
            t = Object.create(t);
1200

    
1201
            if (type === "(string)" || type === "(range)") {
1202
                if (!option.scripturl && jx.test(value)) {
1203
                    warningAt("Script URL.", line, from);
1204
                }
1205
            }
1206

    
1207
            if (type === "(identifier)") {
1208
                t.identifier = true;
1209
                checkName(value);
1210
            }
1211

    
1212
            t.value = value;
1213
            t.line = line;
1214
            t.character = character;
1215
            t.from = from;
1216
            i = t.id;
1217
            if (i !== "(endline)") {
1218
                prereg = i &&
1219
                    (("(,=:[!&|?{};".indexOf(i.charAt(i.length - 1)) >= 0) ||
1220
                    i === "return" ||
1221
                    i === "case");
1222
            }
1223
            return t;
1224
        }
1225

    
1226
        // Public lex methods
1227
        return {
1228
            init: function (source) {
1229
                if (typeof source === "string") {
1230
                    lines = source
1231
                        .replace(/\r\n/g, "\n")
1232
                        .replace(/\r/g, "\n")
1233
                        .split("\n");
1234
                } else {
1235
                    lines = source;
1236
                }
1237

    
1238
                // If the first line is a shebang (#!), make it a blank and move on.
1239
                // Shebangs are used by Node scripts.
1240
                if (lines[0] && lines[0].substr(0, 2) === "#!")
1241
                    lines[0] = "";
1242

    
1243
                line = 0;
1244
                nextLine();
1245
                from = 1;
1246
            },
1247

    
1248
            range: function (begin, end) {
1249
                var c, value = "";
1250
                from = character;
1251
                if (s.charAt(0) !== begin) {
1252
                    errorAt("Expected '{a}' and instead saw '{b}'.",
1253
                            line, character, begin, s.charAt(0));
1254
                }
1255
                for (;;) {
1256
                    s = s.slice(1);
1257
                    character += 1;
1258
                    c = s.charAt(0);
1259
                    switch (c) {
1260
                    case "":
1261
                        errorAt("Missing '{a}'.", line, character, c);
1262
                        break;
1263
                    case end:
1264
                        s = s.slice(1);
1265
                        character += 1;
1266
                        return it("(range)", value);
1267
                    case "\\":
1268
                        warningAt("Unexpected '{a}'.", line, character, c);
1269
                    }
1270
                    value += c;
1271
                }
1272

    
1273
            },
1274

    
1275

    
1276
            // token -- this is called by advance to get the next token
1277
            token: function () {
1278
                var b, c, captures, d, depth, high, i, l, low, q, t, isLiteral, isInRange, n;
1279

    
1280
                function match(x) {
1281
                    var r = x.exec(s), r1;
1282

    
1283
                    if (r) {
1284
                        l = r[0].length;
1285
                        r1 = r[1];
1286
                        c = r1.charAt(0);
1287
                        s = s.substr(l);
1288
                        from = character + l - r1.length;
1289
                        character += l;
1290
                        return r1;
1291
                    }
1292
                }
1293

    
1294
                function string(x) {
1295
                    var c, j, r = "", allowNewLine = false;
1296

    
1297
                    if (jsonmode && x !== "\"") {
1298
                        warningAt("Strings must use doublequote.",
1299
                                line, character);
1300
                    }
1301

    
1302
                    if (option.quotmark) {
1303
                        if (option.quotmark === "single" && x !== "'") {
1304
                            warningAt("Strings must use singlequote.",
1305
                                    line, character);
1306
                        } else if (option.quotmark === "double" && x !== "\"") {
1307
                            warningAt("Strings must use doublequote.",
1308
                                    line, character);
1309
                        } else if (option.quotmark === true) {
1310
                            quotmark = quotmark || x;
1311
                            if (quotmark !== x) {
1312
                                warningAt("Mixed double and single quotes.",
1313
                                        line, character);
1314
                            }
1315
                        }
1316
                    }
1317

    
1318
                    function esc(n) {
1319
                        var i = parseInt(s.substr(j + 1, n), 16);
1320
                        j += n;
1321
                        if (i >= 32 && i <= 126 &&
1322
                                i !== 34 && i !== 92 && i !== 39) {
1323
                            warningAt("Unnecessary escapement.", line, character);
1324
                        }
1325
                        character += n;
1326
                        c = String.fromCharCode(i);
1327
                    }
1328

    
1329
                    j = 0;
1330

    
1331
unclosedString:
1332
                    for (;;) {
1333
                        while (j >= s.length) {
1334
                            j = 0;
1335

    
1336
                            var cl = line, cf = from;
1337
                            if (!nextLine()) {
1338
                                errorAt("Unclosed string.", cl, cf);
1339
                                break unclosedString;
1340
                            }
1341

    
1342
                            if (allowNewLine) {
1343
                                allowNewLine = false;
1344
                            } else {
1345
                                warningAt("Unclosed string.", cl, cf);
1346
                            }
1347
                        }
1348

    
1349
                        c = s.charAt(j);
1350
                        if (c === x) {
1351
                            character += 1;
1352
                            s = s.substr(j + 1);
1353
                            return it("(string)", r, x);
1354
                        }
1355

    
1356
                        if (c < " ") {
1357
                            if (c === "\n" || c === "\r") {
1358
                                break;
1359
                            }
1360
                            warningAt("Control character in string: {a}.",
1361
                                    line, character + j, s.slice(0, j));
1362
                        } else if (c === "\\") {
1363
                            j += 1;
1364
                            character += 1;
1365
                            c = s.charAt(j);
1366
                            n = s.charAt(j + 1);
1367
                            switch (c) {
1368
                            case "\\":
1369
                            case "\"":
1370
                            case "/":
1371
                                break;
1372
                            case "\'":
1373
                                if (jsonmode) {
1374
                                    warningAt("Avoid \\'.", line, character);
1375
                                }
1376
                                break;
1377
                            case "b":
1378
                                c = "\b";
1379
                                break;
1380
                            case "f":
1381
                                c = "\f";
1382
                                break;
1383
                            case "n":
1384
                                c = "\n";
1385
                                break;
1386
                            case "r":
1387
                                c = "\r";
1388
                                break;
1389
                            case "t":
1390
                                c = "\t";
1391
                                break;
1392
                            case "0":
1393
                                c = "\0";
1394
                                // Octal literals fail in strict mode
1395
                                // check if the number is between 00 and 07
1396
                                // where 'n' is the token next to 'c'
1397
                                if (n >= 0 && n <= 7 && directive["use strict"]) {
1398
                                    warningAt(
1399
                                    "Octal literals are not allowed in strict mode.",
1400
                                    line, character);
1401
                                }
1402
                                break;
1403
                            case "u":
1404
                                esc(4);
1405
                                break;
1406
                            case "v":
1407
                                if (jsonmode) {
1408
                                    warningAt("Avoid \\v.", line, character);
1409
                                }
1410
                                c = "\v";
1411
                                break;
1412
                            case "x":
1413
                                if (jsonmode) {
1414
                                    warningAt("Avoid \\x-.", line, character);
1415
                                }
1416
                                esc(2);
1417
                                break;
1418
                            case "":
1419
                                // last character is escape character
1420
                                // always allow new line if escaped, but show
1421
                                // warning if option is not set
1422
                                allowNewLine = true;
1423
                                if (option.multistr) {
1424
                                    if (jsonmode) {
1425
                                        warningAt("Avoid EOL escapement.", line, character);
1426
                                    }
1427
                                    c = "";
1428
                                    character -= 1;
1429
                                    break;
1430
                                }
1431
                                warningAt("Bad escapement of EOL. Use option multistr if needed.",
1432
                                    line, character);
1433
                                break;
1434
                            case "!":
1435
                                if (s.charAt(j - 2) === "<")
1436
                                    break;
1437
                                /*falls through*/
1438
                            default:
1439
                                warningAt("Bad escapement.", line, character);
1440
                            }
1441
                        }
1442
                        r += c;
1443
                        character += 1;
1444
                        j += 1;
1445
                    }
1446
                }
1447

    
1448
                for (;;) {
1449
                    if (!s) {
1450
                        return it(nextLine() ? "(endline)" : "(end)", "");
1451
                    }
1452

    
1453
                    t = match(tx);
1454

    
1455
                    if (!t) {
1456
                        t = "";
1457
                        c = "";
1458
                        while (s && s < "!") {
1459
                            s = s.substr(1);
1460
                        }
1461
                        if (s) {
1462
                            errorAt("Unexpected '{a}'.", line, character, s.substr(0, 1));
1463
                            s = "";
1464
                        }
1465
                    } else {
1466

    
1467
    //      identifier
1468

    
1469
                        if (isAlpha(c) || c === "_" || c === "$") {
1470
                            return it("(identifier)", t);
1471
                        }
1472

    
1473
    //      number
1474

    
1475
                        if (isDigit(c)) {
1476
                            if (!isFinite(Number(t))) {
1477
                                warningAt("Bad number '{a}'.",
1478
                                    line, character, t);
1479
                            }
1480
                            if (isAlpha(s.substr(0, 1))) {
1481
                                warningAt("Missing space after '{a}'.",
1482
                                        line, character, t);
1483
                            }
1484
                            if (c === "0") {
1485
                                d = t.substr(1, 1);
1486
                                if (isDigit(d)) {
1487
                                    if (token.id !== ".") {
1488
                                        warningAt("Don't use extra leading zeros '{a}'.",
1489
                                            line, character, t);
1490
                                    }
1491
                                } else if (jsonmode && (d === "x" || d === "X")) {
1492
                                    warningAt("Avoid 0x-. '{a}'.",
1493
                                            line, character, t);
1494
                                }
1495
                            }
1496
                            if (t.substr(t.length - 1) === ".") {
1497
                                warningAt(
1498
"A trailing decimal point can be confused with a dot '{a}'.", line, character, t);
1499
                            }
1500
                            return it("(number)", t);
1501
                        }
1502
                        switch (t) {
1503

    
1504
    //      string
1505

    
1506
                        case "\"":
1507
                        case "'":
1508
                            return string(t);
1509

    
1510
    //      // comment
1511

    
1512
                        case "//":
1513
                            s = "";
1514
                            token.comment = true;
1515
                            break;
1516

    
1517
    //      /* comment
1518

    
1519
                        case "/*":
1520
                            for (;;) {
1521
                                i = s.search(lx);
1522
                                if (i >= 0) {
1523
                                    break;
1524
                                }
1525
                                if (!nextLine()) {
1526
                                    errorAt("Unclosed comment.", line, character);
1527
                                }
1528
                            }
1529
                            s = s.substr(i + 2);
1530
                            token.comment = true;
1531
                            break;
1532

    
1533
    //      /*members /*jshint /*global
1534

    
1535
                        case "/*members":
1536
                        case "/*member":
1537
                        case "/*jshint":
1538
                        case "/*jslint":
1539
                        case "/*global":
1540
                        case "*/":
1541
                            return {
1542
                                value: t,
1543
                                type: "special",
1544
                                line: line,
1545
                                character: character,
1546
                                from: from
1547
                            };
1548

    
1549
                        case "":
1550
                            break;
1551
    //      /
1552
                        case "/":
1553
                            if (s.charAt(0) === "=") {
1554
                                errorAt("A regular expression literal can be confused with '/='.",
1555
                                    line, from);
1556
                            }
1557

    
1558
                            if (prereg) {
1559
                                depth = 0;
1560
                                captures = 0;
1561
                                l = 0;
1562
                                for (;;) {
1563
                                    b = true;
1564
                                    c = s.charAt(l);
1565
                                    l += 1;
1566
                                    switch (c) {
1567
                                    case "":
1568
                                        errorAt("Unclosed regular expression.", line, from);
1569
                                        return quit("Stopping.", line, from);
1570
                                    case "/":
1571
                                        if (depth > 0) {
1572
                                            warningAt("{a} unterminated regular expression " +
1573
                                                "group(s).", line, from + l, depth);
1574
                                        }
1575
                                        c = s.substr(0, l - 1);
1576
                                        q = {
1577
                                            g: true,
1578
                                            i: true,
1579
                                            m: true
1580
                                        };
1581
                                        while (q[s.charAt(l)] === true) {
1582
                                            q[s.charAt(l)] = false;
1583
                                            l += 1;
1584
                                        }
1585
                                        character += l;
1586
                                        s = s.substr(l);
1587
                                        q = s.charAt(0);
1588
                                        if (q === "/" || q === "*") {
1589
                                            errorAt("Confusing regular expression.",
1590
                                                    line, from);
1591
                                        }
1592
                                        return it("(regexp)", c);
1593
                                    case "\\":
1594
                                        c = s.charAt(l);
1595
                                        if (c < " ") {
1596
                                            warningAt(
1597
"Unexpected control character in regular expression.", line, from + l);
1598
                                        } else if (c === "<") {
1599
                                            warningAt(
1600
"Unexpected escaped character '{a}' in regular expression.", line, from + l, c);
1601
                                        }
1602
                                        l += 1;
1603
                                        break;
1604
                                    case "(":
1605
                                        depth += 1;
1606
                                        b = false;
1607
                                        if (s.charAt(l) === "?") {
1608
                                            l += 1;
1609
                                            switch (s.charAt(l)) {
1610
                                            case ":":
1611
                                            case "=":
1612
                                            case "!":
1613
                                                l += 1;
1614
                                                break;
1615
                                            default:
1616
                                                warningAt(
1617
"Expected '{a}' and instead saw '{b}'.", line, from + l, ":", s.charAt(l));
1618
                                            }
1619
                                        } else {
1620
                                            captures += 1;
1621
                                        }
1622
                                        break;
1623
                                    case "|":
1624
                                        b = false;
1625
                                        break;
1626
                                    case ")":
1627
                                        if (depth === 0) {
1628
                                            warningAt("Unescaped '{a}'.",
1629
                                                    line, from + l, ")");
1630
                                        } else {
1631
                                            depth -= 1;
1632
                                        }
1633
                                        break;
1634
                                    case " ":
1635
                                        q = 1;
1636
                                        while (s.charAt(l) === " ") {
1637
                                            l += 1;
1638
                                            q += 1;
1639
                                        }
1640
                                        if (q > 1) {
1641
                                            warningAt(
1642
"Spaces are hard to count. Use {{a}}.", line, from + l, q);
1643
                                        }
1644
                                        break;
1645
                                    case "[":
1646
                                        c = s.charAt(l);
1647
                                        if (c === "^") {
1648
                                            l += 1;
1649
                                            if (s.charAt(l) === "]") {
1650
                                                errorAt("Unescaped '{a}'.",
1651
                                                    line, from + l, "^");
1652
                                            }
1653
                                        }
1654
                                        if (c === "]") {
1655
                                            warningAt("Empty class.", line,
1656
                                                    from + l - 1);
1657
                                        }
1658
                                        isLiteral = false;
1659
                                        isInRange = false;
1660
klass:
1661
                                        do {
1662
                                            c = s.charAt(l);
1663
                                            l += 1;
1664
                                            switch (c) {
1665
                                            case "[":
1666
                                            case "^":
1667
                                                warningAt("Unescaped '{a}'.",
1668
                                                        line, from + l, c);
1669
                                                if (isInRange) {
1670
                                                    isInRange = false;
1671
                                                } else {
1672
                                                    isLiteral = true;
1673
                                                }
1674
                                                break;
1675
                                            case "-":
1676
                                                if (isLiteral && !isInRange) {
1677
                                                    isLiteral = false;
1678
                                                    isInRange = true;
1679
                                                } else if (isInRange) {
1680
                                                    isInRange = false;
1681
                                                } else if (s.charAt(l) === "]") {
1682
                                                    isInRange = true;
1683
                                                } else {
1684
                                                    if (option.regexdash !== (l === 2 || (l === 3 &&
1685
                                                        s.charAt(1) === "^"))) {
1686
                                                        warningAt("Unescaped '{a}'.",
1687
                                                            line, from + l - 1, "-");
1688
                                                    }
1689
                                                    isLiteral = true;
1690
                                                }
1691
                                                break;
1692
                                            case "]":
1693
                                                if (isInRange && !option.regexdash) {
1694
                                                    warningAt("Unescaped '{a}'.",
1695
                                                            line, from + l - 1, "-");
1696
                                                }
1697
                                                break klass;
1698
                                            case "\\":
1699
                                                c = s.charAt(l);
1700
                                                if (c < " ") {
1701
                                                    warningAt(
1702
"Unexpected control character in regular expression.", line, from + l);
1703
                                                } else if (c === "<") {
1704
                                                    warningAt(
1705
"Unexpected escaped character '{a}' in regular expression.", line, from + l, c);
1706
                                                }
1707
                                                l += 1;
1708

    
1709
                                                // \w, \s and \d are never part of a character range
1710
                                                if (/[wsd]/i.test(c)) {
1711
                                                    if (isInRange) {
1712
                                                        warningAt("Unescaped '{a}'.",
1713
                                                            line, from + l, "-");
1714
                                                        isInRange = false;
1715
                                                    }
1716
                                                    isLiteral = false;
1717
                                                } else if (isInRange) {
1718
                                                    isInRange = false;
1719
                                                } else {
1720
                                                    isLiteral = true;
1721
                                                }
1722
                                                break;
1723
                                            case "/":
1724
                                                warningAt("Unescaped '{a}'.",
1725
                                                        line, from + l - 1, "/");
1726

    
1727
                                                if (isInRange) {
1728
                                                    isInRange = false;
1729
                                                } else {
1730
                                                    isLiteral = true;
1731
                                                }
1732
                                                break;
1733
                                            case "<":
1734
                                                if (isInRange) {
1735
                                                    isInRange = false;
1736
                                                } else {
1737
                                                    isLiteral = true;
1738
                                                }
1739
                                                break;
1740
                                            default:
1741
                                                if (isInRange) {
1742
                                                    isInRange = false;
1743
                                                } else {
1744
                                                    isLiteral = true;
1745
                                                }
1746
                                            }
1747
                                        } while (c);
1748
                                        break;
1749
                                    case ".":
1750
                                        if (option.regexp) {
1751
                                            warningAt("Insecure '{a}'.", line,
1752
                                                    from + l, c);
1753
                                        }
1754
                                        break;
1755
                                    case "]":
1756
                                    case "?":
1757
                                    case "{":
1758
                                    case "}":
1759
                                    case "+":
1760
                                    case "*":
1761
                                        warningAt("Unescaped '{a}'.", line,
1762
                                                from + l, c);
1763
                                    }
1764
                                    if (b) {
1765
                                        switch (s.charAt(l)) {
1766
                                        case "?":
1767
                                        case "+":
1768
                                        case "*":
1769
                                            l += 1;
1770
                                            if (s.charAt(l) === "?") {
1771
                                                l += 1;
1772
                                            }
1773
                                            break;
1774
                                        case "{":
1775
                                            l += 1;
1776
                                            c = s.charAt(l);
1777
                                            if (c < "0" || c > "9") {
1778
                                                warningAt(
1779
"Expected a number and instead saw '{a}'.", line, from + l, c);
1780
                                                break; // No reason to continue checking numbers.
1781
                                            }
1782
                                            l += 1;
1783
                                            low = +c;
1784
                                            for (;;) {
1785
                                                c = s.charAt(l);
1786
                                                if (c < "0" || c > "9") {
1787
                                                    break;
1788
                                                }
1789
                                                l += 1;
1790
                                                low = +c + (low * 10);
1791
                                            }
1792
                                            high = low;
1793
                                            if (c === ",") {
1794
                                                l += 1;
1795
                                                high = Infinity;
1796
                                                c = s.charAt(l);
1797
                                                if (c >= "0" && c <= "9") {
1798
                                                    l += 1;
1799
                                                    high = +c;
1800
                                                    for (;;) {
1801
                                                        c = s.charAt(l);
1802
                                                        if (c < "0" || c > "9") {
1803
                                                            break;
1804
                                                        }
1805
                                                        l += 1;
1806
                                                        high = +c + (high * 10);
1807
                                                    }
1808
                                                }
1809
                                            }
1810
                                            if (s.charAt(l) !== "}") {
1811
                                                warningAt(
1812
"Expected '{a}' and instead saw '{b}'.", line, from + l, "}", c);
1813
                                            } else {
1814
                                                l += 1;
1815
                                            }
1816
                                            if (s.charAt(l) === "?") {
1817
                                                l += 1;
1818
                                            }
1819
                                            if (low > high) {
1820
                                                warningAt(
1821
"'{a}' should not be greater than '{b}'.", line, from + l, low, high);
1822
                                            }
1823
                                        }
1824
                                    }
1825
                                }
1826
                                c = s.substr(0, l - 1);
1827
                                character += l;
1828
                                s = s.substr(l);
1829
                                return it("(regexp)", c);
1830
                            }
1831
                            return it("(punctuator)", t);
1832

    
1833
    //      punctuator
1834

    
1835
                        case "#":
1836
                            return it("(punctuator)", t);
1837
                        default:
1838
                            return it("(punctuator)", t);
1839
                        }
1840
                    }
1841
                }
1842
            }
1843
        };
1844
    }());
1845

    
1846

    
1847
    function addlabel(t, type, token) {
1848
        if (t === "hasOwnProperty") {
1849
            warning("'hasOwnProperty' is a really bad name.");
1850
        }
1851

    
1852
        // Define t in the current function in the current scope.
1853
        if (type === "exception") {
1854
            if (is_own(funct["(context)"], t)) {
1855
                if (funct[t] !== true && !option.node) {
1856
                    warning("Value of '{a}' may be overwritten in IE.", nexttoken, t);
1857
                }
1858
            }
1859
        }
1860

    
1861
        if (is_own(funct, t) && !funct["(global)"]) {
1862
            if (funct[t] === true) {
1863
                if (option.latedef)
1864
                    warning("'{a}' was used before it was defined.", nexttoken, t);
1865
            } else {
1866
                if (!option.shadow && type !== "exception") {
1867
                    warning("'{a}' is already defined.", nexttoken, t);
1868
                }
1869
            }
1870
        }
1871

    
1872
        funct[t] = type;
1873

    
1874
        if (token) {
1875
            funct["(tokens)"][t] = token;
1876
        }
1877

    
1878
        if (funct["(global)"]) {
1879
            global[t] = funct;
1880
            if (is_own(implied, t)) {
1881
                if (option.latedef)
1882
                    warning("'{a}' was used before it was defined.", nexttoken, t);
1883
                delete implied[t];
1884
            }
1885
        } else {
1886
            scope[t] = funct;
1887
        }
1888
    }
1889

    
1890

    
1891
    function doOption() {
1892
        var nt = nexttoken;
1893
        var o  = nt.value;
1894
        var quotmarkValue = option.quotmark;
1895
        var predef = {};
1896
        var b, obj, filter, t, tn, v, minus;
1897

    
1898
        switch (o) {
1899
        case "*/":
1900
            error("Unbegun comment.");
1901
            break;
1902
        case "/*members":
1903
        case "/*member":
1904
            o = "/*members";
1905
            if (!membersOnly) {
1906
                membersOnly = {};
1907
            }
1908
            obj = membersOnly;
1909
            option.quotmark = false;
1910
            break;
1911
        case "/*jshint":
1912
        case "/*jslint":
1913
            obj = option;
1914
            filter = boolOptions;
1915
            break;
1916
        case "/*global":
1917
            obj = predef;
1918
            break;
1919
        default:
1920
            error("What?");
1921
        }
1922

    
1923
        t = lex.token();
1924

    
1925
loop:
1926
        for (;;) {
1927
            minus = false;
1928
            for (;;) {
1929
                if (t.type === "special" && t.value === "*/") {
1930
                    break loop;
1931
                }
1932
                if (t.id !== "(endline)" && t.id !== ",") {
1933
                    break;
1934
                }
1935
                t = lex.token();
1936
            }
1937

    
1938
            if (o === "/*global" && t.value === "-") {
1939
                minus = true;
1940
                t = lex.token();
1941
            }
1942

    
1943
            if (t.type !== "(string)" && t.type !== "(identifier)" && o !== "/*members") {
1944
                error("Bad option.", t);
1945
            }
1946

    
1947
            v = lex.token();
1948
            if (v.id === ":") {
1949
                v = lex.token();
1950

    
1951
                if (obj === membersOnly) {
1952
                    error("Expected '{a}' and instead saw '{b}'.", t, "*/", ":");
1953
                }
1954

    
1955
                if (o === "/*jshint") {
1956
                    checkOption(t.value, t);
1957
                }
1958

    
1959
                var numericVals = [
1960
                    "maxstatements",
1961
                    "maxparams",
1962
                    "maxdepth",
1963
                    "maxcomplexity",
1964
                    "maxerr",
1965
                    "maxlen",
1966
                    "indent"
1967
                ];
1968

    
1969
                if (numericVals.indexOf(t.value) > -1 && (o === "/*jshint" || o === "/*jslint")) {
1970
                    b = +v.value;
1971

    
1972
                    if (typeof b !== "number" || !isFinite(b) || b <= 0 || Math.floor(b) !== b) {
1973
                        error("Expected a small integer and instead saw '{a}'.", v, v.value);
1974
                    }
1975

    
1976
                    if (t.value === "indent")
1977
                        obj.white = true;
1978

    
1979
                    obj[t.value] = b;
1980
                } else if (t.value === "validthis") {
1981
                    if (funct["(global)"]) {
1982
                        error("Option 'validthis' can't be used in a global scope.");
1983
                    } else {
1984
                        if (v.value === "true" || v.value === "false")
1985
                            obj[t.value] = v.value === "true";
1986
                        else
1987
                            error("Bad option value.", v);
1988
                    }
1989
                } else if (t.value === "quotmark" && (o === "/*jshint")) {
1990
                    switch (v.value) {
1991
                    case "true":
1992
                        obj.quotmark = true;
1993
                        break;
1994
                    case "false":
1995
                        obj.quotmark = false;
1996
                        break;
1997
                    case "double":
1998
                    case "single":
1999
                        obj.quotmark = v.value;
2000
                        break;
2001
                    default:
2002
                        error("Bad option value.", v);
2003
                    }
2004
                } else if (v.value === "true" || v.value === "false") {
2005
                    if (o === "/*jslint") {
2006
                        tn = renamedOptions[t.value] || t.value;
2007
                        obj[tn] = v.value === "true";
2008
                        if (invertedOptions[tn] !== undefined) {
2009
                            obj[tn] = !obj[tn];
2010
                        }
2011
                    } else {
2012
                        obj[t.value] = v.value === "true";
2013
                    }
2014

    
2015
                    if (t.value === "newcap")
2016
                        obj["(explicitNewcap)"] = true;
2017
                } else {
2018
                    error("Bad option value.", v);
2019
                }
2020
                t = lex.token();
2021
            } else {
2022
                if (o === "/*jshint" || o === "/*jslint") {
2023
                    error("Missing option value.", t);
2024
                }
2025

    
2026
                obj[t.value] = false;
2027

    
2028
                if (o === "/*global" && minus === true) {
2029
                    JSHINT.blacklist[t.value] = t.value;
2030
                    updatePredefined();
2031
                }
2032

    
2033
                t = v;
2034
            }
2035
        }
2036

    
2037
        if (o === "/*members") {
2038
            option.quotmark = quotmarkValue;
2039
        }
2040

    
2041
        combine(predefined, predef);
2042

    
2043
        for (var key in predef) {
2044
            if (is_own(predef, key)) {
2045
                declared[key] = nt;
2046
            }
2047
        }
2048

    
2049
        if (filter) {
2050
            assume();
2051
        }
2052
    }
2053

    
2054

    
2055
// We need a peek function. If it has an argument, it peeks that much farther
2056
// ahead. It is used to distinguish
2057
//     for ( var i in ...
2058
// from
2059
//     for ( var i = ...
2060

    
2061
    function peek(p) {
2062
        var i = p || 0, j = 0, t;
2063

    
2064
        while (j <= i) {
2065
            t = lookahead[j];
2066
            if (!t) {
2067
                t = lookahead[j] = lex.token();
2068
            }
2069
            j += 1;
2070
        }
2071
        return t;
2072
    }
2073

    
2074

    
2075

    
2076
// Produce the next token. It looks for programming errors.
2077

    
2078
    function advance(id, t) {
2079
        switch (token.id) {
2080
        case "(number)":
2081
            if (nexttoken.id === ".") {
2082
                warning("A dot following a number can be confused with a decimal point.", token);
2083
            }
2084
            break;
2085
        case "-":
2086
            if (nexttoken.id === "-" || nexttoken.id === "--") {
2087
                warning("Confusing minusses.");
2088
            }
2089
            break;
2090
        case "+":
2091
            if (nexttoken.id === "+" || nexttoken.id === "++") {
2092
                warning("Confusing plusses.");
2093
            }
2094
            break;
2095
        }
2096

    
2097
        if (token.type === "(string)" || token.identifier) {
2098
            anonname = token.value;
2099
        }
2100

    
2101
        if (id && nexttoken.id !== id) {
2102
            if (t) {
2103
                if (nexttoken.id === "(end)") {
2104
                    warning("Unmatched '{a}'.", t, t.id);
2105
                } else {
2106
                    warning("Expected '{a}' to match '{b}' from line {c} and instead saw '{d}'.",
2107
                            nexttoken, id, t.id, t.line, nexttoken.value);
2108
                }
2109
            } else if (nexttoken.type !== "(identifier)" ||
2110
                            nexttoken.value !== id) {
2111
                warning("Expected '{a}' and instead saw '{b}'.",
2112
                        nexttoken, id, nexttoken.value);
2113
            }
2114
        }
2115

    
2116
        prevtoken = token;
2117
        token = nexttoken;
2118
        for (;;) {
2119
            nexttoken = lookahead.shift() || lex.token();
2120
            if (nexttoken.id === "(end)" || nexttoken.id === "(error)") {
2121
                return;
2122
            }
2123
            if (nexttoken.type === "special") {
2124
                doOption();
2125
            } else {
2126
                if (nexttoken.id !== "(endline)") {
2127
                    break;
2128
                }
2129
            }
2130
        }
2131
    }
2132

    
2133

    
2134
// This is the heart of JSHINT, the Pratt parser. In addition to parsing, it
2135
// is looking for ad hoc lint patterns. We add .fud to Pratt's model, which is
2136
// like .nud except that it is only used on the first token of a statement.
2137
// Having .fud makes it much easier to define statement-oriented languages like
2138
// JavaScript. I retained Pratt's nomenclature.
2139

    
2140
// .nud     Null denotation
2141
// .fud     First null denotation
2142
// .led     Left denotation
2143
//  lbp     Left binding power
2144
//  rbp     Right binding power
2145

    
2146
// They are elements of the parsing method called Top Down Operator Precedence.
2147

    
2148
    function expression(rbp, initial) {
2149
        var left, isArray = false, isObject = false;
2150

    
2151
        if (nexttoken.id === "(end)")
2152
            error("Unexpected early end of program.", token);
2153

    
2154
        advance();
2155
        if (initial) {
2156
            anonname = "anonymous";
2157
            funct["(verb)"] = token.value;
2158
        }
2159
        if (initial === true && token.fud) {
2160
            left = token.fud();
2161
        } else {
2162
            if (token.nud) {
2163
                left = token.nud();
2164
            } else {
2165
                if (nexttoken.type === "(number)" && token.id === ".") {
2166
                    warning("A leading decimal point can be confused with a dot: '.{a}'.",
2167
                            token, nexttoken.value);
2168
                    advance();
2169
                    return token;
2170
                } else {
2171
                    error("Expected an identifier and instead saw '{a}'.",
2172
                            token, token.id);
2173
                }
2174
            }
2175
            while (rbp < nexttoken.lbp) {
2176
                isArray = token.value === "Array";
2177
                isObject = token.value === "Object";
2178

    
2179
                // #527, new Foo.Array(), Foo.Array(), new Foo.Object(), Foo.Object()
2180
                // Line breaks in IfStatement heads exist to satisfy the checkJSHint
2181
                // "Line too long." error.
2182
                if (left && (left.value || (left.first && left.first.value))) {
2183
                    // If the left.value is not "new", or the left.first.value is a "."
2184
                    // then safely assume that this is not "new Array()" and possibly
2185
                    // not "new Object()"...
2186
                    if (left.value !== "new" ||
2187
                      (left.first && left.first.value && left.first.value === ".")) {
2188
                        isArray = false;
2189
                        // ...In the case of Object, if the left.value and token.value
2190
                        // are not equal, then safely assume that this not "new Object()"
2191
                        if (left.value !== token.value) {
2192
                            isObject = false;
2193
                        }
2194
                    }
2195
                }
2196

    
2197
                advance();
2198
                if (isArray && token.id === "(" && nexttoken.id === ")")
2199
                    warning("Use the array literal notation [].", token);
2200
                if (isObject && token.id === "(" && nexttoken.id === ")")
2201
                    warning("Use the object literal notation {}.", token);
2202
                if (token.led) {
2203
                    left = token.led(left);
2204
                } else {
2205
                    error("Expected an operator and instead saw '{a}'.",
2206
                        token, token.id);
2207
                }
2208
            }
2209
        }
2210
        return left;
2211
    }
2212

    
2213

    
2214
// Functions for conformance of style.
2215

    
2216
    function adjacent(left, right) {
2217
        left = left || token;
2218
        right = right || nexttoken;
2219
        if (option.white) {
2220
            if (left.character !== right.from && left.line === right.line) {
2221
                left.from += (left.character - left.from);
2222
                warning("Unexpected space after '{a}'.", left, left.value);
2223
            }
2224
        }
2225
    }
2226

    
2227
    function nobreak(left, right) {
2228
        left = left || token;
2229
        right = right || nexttoken;
2230
        if (option.white && (left.character !== right.from || left.line !== right.line)) {
2231
            warning("Unexpected space before '{a}'.", right, right.value);
2232
        }
2233
    }
2234

    
2235
    function nospace(left, right) {
2236
        left = left || token;
2237
        right = right || nexttoken;
2238
        if (option.white && !left.comment) {
2239
            if (left.line === right.line) {
2240
                adjacent(left, right);
2241
            }
2242
        }
2243
    }
2244

    
2245
    function nonadjacent(left, right) {
2246
        if (option.white) {
2247
            left = left || token;
2248
            right = right || nexttoken;
2249
            if (left.value === ";" && right.value === ";") {
2250
                return;
2251
            }
2252
            if (left.line === right.line && left.character === right.from) {
2253
                left.from += (left.character - left.from);
2254
                warning("Missing space after '{a}'.",
2255
                        left, left.value);
2256
            }
2257
        }
2258
    }
2259

    
2260
    function nobreaknonadjacent(left, right) {
2261
        left = left || token;
2262
        right = right || nexttoken;
2263
        if (!option.laxbreak && left.line !== right.line) {
2264
            warning("Bad line breaking before '{a}'.", right, right.id);
2265
        } else if (option.white) {
2266
            left = left || token;
2267
            right = right || nexttoken;
2268
            if (left.character === right.from) {
2269
                left.from += (left.character - left.from);
2270
                warning("Missing space after '{a}'.",
2271
                        left, left.value);
2272
            }
2273
        }
2274
    }
2275

    
2276
    function indentation(bias) {
2277
        var i;
2278
        if (option.white && nexttoken.id !== "(end)") {
2279
            i = indent + (bias || 0);
2280
            if (nexttoken.from !== i) {
2281
                warning(
2282
"Expected '{a}' to have an indentation at {b} instead at {c}.",
2283
                        nexttoken, nexttoken.value, i, nexttoken.from);
2284
            }
2285
        }
2286
    }
2287

    
2288
    function nolinebreak(t) {
2289
        t = t || token;
2290
        if (t.line !== nexttoken.line) {
2291
            warning("Line breaking error '{a}'.", t, t.value);
2292
        }
2293
    }
2294

    
2295

    
2296
    function comma() {
2297
        if (token.line !== nexttoken.line) {
2298
            if (!option.laxcomma) {
2299
                if (comma.first) {
2300
                    warning("Comma warnings can be turned off with 'laxcomma'");
2301
                    comma.first = false;
2302
                }
2303
                warning("Bad line breaking before '{a}'.", token, nexttoken.id);
2304
            }
2305
        } else if (!token.comment && token.character !== nexttoken.from && option.white) {
2306
            token.from += (token.character - token.from);
2307
            warning("Unexpected space after '{a}'.", token, token.value);
2308
        }
2309
        advance(",");
2310
        nonadjacent(token, nexttoken);
2311
    }
2312

    
2313

    
2314
// Functional constructors for making the symbols that will be inherited by
2315
// tokens.
2316

    
2317
    function symbol(s, p) {
2318
        var x = syntax[s];
2319
        if (!x || typeof x !== "object") {
2320
            syntax[s] = x = {
2321
                id: s,
2322
                lbp: p,
2323
                value: s
2324
            };
2325
        }
2326
        return x;
2327
    }
2328

    
2329

    
2330
    function delim(s) {
2331
        return symbol(s, 0);
2332
    }
2333

    
2334

    
2335
    function stmt(s, f) {
2336
        var x = delim(s);
2337
        x.identifier = x.reserved = true;
2338
        x.fud = f;
2339
        return x;
2340
    }
2341

    
2342

    
2343
    function blockstmt(s, f) {
2344
        var x = stmt(s, f);
2345
        x.block = true;
2346
        return x;
2347
    }
2348

    
2349

    
2350
    function reserveName(x) {
2351
        var c = x.id.charAt(0);
2352
        if ((c >= "a" && c <= "z") || (c >= "A" && c <= "Z")) {
2353
            x.identifier = x.reserved = true;
2354
        }
2355
        return x;
2356
    }
2357

    
2358

    
2359
    function prefix(s, f) {
2360
        var x = symbol(s, 150);
2361
        reserveName(x);
2362
        x.nud = (typeof f === "function") ? f : function () {
2363
            this.right = expression(150);
2364
            this.arity = "unary";
2365
            if (this.id === "++" || this.id === "--") {
2366
                if (option.plusplus) {
2367
                    warning("Unexpected use of '{a}'.", this, this.id);
2368
                } else if ((!this.right.identifier || this.right.reserved) &&
2369
                        this.right.id !== "." && this.right.id !== "[") {
2370
                    warning("Bad operand.", this);
2371
                }
2372
            }
2373
            return this;
2374
        };
2375
        return x;
2376
    }
2377

    
2378

    
2379
    function type(s, f) {
2380
        var x = delim(s);
2381
        x.type = s;
2382
        x.nud = f;
2383
        return x;
2384
    }
2385

    
2386

    
2387
    function reserve(s, f) {
2388
        var x = type(s, f);
2389
        x.identifier = x.reserved = true;
2390
        return x;
2391
    }
2392

    
2393

    
2394
    function reservevar(s, v) {
2395
        return reserve(s, function () {
2396
            if (typeof v === "function") {
2397
                v(this);
2398
            }
2399
            return this;
2400
        });
2401
    }
2402

    
2403

    
2404
    function infix(s, f, p, w) {
2405
        var x = symbol(s, p);
2406
        reserveName(x);
2407
        x.led = function (left) {
2408
            if (!w) {
2409
                nobreaknonadjacent(prevtoken, token);
2410
                nonadjacent(token, nexttoken);
2411
            }
2412
            if (s === "in" && left.id === "!") {
2413
                warning("Confusing use of '{a}'.", left, "!");
2414
            }
2415
            if (typeof f === "function") {
2416
                return f(left, this);
2417
            } else {
2418
                this.left = left;
2419
                this.right = expression(p);
2420
                return this;
2421
            }
2422
        };
2423
        return x;
2424
    }
2425

    
2426

    
2427
    function relation(s, f) {
2428
        var x = symbol(s, 100);
2429
        x.led = function (left) {
2430
            nobreaknonadjacent(prevtoken, token);
2431
            nonadjacent(token, nexttoken);
2432
            var right = expression(100);
2433

    
2434
            if (isIdentifier(left, "NaN") || isIdentifier(right, "NaN")) {
2435
                warning("Use the isNaN function to compare with NaN.", this);
2436
            } else if (f) {
2437
                f.apply(this, [left, right]);
2438
            }
2439
            if (left.id === "!") {
2440
                warning("Confusing use of '{a}'.", left, "!");
2441
            }
2442
            if (right.id === "!") {
2443
                warning("Confusing use of '{a}'.", right, "!");
2444
            }
2445
            this.left = left;
2446
            this.right = right;
2447
            return this;
2448
        };
2449
        return x;
2450
    }
2451

    
2452

    
2453
    function isPoorRelation(node) {
2454
        return node &&
2455
              ((node.type === "(number)" && +node.value === 0) ||
2456
               (node.type === "(string)" && node.value === "") ||
2457
               (node.type === "null" && !option.eqnull) ||
2458
                node.type === "true" ||
2459
                node.type === "false" ||
2460
                node.type === "undefined");
2461
    }
2462

    
2463

    
2464
    function assignop(s) {
2465
        symbol(s, 20).exps = true;
2466

    
2467
        return infix(s, function (left, that) {
2468
            that.left = left;
2469

    
2470
            if (predefined[left.value] === false &&
2471
                    scope[left.value]["(global)"] === true) {
2472
                warning("Read only.", left);
2473
            } else if (left["function"]) {
2474
                warning("'{a}' is a function.", left, left.value);
2475
            }
2476

    
2477
            if (left) {
2478
                if (option.esnext && funct[left.value] === "const") {
2479
                    warning("Attempting to override '{a}' which is a constant", left, left.value);
2480
                }
2481

    
2482
                if (left.id === "." || left.id === "[") {
2483
                    if (!left.left || left.left.value === "arguments") {
2484
                        warning("Bad assignment.", that);
2485
                    }
2486
                    that.right = expression(19);
2487
                    return that;
2488
                } else if (left.identifier && !left.reserved) {
2489
                    if (funct[left.value] === "exception") {
2490
                        warning("Do not assign to the exception parameter.", left);
2491
                    }
2492
                    that.right = expression(19);
2493
                    return that;
2494
                }
2495

    
2496
                if (left === syntax["function"]) {
2497
                    warning(
2498
"Expected an identifier in an assignment and instead saw a function invocation.",
2499
                                token);
2500
                }
2501
            }
2502

    
2503
            error("Bad assignment.", that);
2504
        }, 20);
2505
    }
2506

    
2507

    
2508
    function bitwise(s, f, p) {
2509
        var x = symbol(s, p);
2510
        reserveName(x);
2511
        x.led = (typeof f === "function") ? f : function (left) {
2512
            if (option.bitwise) {
2513
                warning("Unexpected use of '{a}'.", this, this.id);
2514
            }
2515
            this.left = left;
2516
            this.right = expression(p);
2517
            return this;
2518
        };
2519
        return x;
2520
    }
2521

    
2522

    
2523
    function bitwiseassignop(s) {
2524
        symbol(s, 20).exps = true;
2525
        return infix(s, function (left, that) {
2526
            if (option.bitwise) {
2527
                warning("Unexpected use of '{a}'.", that, that.id);
2528
            }
2529
            nonadjacent(prevtoken, token);
2530
            nonadjacent(token, nexttoken);
2531
            if (left) {
2532
                if (left.id === "." || left.id === "[" ||
2533
                        (left.identifier && !left.reserved)) {
2534
                    expression(19);
2535
                    return that;
2536
                }
2537
                if (left === syntax["function"]) {
2538
                    warning(
2539
"Expected an identifier in an assignment, and instead saw a function invocation.",
2540
                                token);
2541
                }
2542
                return that;
2543
            }
2544
            error("Bad assignment.", that);
2545
        }, 20);
2546
    }
2547

    
2548

    
2549
    function suffix(s) {
2550
        var x = symbol(s, 150);
2551
        x.led = function (left) {
2552
            if (option.plusplus) {
2553
                warning("Unexpected use of '{a}'.", this, this.id);
2554
            } else if ((!left.identifier || left.reserved) &&
2555
                    left.id !== "." && left.id !== "[") {
2556
                warning("Bad operand.", this);
2557
            }
2558
            this.left = left;
2559
            return this;
2560
        };
2561
        return x;
2562
    }
2563

    
2564

    
2565
    // fnparam means that this identifier is being defined as a function
2566
    // argument (see identifier())
2567
    function optionalidentifier(fnparam) {
2568
        if (nexttoken.identifier) {
2569
            advance();
2570
            if (token.reserved && !option.es5) {
2571
                // `undefined` as a function param is a common pattern to protect
2572
                // against the case when somebody does `undefined = true` and
2573
                // help with minification. More info: https://gist.github.com/315916
2574
                if (!fnparam || token.value !== "undefined") {
2575
                    warning("Expected an identifier and instead saw '{a}' (a reserved word).",
2576
                            token, token.id);
2577
                }
2578
            }
2579
            return token.value;
2580
        }
2581
    }
2582

    
2583
    // fnparam means that this identifier is being defined as a function
2584
    // argument
2585
    function identifier(fnparam) {
2586
        var i = optionalidentifier(fnparam);
2587
        if (i) {
2588
            return i;
2589
        }
2590
        if (token.id === "function" && nexttoken.id === "(") {
2591
            warning("Missing name in function declaration.");
2592
        } else {
2593
            error("Expected an identifier and instead saw '{a}'.",
2594
                    nexttoken, nexttoken.value);
2595
        }
2596
    }
2597

    
2598

    
2599
    function reachable(s) {
2600
        var i = 0, t;
2601
        if (nexttoken.id !== ";" || noreach) {
2602
            return;
2603
        }
2604
        for (;;) {
2605
            t = peek(i);
2606
            if (t.reach) {
2607
                return;
2608
            }
2609
            if (t.id !== "(endline)") {
2610
                if (t.id === "function") {
2611
                    if (!option.latedef) {
2612
                        break;
2613
                    }
2614
                    warning(
2615
"Inner functions should be listed at the top of the outer function.", t);
2616
                    break;
2617
                }
2618
                warning("Unreachable '{a}' after '{b}'.", t, t.value, s);
2619
                break;
2620
            }
2621
            i += 1;
2622
        }
2623
    }
2624

    
2625

    
2626
    function statement(noindent) {
2627
        var i = indent, r, s = scope, t = nexttoken;
2628

    
2629
        if (t.id === ";") {
2630
            advance(";");
2631
            return;
2632
        }
2633

    
2634
        // Is this a labelled statement?
2635

    
2636
        if (t.identifier && !t.reserved && peek().id === ":") {
2637
            advance();
2638
            advance(":");
2639
            scope = Object.create(s);
2640
            addlabel(t.value, "label");
2641

    
2642
            if (!nexttoken.labelled && nexttoken.value !== "{") {
2643
                warning("Label '{a}' on {b} statement.", nexttoken, t.value, nexttoken.value);
2644
            }
2645

    
2646
            if (jx.test(t.value + ":")) {
2647
                warning("Label '{a}' looks like a javascript url.", t, t.value);
2648
            }
2649

    
2650
            nexttoken.label = t.value;
2651
            t = nexttoken;
2652
        }
2653

    
2654
        // Is it a lonely block?
2655

    
2656
        if (t.id === "{") {
2657
            block(true, true);
2658
            return;
2659
        }
2660

    
2661
        // Parse the statement.
2662

    
2663
        if (!noindent) {
2664
            indentation();
2665
        }
2666
        r = expression(0, true);
2667

    
2668
        // Look for the final semicolon.
2669

    
2670
        if (!t.block) {
2671
            if (!option.expr && (!r || !r.exps)) {
2672
                warning("Expected an assignment or function call and instead saw an expression.",
2673
                    token);
2674
            } else if (option.nonew && r.id === "(" && r.left.id === "new") {
2675
                warning("Do not use 'new' for side effects.", t);
2676
            }
2677

    
2678
            if (nexttoken.id === ",") {
2679
                return comma();
2680
            }
2681

    
2682
            if (nexttoken.id !== ";") {
2683
                if (!option.asi) {
2684
                    // If this is the last statement in a block that ends on
2685
                    // the same line *and* option lastsemic is on, ignore the warning.
2686
                    // Otherwise, complain about missing semicolon.
2687
                    if (!option.lastsemic || nexttoken.id !== "}" ||
2688
                            nexttoken.line !== token.line) {
2689
                        warningAt("Missing semicolon.", token.line, token.character);
2690
                    }
2691
                }
2692
            } else {
2693
                adjacent(token, nexttoken);
2694
                advance(";");
2695
                nonadjacent(token, nexttoken);
2696
            }
2697
        }
2698

    
2699
// Restore the indentation.
2700

    
2701
        indent = i;
2702
        scope = s;
2703
        return r;
2704
    }
2705

    
2706

    
2707
    function statements(startLine) {
2708
        var a = [], p;
2709

    
2710
        while (!nexttoken.reach && nexttoken.id !== "(end)") {
2711
            if (nexttoken.id === ";") {
2712
                p = peek();
2713
                if (!p || p.id !== "(") {
2714
                    warning("Unnecessary semicolon.");
2715
                }
2716
                advance(";");
2717
            } else {
2718
                a.push(statement(startLine === nexttoken.line));
2719
            }
2720
        }
2721
        return a;
2722
    }
2723

    
2724

    
2725
    /*
2726
     * read all directives
2727
     * recognizes a simple form of asi, but always
2728
     * warns, if it is used
2729
     */
2730
    function directives() {
2731
        var i, p, pn;
2732

    
2733
        for (;;) {
2734
            if (nexttoken.id === "(string)") {
2735
                p = peek(0);
2736
                if (p.id === "(endline)") {
2737
                    i = 1;
2738
                    do {
2739
                        pn = peek(i);
2740
                        i = i + 1;
2741
                    } while (pn.id === "(endline)");
2742

    
2743
                    if (pn.id !== ";") {
2744
                        if (pn.id !== "(string)" && pn.id !== "(number)" &&
2745
                            pn.id !== "(regexp)" && pn.identifier !== true &&
2746
                            pn.id !== "}") {
2747
                            break;
2748
                        }
2749
                        warning("Missing semicolon.", nexttoken);
2750
                    } else {
2751
                        p = pn;
2752
                    }
2753
                } else if (p.id === "}") {
2754
                    // directive with no other statements, warn about missing semicolon
2755
                    warning("Missing semicolon.", p);
2756
                } else if (p.id !== ";") {
2757
                    break;
2758
                }
2759

    
2760
                indentation();
2761
                advance();
2762
                if (directive[token.value]) {
2763
                    warning("Unnecessary directive \"{a}\".", token, token.value);
2764
                }
2765

    
2766
                if (token.value === "use strict") {
2767
                    if (!option["(explicitNewcap)"])
2768
                        option.newcap = true;
2769
                    option.undef = true;
2770
                }
2771

    
2772
                // there's no directive negation, so always set to true
2773
                directive[token.value] = true;
2774

    
2775
                if (p.id === ";") {
2776
                    advance(";");
2777
                }
2778
                continue;
2779
            }
2780
            break;
2781
        }
2782
    }
2783

    
2784

    
2785
    /*
2786
     * Parses a single block. A block is a sequence of statements wrapped in
2787
     * braces.
2788
     *
2789
     * ordinary - true for everything but function bodies and try blocks.
2790
     * stmt     - true if block can be a single statement (e.g. in if/for/while).
2791
     * isfunc   - true if block is a function body
2792
     */
2793
    function block(ordinary, stmt, isfunc) {
2794
        var a,
2795
            b = inblock,
2796
            old_indent = indent,
2797
            m,
2798
            s = scope,
2799
            t,
2800
            line,
2801
            d;
2802

    
2803
        inblock = ordinary;
2804

    
2805
        if (!ordinary || !option.funcscope)
2806
            scope = Object.create(scope);
2807

    
2808
        nonadjacent(token, nexttoken);
2809
        t = nexttoken;
2810

    
2811
        var metrics = funct["(metrics)"];
2812
        metrics.nestedBlockDepth += 1;
2813
        metrics.verifyMaxNestedBlockDepthPerFunction();
2814

    
2815
        if (nexttoken.id === "{") {
2816
            advance("{");
2817
            line = token.line;
2818
            if (nexttoken.id !== "}") {
2819
                indent += option.indent;
2820
                while (!ordinary && nexttoken.from > indent) {
2821
                    indent += option.indent;
2822
                }
2823

    
2824
                if (isfunc) {
2825
                    m = {};
2826
                    for (d in directive) {
2827
                        if (is_own(directive, d)) {
2828
                            m[d] = directive[d];
2829
                        }
2830
                    }
2831
                    directives();
2832

    
2833
                    if (option.strict && funct["(context)"]["(global)"]) {
2834
                        if (!m["use strict"] && !directive["use strict"]) {
2835
                            warning("Missing \"use strict\" statement.");
2836
                        }
2837
                    }
2838
                }
2839

    
2840
                a = statements(line);
2841

    
2842
                metrics.statementCount += a.length;
2843

    
2844
                if (isfunc) {
2845
                    directive = m;
2846
                }
2847

    
2848
                indent -= option.indent;
2849
                if (line !== nexttoken.line) {
2850
                    indentation();
2851
                }
2852
            } else if (line !== nexttoken.line) {
2853
                indentation();
2854
            }
2855
            advance("}", t);
2856
            indent = old_indent;
2857
        } else if (!ordinary) {
2858
            error("Expected '{a}' and instead saw '{b}'.",
2859
                  nexttoken, "{", nexttoken.value);
2860
        } else {
2861
            if (!stmt || option.curly)
2862
                warning("Expected '{a}' and instead saw '{b}'.",
2863
                        nexttoken, "{", nexttoken.value);
2864

    
2865
            noreach = true;
2866
            indent += option.indent;
2867
            // test indentation only if statement is in new line
2868
            a = [statement(nexttoken.line === token.line)];
2869
            indent -= option.indent;
2870
            noreach = false;
2871
        }
2872
        funct["(verb)"] = null;
2873
        if (!ordinary || !option.funcscope) scope = s;
2874
        inblock = b;
2875
        if (ordinary && option.noempty && (!a || a.length === 0)) {
2876
            warning("Empty block.");
2877
        }
2878
        metrics.nestedBlockDepth -= 1;
2879
        return a;
2880
    }
2881

    
2882

    
2883
    function countMember(m) {
2884
        if (membersOnly && typeof membersOnly[m] !== "boolean") {
2885
            warning("Unexpected /*member '{a}'.", token, m);
2886
        }
2887
        if (typeof member[m] === "number") {
2888
            member[m] += 1;
2889
        } else {
2890
            member[m] = 1;
2891
        }
2892
    }
2893

    
2894

    
2895
    function note_implied(token) {
2896
        var name = token.value, line = token.line, a = implied[name];
2897
        if (typeof a === "function") {
2898
            a = false;
2899
        }
2900

    
2901
        if (!a) {
2902
            a = [line];
2903
            implied[name] = a;
2904
        } else if (a[a.length - 1] !== line) {
2905
            a.push(line);
2906
        }
2907
    }
2908

    
2909

    
2910
    // Build the syntax table by declaring the syntactic elements of the language.
2911

    
2912
    type("(number)", function () {
2913
        return this;
2914
    });
2915

    
2916
    type("(string)", function () {
2917
        return this;
2918
    });
2919

    
2920
    syntax["(identifier)"] = {
2921
        type: "(identifier)",
2922
        lbp: 0,
2923
        identifier: true,
2924
        nud: function () {
2925
            var v = this.value,
2926
                s = scope[v],
2927
                f;
2928

    
2929
            if (typeof s === "function") {
2930
                // Protection against accidental inheritance.
2931
                s = undefined;
2932
            } else if (typeof s === "boolean") {
2933
                f = funct;
2934
                funct = functions[0];
2935
                addlabel(v, "var");
2936
                s = funct;
2937
                funct = f;
2938
            }
2939

    
2940
            // The name is in scope and defined in the current function.
2941
            if (funct === s) {
2942
                // Change 'unused' to 'var', and reject labels.
2943
                switch (funct[v]) {
2944
                case "unused":
2945
                    funct[v] = "var";
2946
                    break;
2947
                case "unction":
2948
                    funct[v] = "function";
2949
                    this["function"] = true;
2950
                    break;
2951
                case "function":
2952
                    this["function"] = true;
2953
                    break;
2954
                case "label":
2955
                    warning("'{a}' is a statement label.", token, v);
2956
                    break;
2957
                }
2958
            } else if (funct["(global)"]) {
2959
                // The name is not defined in the function.  If we are in the global
2960
                // scope, then we have an undefined variable.
2961
                //
2962
                // Operators typeof and delete do not raise runtime errors even if
2963
                // the base object of a reference is null so no need to display warning
2964
                // if we're inside of typeof or delete.
2965

    
2966
                if (option.undef && typeof predefined[v] !== "boolean") {
2967
                    // Attempting to subscript a null reference will throw an
2968
                    // error, even within the typeof and delete operators
2969
                    if (!(anonname === "typeof" || anonname === "delete") ||
2970
                        (nexttoken && (nexttoken.value === "." || nexttoken.value === "["))) {
2971

    
2972
                        isundef(funct, "'{a}' is not defined.", token, v);
2973
                    }
2974
                }
2975

    
2976
                note_implied(token);
2977
            } else {
2978
                // If the name is already defined in the current
2979
                // function, but not as outer, then there is a scope error.
2980

    
2981
                switch (funct[v]) {
2982
                case "closure":
2983
                case "function":
2984
                case "var":
2985
                case "unused":
2986
                    warning("'{a}' used out of scope.", token, v);
2987
                    break;
2988
                case "label":
2989
                    warning("'{a}' is a statement label.", token, v);
2990
                    break;
2991
                case "outer":
2992
                case "global":
2993
                    break;
2994
                default:
2995
                    // If the name is defined in an outer function, make an outer entry,
2996
                    // and if it was unused, make it var.
2997
                    if (s === true) {
2998
                        funct[v] = true;
2999
                    } else if (s === null) {
3000
                        warning("'{a}' is not allowed.", token, v);
3001
                        note_implied(token);
3002
                    } else if (typeof s !== "object") {
3003
                        // Operators typeof and delete do not raise runtime errors even
3004
                        // if the base object of a reference is null so no need to
3005
                        // display warning if we're inside of typeof or delete.
3006
                        if (option.undef) {
3007
                            // Attempting to subscript a null reference will throw an
3008
                            // error, even within the typeof and delete operators
3009
                            if (!(anonname === "typeof" || anonname === "delete") ||
3010
                                (nexttoken &&
3011
                                    (nexttoken.value === "." || nexttoken.value === "["))) {
3012

    
3013
                                isundef(funct, "'{a}' is not defined.", token, v);
3014
                            }
3015
                        }
3016
                        funct[v] = true;
3017
                        note_implied(token);
3018
                    } else {
3019
                        switch (s[v]) {
3020
                        case "function":
3021
                        case "unction":
3022
                            this["function"] = true;
3023
                            s[v] = "closure";
3024
                            funct[v] = s["(global)"] ? "global" : "outer";
3025
                            break;
3026
                        case "var":
3027
                        case "unused":
3028
                            s[v] = "closure";
3029
                            funct[v] = s["(global)"] ? "global" : "outer";
3030
                            break;
3031
                        case "closure":
3032
                            funct[v] = s["(global)"] ? "global" : "outer";
3033
                            break;
3034
                        case "label":
3035
                            warning("'{a}' is a statement label.", token, v);
3036
                        }
3037
                    }
3038
                }
3039
            }
3040
            return this;
3041
        },
3042
        led: function () {
3043
            error("Expected an operator and instead saw '{a}'.",
3044
                nexttoken, nexttoken.value);
3045
        }
3046
    };
3047

    
3048
    type("(regexp)", function () {
3049
        return this;
3050
    });
3051

    
3052

    
3053
// ECMAScript parser
3054

    
3055
    delim("(endline)");
3056
    delim("(begin)");
3057
    delim("(end)").reach = true;
3058
    delim("</").reach = true;
3059
    delim("<!");
3060
    delim("<!--");
3061
    delim("-->");
3062
    delim("(error)").reach = true;
3063
    delim("}").reach = true;
3064
    delim(")");
3065
    delim("]");
3066
    delim("\"").reach = true;
3067
    delim("'").reach = true;
3068
    delim(";");
3069
    delim(":").reach = true;
3070
    delim(",");
3071
    delim("#");
3072
    delim("@");
3073
    reserve("else");
3074
    reserve("case").reach = true;
3075
    reserve("catch");
3076
    reserve("default").reach = true;
3077
    reserve("finally");
3078
    reservevar("arguments", function (x) {
3079
        if (directive["use strict"] && funct["(global)"]) {
3080
            warning("Strict violation.", x);
3081
        }
3082
    });
3083
    reservevar("eval");
3084
    reservevar("false");
3085
    reservevar("Infinity");
3086
    reservevar("null");
3087
    reservevar("this", function (x) {
3088
        if (directive["use strict"] && !option.validthis && ((funct["(statement)"] &&
3089
                funct["(name)"].charAt(0) > "Z") || funct["(global)"])) {
3090
            warning("Possible strict violation.", x);
3091
        }
3092
    });
3093
    reservevar("true");
3094
    reservevar("undefined");
3095
    assignop("=", "assign", 20);
3096
    assignop("+=", "assignadd", 20);
3097
    assignop("-=", "assignsub", 20);
3098
    assignop("*=", "assignmult", 20);
3099
    assignop("/=", "assigndiv", 20).nud = function () {
3100
        error("A regular expression literal can be confused with '/='.");
3101
    };
3102
    assignop("%=", "assignmod", 20);
3103
    bitwiseassignop("&=", "assignbitand", 20);
3104
    bitwiseassignop("|=", "assignbitor", 20);
3105
    bitwiseassignop("^=", "assignbitxor", 20);
3106
    bitwiseassignop("<<=", "assignshiftleft", 20);
3107
    bitwiseassignop(">>=", "assignshiftright", 20);
3108
    bitwiseassignop(">>>=", "assignshiftrightunsigned", 20);
3109
    infix("?", function (left, that) {
3110
        that.left = left;
3111
        that.right = expression(10);
3112
        advance(":");
3113
        that["else"] = expression(10);
3114
        return that;
3115
    }, 30);
3116

    
3117
    infix("||", "or", 40);
3118
    infix("&&", "and", 50);
3119
    bitwise("|", "bitor", 70);
3120
    bitwise("^", "bitxor", 80);
3121
    bitwise("&", "bitand", 90);
3122
    relation("==", function (left, right) {
3123
        var eqnull = option.eqnull && (left.value === "null" || right.value === "null");
3124

    
3125
        if (!eqnull && option.eqeqeq)
3126
            warning("Expected '{a}' and instead saw '{b}'.", this, "===", "==");
3127
        else if (isPoorRelation(left))
3128
            warning("Use '{a}' to compare with '{b}'.", this, "===", left.value);
3129
        else if (isPoorRelation(right))
3130
            warning("Use '{a}' to compare with '{b}'.", this, "===", right.value);
3131

    
3132
        return this;
3133
    });
3134
    relation("===");
3135
    relation("!=", function (left, right) {
3136
        var eqnull = option.eqnull &&
3137
                (left.value === "null" || right.value === "null");
3138

    
3139
        if (!eqnull && option.eqeqeq) {
3140
            warning("Expected '{a}' and instead saw '{b}'.",
3141
                    this, "!==", "!=");
3142
        } else if (isPoorRelation(left)) {
3143
            warning("Use '{a}' to compare with '{b}'.",
3144
                    this, "!==", left.value);
3145
        } else if (isPoorRelation(right)) {
3146
            warning("Use '{a}' to compare with '{b}'.",
3147
                    this, "!==", right.value);
3148
        }
3149
        return this;
3150
    });
3151
    relation("!==");
3152
    relation("<");
3153
    relation(">");
3154
    relation("<=");
3155
    relation(">=");
3156
    bitwise("<<", "shiftleft", 120);
3157
    bitwise(">>", "shiftright", 120);
3158
    bitwise(">>>", "shiftrightunsigned", 120);
3159
    infix("in", "in", 120);
3160
    infix("instanceof", "instanceof", 120);
3161
    infix("+", function (left, that) {
3162
        var right = expression(130);
3163
        if (left && right && left.id === "(string)" && right.id === "(string)") {
3164
            left.value += right.value;
3165
            left.character = right.character;
3166
            if (!option.scripturl && jx.test(left.value)) {
3167
                warning("JavaScript URL.", left);
3168
            }
3169
            return left;
3170
        }
3171
        that.left = left;
3172
        that.right = right;
3173
        return that;
3174
    }, 130);
3175
    prefix("+", "num");
3176
    prefix("+++", function () {
3177
        warning("Confusing pluses.");
3178
        this.right = expression(150);
3179
        this.arity = "unary";
3180
        return this;
3181
    });
3182
    infix("+++", function (left) {
3183
        warning("Confusing pluses.");
3184
        this.left = left;
3185
        this.right = expression(130);
3186
        return this;
3187
    }, 130);
3188
    infix("-", "sub", 130);
3189
    prefix("-", "neg");
3190
    prefix("---", function () {
3191
        warning("Confusing minuses.");
3192
        this.right = expression(150);
3193
        this.arity = "unary";
3194
        return this;
3195
    });
3196
    infix("---", function (left) {
3197
        warning("Confusing minuses.");
3198
        this.left = left;
3199
        this.right = expression(130);
3200
        return this;
3201
    }, 130);
3202
    infix("*", "mult", 140);
3203
    infix("/", "div", 140);
3204
    infix("%", "mod", 140);
3205

    
3206
    suffix("++", "postinc");
3207
    prefix("++", "preinc");
3208
    syntax["++"].exps = true;
3209

    
3210
    suffix("--", "postdec");
3211
    prefix("--", "predec");
3212
    syntax["--"].exps = true;
3213
    prefix("delete", function () {
3214
        var p = expression(0);
3215
        if (!p || (p.id !== "." && p.id !== "[")) {
3216
            warning("Variables should not be deleted.");
3217
        }
3218
        this.first = p;
3219
        return this;
3220
    }).exps = true;
3221

    
3222
    prefix("~", function () {
3223
        if (option.bitwise) {
3224
            warning("Unexpected '{a}'.", this, "~");
3225
        }
3226
        expression(150);
3227
        return this;
3228
    });
3229

    
3230
    prefix("!", function () {
3231
        this.right = expression(150);
3232
        this.arity = "unary";
3233
        if (bang[this.right.id] === true) {
3234
            warning("Confusing use of '{a}'.", this, "!");
3235
        }
3236
        return this;
3237
    });
3238
    prefix("typeof", "typeof");
3239
    prefix("new", function () {
3240
        var c = expression(155), i;
3241
        if (c && c.id !== "function") {
3242
            if (c.identifier) {
3243
                c["new"] = true;
3244
                switch (c.value) {
3245
                case "Number":
3246
                case "String":
3247
                case "Boolean":
3248
                case "Math":
3249
                case "JSON":
3250
                    warning("Do not use {a} as a constructor.", prevtoken, c.value);
3251
                    break;
3252
                case "Function":
3253
                    if (!option.evil) {
3254
                        warning("The Function constructor is eval.");
3255
                    }
3256
                    break;
3257
                case "Date":
3258
                case "RegExp":
3259
                    break;
3260
                default:
3261
                    if (c.id !== "function") {
3262
                        i = c.value.substr(0, 1);
3263
                        if (option.newcap && (i < "A" || i > "Z") && !is_own(global, c.value)) {
3264
                            warning("A constructor name should start with an uppercase letter.",
3265
                                token);
3266
                        }
3267
                    }
3268
                }
3269
            } else {
3270
                if (c.id !== "." && c.id !== "[" && c.id !== "(") {
3271
                    warning("Bad constructor.", token);
3272
                }
3273
            }
3274
        } else {
3275
            if (!option.supernew)
3276
                warning("Weird construction. Delete 'new'.", this);
3277
        }
3278
        adjacent(token, nexttoken);
3279
        if (nexttoken.id !== "(" && !option.supernew) {
3280
            warning("Missing '()' invoking a constructor.",
3281
                token, token.value);
3282
        }
3283
        this.first = c;
3284
        return this;
3285
    });
3286
    syntax["new"].exps = true;
3287

    
3288
    prefix("void").exps = true;
3289

    
3290
    infix(".", function (left, that) {
3291
        adjacent(prevtoken, token);
3292
        nobreak();
3293
        var m = identifier();
3294
        if (typeof m === "string") {
3295
            countMember(m);
3296
        }
3297
        that.left = left;
3298
        that.right = m;
3299
        if (left && left.value === "arguments" && (m === "callee" || m === "caller")) {
3300
            if (option.noarg)
3301
                warning("Avoid arguments.{a}.", left, m);
3302
            else if (directive["use strict"])
3303
                error("Strict violation.");
3304
        } else if (!option.evil && left && left.value === "document" &&
3305
                (m === "write" || m === "writeln")) {
3306
            warning("document.write can be a form of eval.", left);
3307
        }
3308
        if (!option.evil && (m === "eval" || m === "execScript")) {
3309
            warning("eval is evil.");
3310
        }
3311
        return that;
3312
    }, 160, true);
3313

    
3314
    infix("(", function (left, that) {
3315
        if (prevtoken.id !== "}" && prevtoken.id !== ")") {
3316
            nobreak(prevtoken, token);
3317
        }
3318
        nospace();
3319
        if (option.immed && !left.immed && left.id === "function") {
3320
            warning("Wrap an immediate function invocation in parentheses " +
3321
                "to assist the reader in understanding that the expression " +
3322
                "is the result of a function, and not the function itself.");
3323
        }
3324
        var n = 0,
3325
            p = [];
3326
        if (left) {
3327
            if (left.type === "(identifier)") {
3328
                if (left.value.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)) {
3329
                    if ("Number String Boolean Date Object".indexOf(left.value) === -1) {
3330
                        if (left.value === "Math") {
3331
                            warning("Math is not a function.", left);
3332
                        } else if (option.newcap) {
3333
                            warning("Missing 'new' prefix when invoking a constructor.", left);
3334
                        }
3335
                    }
3336
                }
3337
            }
3338
        }
3339
        if (nexttoken.id !== ")") {
3340
            for (;;) {
3341
                p[p.length] = expression(10);
3342
                n += 1;
3343
                if (nexttoken.id !== ",") {
3344
                    break;
3345
                }
3346
                comma();
3347
            }
3348
        }
3349
        advance(")");
3350
        nospace(prevtoken, token);
3351
        if (typeof left === "object") {
3352
            if (left.value === "parseInt" && n === 1) {
3353
                warning("Missing radix parameter.", token);
3354
            }
3355
            if (!option.evil) {
3356
                if (left.value === "eval" || left.value === "Function" ||
3357
                        left.value === "execScript") {
3358
                    warning("eval is evil.", left);
3359

    
3360
                    if (p[0] && [0].id === "(string)") {
3361
                        addInternalSrc(left, p[0].value);
3362
                    }
3363
                } else if (p[0] && p[0].id === "(string)" &&
3364
                       (left.value === "setTimeout" ||
3365
                        left.value === "setInterval")) {
3366
                    warning(
3367
    "Implied eval is evil. Pass a function instead of a string.", left);
3368
                    addInternalSrc(left, p[0].value);
3369

    
3370
                // window.setTimeout/setInterval
3371
                } else if (p[0] && p[0].id === "(string)" &&
3372
                       left.value === "." &&
3373
                       left.left.value === "window" &&
3374
                       (left.right === "setTimeout" ||
3375
                        left.right === "setInterval")) {
3376
                    warning(
3377
    "Implied eval is evil. Pass a function instead of a string.", left);
3378
                    addInternalSrc(left, p[0].value);
3379
                }
3380
            }
3381
            if (!left.identifier && left.id !== "." && left.id !== "[" &&
3382
                    left.id !== "(" && left.id !== "&&" && left.id !== "||" &&
3383
                    left.id !== "?") {
3384
                warning("Bad invocation.", left);
3385
            }
3386
        }
3387
        that.left = left;
3388
        return that;
3389
    }, 155, true).exps = true;
3390

    
3391
    prefix("(", function () {
3392
        nospace();
3393
        if (nexttoken.id === "function") {
3394
            nexttoken.immed = true;
3395
        }
3396
        var v = expression(0);
3397
        advance(")", this);
3398
        nospace(prevtoken, token);
3399
        if (option.immed && v.id === "function") {
3400
            if (nexttoken.id !== "(" &&
3401
              (nexttoken.id !== "." || (peek().value !== "call" && peek().value !== "apply"))) {
3402
                warning(
3403
"Do not wrap function literals in parens unless they are to be immediately invoked.",
3404
                        this);
3405
            }
3406
        }
3407

    
3408
        return v;
3409
    });
3410

    
3411
    infix("[", function (left, that) {
3412
        nobreak(prevtoken, token);
3413
        nospace();
3414
        var e = expression(0), s;
3415
        if (e && e.type === "(string)") {
3416
            if (!option.evil && (e.value === "eval" || e.value === "execScript")) {
3417
                warning("eval is evil.", that);
3418
            }
3419
            countMember(e.value);
3420
            if (!option.sub && ix.test(e.value)) {
3421
                s = syntax[e.value];
3422
                if (!s || !s.reserved) {
3423
                    warning("['{a}'] is better written in dot notation.",
3424
                            prevtoken, e.value);
3425
                }
3426
            }
3427
        }
3428
        advance("]", that);
3429
        nospace(prevtoken, token);
3430
        that.left = left;
3431
        that.right = e;
3432
        return that;
3433
    }, 160, true);
3434

    
3435
    prefix("[", function () {
3436
        var b = token.line !== nexttoken.line;
3437
        this.first = [];
3438
        if (b) {
3439
            indent += option.indent;
3440
            if (nexttoken.from === indent + option.indent) {
3441
                indent += option.indent;
3442
            }
3443
        }
3444
        while (nexttoken.id !== "(end)") {
3445
            while (nexttoken.id === ",") {
3446
                if (!option.es5)
3447
                    warning("Extra comma.");
3448
                advance(",");
3449
            }
3450
            if (nexttoken.id === "]") {
3451
                break;
3452
            }
3453
            if (b && token.line !== nexttoken.line) {
3454
                indentation();
3455
            }
3456
            this.first.push(expression(10));
3457
            if (nexttoken.id === ",") {
3458
                comma();
3459
                if (nexttoken.id === "]" && !option.es5) {
3460
                    warning("Extra comma.", token);
3461
                    break;
3462
                }
3463
            } else {
3464
                break;
3465
            }
3466
        }
3467
        if (b) {
3468
            indent -= option.indent;
3469
            indentation();
3470
        }
3471
        advance("]", this);
3472
        return this;
3473
    }, 160);
3474

    
3475

    
3476
    function property_name() {
3477
        var id = optionalidentifier(true);
3478
        if (!id) {
3479
            if (nexttoken.id === "(string)") {
3480
                id = nexttoken.value;
3481
                advance();
3482
            } else if (nexttoken.id === "(number)") {
3483
                id = nexttoken.value.toString();
3484
                advance();
3485
            }
3486
        }
3487
        return id;
3488
    }
3489

    
3490

    
3491
    function functionparams() {
3492
        var next   = nexttoken;
3493
        var params = [];
3494
        var ident;
3495

    
3496
        advance("(");
3497
        nospace();
3498

    
3499
        if (nexttoken.id === ")") {
3500
            advance(")");
3501
            return;
3502
        }
3503

    
3504
        for (;;) {
3505
            ident = identifier(true);
3506
            params.push(ident);
3507
            addlabel(ident, "unused", token);
3508
            if (nexttoken.id === ",") {
3509
                comma();
3510
            } else {
3511
                advance(")", next);
3512
                nospace(prevtoken, token);
3513
                return params;
3514
            }
3515
        }
3516
    }
3517

    
3518

    
3519
    function doFunction(name, statement) {
3520
        var f;
3521
        var oldOption = option;
3522
        var oldScope  = scope;
3523

    
3524
        option = Object.create(option);
3525
        scope  = Object.create(scope);
3526

    
3527
        funct = {
3528
            "(name)"     : name || "\"" + anonname + "\"",
3529
            "(line)"     : nexttoken.line,
3530
            "(character)": nexttoken.character,
3531
            "(context)"  : funct,
3532
            "(breakage)" : 0,
3533
            "(loopage)"  : 0,
3534
            "(metrics)"  : createMetrics(nexttoken),
3535
            "(scope)"    : scope,
3536
            "(statement)": statement,
3537
            "(tokens)"   : {}
3538
        };
3539

    
3540
        f = funct;
3541
        token.funct = funct;
3542

    
3543
        functions.push(funct);
3544

    
3545
        if (name) {
3546
            addlabel(name, "function");
3547
        }
3548

    
3549
        funct["(params)"] = functionparams();
3550
        funct["(metrics)"].verifyMaxParametersPerFunction(funct["(params)"]);
3551

    
3552
        block(false, false, true);
3553

    
3554
        funct["(metrics)"].verifyMaxStatementsPerFunction();
3555
        funct["(metrics)"].verifyMaxComplexityPerFunction();
3556

    
3557
        scope = oldScope;
3558
        option = oldOption;
3559
        funct["(last)"] = token.line;
3560
        funct["(lastcharacter)"] = token.character;
3561
        funct = funct["(context)"];
3562

    
3563
        return f;
3564
    }
3565

    
3566
    function createMetrics(functionStartToken) {
3567
        return {
3568
            statementCount: 0,
3569
            nestedBlockDepth: -1,
3570
            ComplexityCount: 1,
3571
            verifyMaxStatementsPerFunction: function () {
3572
                if (option.maxstatements &&
3573
                    this.statementCount > option.maxstatements) {
3574
                    var message = "Too many statements per function (" + this.statementCount + ").";
3575
                    warning(message, functionStartToken);
3576
                }
3577
            },
3578

    
3579
            verifyMaxParametersPerFunction: function (params) {
3580
                params = params || [];
3581

    
3582
                if (option.maxparams && params.length > option.maxparams) {
3583
                    var message = "Too many parameters per function (" + params.length + ").";
3584
                    warning(message, functionStartToken);
3585
                }
3586
            },
3587

    
3588
            verifyMaxNestedBlockDepthPerFunction: function () {
3589
                if (option.maxdepth &&
3590
                    this.nestedBlockDepth > 0 &&
3591
                    this.nestedBlockDepth === option.maxdepth + 1) {
3592
                    var message = "Blocks are nested too deeply (" + this.nestedBlockDepth + ").";
3593
                    warning(message);
3594
                }
3595
            },
3596

    
3597
            verifyMaxComplexityPerFunction: function () {
3598
                var max = option.maxcomplexity;
3599
                var cc = this.ComplexityCount;
3600
                if (max && cc > max) {
3601
                    var message = "Cyclomatic complexity is too high per function (" + cc + ").";
3602
                    warning(message, functionStartToken);
3603
                }
3604
            }
3605
        };
3606
    }
3607

    
3608
    function increaseComplexityCount() {
3609
        funct["(metrics)"].ComplexityCount += 1;
3610
    }
3611

    
3612

    
3613
    (function (x) {
3614
        x.nud = function () {
3615
            var b, f, i, p, t;
3616
            var props = {}; // All properties, including accessors
3617

    
3618
            function saveProperty(name, token) {
3619
                if (props[name] && is_own(props, name))
3620
                    warning("Duplicate member '{a}'.", nexttoken, i);
3621
                else
3622
                    props[name] = {};
3623

    
3624
                props[name].basic = true;
3625
                props[name].basicToken = token;
3626
            }
3627

    
3628
            function saveSetter(name, token) {
3629
                if (props[name] && is_own(props, name)) {
3630
                    if (props[name].basic || props[name].setter)
3631
                        warning("Duplicate member '{a}'.", nexttoken, i);
3632
                } else {
3633
                    props[name] = {};
3634
                }
3635

    
3636
                props[name].setter = true;
3637
                props[name].setterToken = token;
3638
            }
3639

    
3640
            function saveGetter(name) {
3641
                if (props[name] && is_own(props, name)) {
3642
                    if (props[name].basic || props[name].getter)
3643
                        warning("Duplicate member '{a}'.", nexttoken, i);
3644
                } else {
3645
                    props[name] = {};
3646
                }
3647

    
3648
                props[name].getter = true;
3649
                props[name].getterToken = token;
3650
            }
3651

    
3652
            b = token.line !== nexttoken.line;
3653
            if (b) {
3654
                indent += option.indent;
3655
                if (nexttoken.from === indent + option.indent) {
3656
                    indent += option.indent;
3657
                }
3658
            }
3659
            for (;;) {
3660
                if (nexttoken.id === "}") {
3661
                    break;
3662
                }
3663
                if (b) {
3664
                    indentation();
3665
                }
3666
                if (nexttoken.value === "get" && peek().id !== ":") {
3667
                    advance("get");
3668
                    if (!option.es5) {
3669
                        error("get/set are ES5 features.");
3670
                    }
3671
                    i = property_name();
3672
                    if (!i) {
3673
                        error("Missing property name.");
3674
                    }
3675
                    saveGetter(i);
3676
                    t = nexttoken;
3677
                    adjacent(token, nexttoken);
3678
                    f = doFunction();
3679
                    p = f["(params)"];
3680
                    if (p) {
3681
                        warning("Unexpected parameter '{a}' in get {b} function.", t, p[0], i);
3682
                    }
3683
                    adjacent(token, nexttoken);
3684
                } else if (nexttoken.value === "set" && peek().id !== ":") {
3685
                    advance("set");
3686
                    if (!option.es5) {
3687
                        error("get/set are ES5 features.");
3688
                    }
3689
                    i = property_name();
3690
                    if (!i) {
3691
                        error("Missing property name.");
3692
                    }
3693
                    saveSetter(i, nexttoken);
3694
                    t = nexttoken;
3695
                    adjacent(token, nexttoken);
3696
                    f = doFunction();
3697
                    p = f["(params)"];
3698
                    if (!p || p.length !== 1) {
3699
                        warning("Expected a single parameter in set {a} function.", t, i);
3700
                    }
3701
                } else {
3702
                    i = property_name();
3703
                    saveProperty(i, nexttoken);
3704
                    if (typeof i !== "string") {
3705
                        break;
3706
                    }
3707
                    advance(":");
3708
                    nonadjacent(token, nexttoken);
3709
                    expression(10);
3710
                }
3711

    
3712
                countMember(i);
3713
                if (nexttoken.id === ",") {
3714
                    comma();
3715
                    if (nexttoken.id === ",") {
3716
                        warning("Extra comma.", token);
3717
                    } else if (nexttoken.id === "}" && !option.es5) {
3718
                        warning("Extra comma.", token);
3719
                    }
3720
                } else {
3721
                    break;
3722
                }
3723
            }
3724
            if (b) {
3725
                indent -= option.indent;
3726
                indentation();
3727
            }
3728
            advance("}", this);
3729

    
3730
            // Check for lonely setters if in the ES5 mode.
3731
            if (option.es5) {
3732
                for (var name in props) {
3733
                    if (is_own(props, name) && props[name].setter && !props[name].getter) {
3734
                        warning("Setter is defined without getter.", props[name].setterToken);
3735
                    }
3736
                }
3737
            }
3738
            return this;
3739
        };
3740
        x.fud = function () {
3741
            error("Expected to see a statement and instead saw a block.", token);
3742
        };
3743
    }(delim("{")));
3744

    
3745
// This Function is called when esnext option is set to true
3746
// it adds the `const` statement to JSHINT
3747

    
3748
    useESNextSyntax = function () {
3749
        var conststatement = stmt("const", function (prefix) {
3750
            var id, name, value;
3751

    
3752
            this.first = [];
3753
            for (;;) {
3754
                nonadjacent(token, nexttoken);
3755
                id = identifier();
3756
                if (funct[id] === "const") {
3757
                    warning("const '" + id + "' has already been declared");
3758
                }
3759
                if (funct["(global)"] && predefined[id] === false) {
3760
                    warning("Redefinition of '{a}'.", token, id);
3761
                }
3762
                addlabel(id, "const");
3763
                if (prefix) {
3764
                    break;
3765
                }
3766
                name = token;
3767
                this.first.push(token);
3768

    
3769
                if (nexttoken.id !== "=") {
3770
                    warning("const " +
3771
                      "'{a}' is initialized to 'undefined'.", token, id);
3772
                }
3773

    
3774
                if (nexttoken.id === "=") {
3775
                    nonadjacent(token, nexttoken);
3776
                    advance("=");
3777
                    nonadjacent(token, nexttoken);
3778
                    if (nexttoken.id === "undefined") {
3779
                        warning("It is not necessary to initialize " +
3780
                          "'{a}' to 'undefined'.", token, id);
3781
                    }
3782
                    if (peek(0).id === "=" && nexttoken.identifier) {
3783
                        error("Constant {a} was not declared correctly.",
3784
                                nexttoken, nexttoken.value);
3785
                    }
3786
                    value = expression(0);
3787
                    name.first = value;
3788
                }
3789

    
3790
                if (nexttoken.id !== ",") {
3791
                    break;
3792
                }
3793
                comma();
3794
            }
3795
            return this;
3796
        });
3797
        conststatement.exps = true;
3798
    };
3799

    
3800
    var varstatement = stmt("var", function (prefix) {
3801
        // JavaScript does not have block scope. It only has function scope. So,
3802
        // declaring a variable in a block can have unexpected consequences.
3803
        var id, name, value;
3804

    
3805
        if (funct["(onevar)"] && option.onevar) {
3806
            warning("Too many var statements.");
3807
        } else if (!funct["(global)"]) {
3808
            funct["(onevar)"] = true;
3809
        }
3810

    
3811
        this.first = [];
3812

    
3813
        for (;;) {
3814
            nonadjacent(token, nexttoken);
3815
            id = identifier();
3816

    
3817
            if (option.esnext && funct[id] === "const") {
3818
                warning("const '" + id + "' has already been declared");
3819
            }
3820

    
3821
            if (funct["(global)"] && predefined[id] === false) {
3822
                warning("Redefinition of '{a}'.", token, id);
3823
            }
3824

    
3825
            addlabel(id, "unused", token);
3826

    
3827
            if (prefix) {
3828
                break;
3829
            }
3830

    
3831
            name = token;
3832
            this.first.push(token);
3833

    
3834
            if (nexttoken.id === "=") {
3835
                nonadjacent(token, nexttoken);
3836
                advance("=");
3837
                nonadjacent(token, nexttoken);
3838
                if (nexttoken.id === "undefined") {
3839
                    warning("It is not necessary to initialize '{a}' to 'undefined'.", token, id);
3840
                }
3841
                if (peek(0).id === "=" && nexttoken.identifier) {
3842
                    error("Variable {a} was not declared correctly.",
3843
                            nexttoken, nexttoken.value);
3844
                }
3845
                value = expression(0);
3846
                name.first = value;
3847
            }
3848
            if (nexttoken.id !== ",") {
3849
                break;
3850
            }
3851
            comma();
3852
        }
3853
        return this;
3854
    });
3855
    varstatement.exps = true;
3856

    
3857
    blockstmt("function", function () {
3858
        if (inblock) {
3859
            warning("Function declarations should not be placed in blocks. " +
3860
                "Use a function expression or move the statement to the top of " +
3861
                "the outer function.", token);
3862

    
3863
        }
3864
        var i = identifier();
3865
        if (option.esnext && funct[i] === "const") {
3866
            warning("const '" + i + "' has already been declared");
3867
        }
3868
        adjacent(token, nexttoken);
3869
        addlabel(i, "unction", token);
3870

    
3871
        doFunction(i, { statement: true });
3872
        if (nexttoken.id === "(" && nexttoken.line === token.line) {
3873
            error(
3874
"Function declarations are not invocable. Wrap the whole function invocation in parens.");
3875
        }
3876
        return this;
3877
    });
3878

    
3879
    prefix("function", function () {
3880
        var i = optionalidentifier();
3881
        if (i) {
3882
            adjacent(token, nexttoken);
3883
        } else {
3884
            nonadjacent(token, nexttoken);
3885
        }
3886
        doFunction(i);
3887
        if (!option.loopfunc && funct["(loopage)"]) {
3888
            warning("Don't make functions within a loop.");
3889
        }
3890
        return this;
3891
    });
3892

    
3893
    blockstmt("if", function () {
3894
        var t = nexttoken;
3895
        increaseComplexityCount();
3896
        advance("(");
3897
        nonadjacent(this, t);
3898
        nospace();
3899
        expression(20);
3900
        if (nexttoken.id === "=") {
3901
            if (!option.boss)
3902
                warning("Expected a conditional expression and instead saw an assignment.");
3903
            advance("=");
3904
            expression(20);
3905
        }
3906
        advance(")", t);
3907
        nospace(prevtoken, token);
3908
        block(true, true);
3909
        if (nexttoken.id === "else") {
3910
            nonadjacent(token, nexttoken);
3911
            advance("else");
3912
            if (nexttoken.id === "if" || nexttoken.id === "switch") {
3913
                statement(true);
3914
            } else {
3915
                block(true, true);
3916
            }
3917
        }
3918
        return this;
3919
    });
3920

    
3921
    blockstmt("try", function () {
3922
        var b;
3923

    
3924
        function doCatch() {
3925
            var oldScope = scope;
3926
            var e;
3927

    
3928
            advance("catch");
3929
            nonadjacent(token, nexttoken);
3930
            advance("(");
3931

    
3932
            scope = Object.create(oldScope);
3933

    
3934
            e = nexttoken.value;
3935
            if (nexttoken.type !== "(identifier)") {
3936
                e = null;
3937
                warning("Expected an identifier and instead saw '{a}'.", nexttoken, e);
3938
            }
3939

    
3940
            advance();
3941
            advance(")");
3942

    
3943
            funct = {
3944
                "(name)"     : "(catch)",
3945
                "(line)"     : nexttoken.line,
3946
                "(character)": nexttoken.character,
3947
                "(context)"  : funct,
3948
                "(breakage)" : funct["(breakage)"],
3949
                "(loopage)"  : funct["(loopage)"],
3950
                "(scope)"    : scope,
3951
                "(statement)": false,
3952
                "(metrics)"  : createMetrics(nexttoken),
3953
                "(catch)"    : true,
3954
                "(tokens)"   : {}
3955
            };
3956

    
3957
            if (e) {
3958
                addlabel(e, "exception");
3959
            }
3960

    
3961
            token.funct = funct;
3962
            functions.push(funct);
3963

    
3964
            block(false);
3965

    
3966
            scope = oldScope;
3967

    
3968
            funct["(last)"] = token.line;
3969
            funct["(lastcharacter)"] = token.character;
3970
            funct = funct["(context)"];
3971
        }
3972

    
3973
        block(false);
3974

    
3975
        if (nexttoken.id === "catch") {
3976
            increaseComplexityCount();
3977
            doCatch();
3978
            b = true;
3979
        }
3980

    
3981
        if (nexttoken.id === "finally") {
3982
            advance("finally");
3983
            block(false);
3984
            return;
3985
        } else if (!b) {
3986
            error("Expected '{a}' and instead saw '{b}'.",
3987
                    nexttoken, "catch", nexttoken.value);
3988
        }
3989

    
3990
        return this;
3991
    });
3992

    
3993
    blockstmt("while", function () {
3994
        var t = nexttoken;
3995
        funct["(breakage)"] += 1;
3996
        funct["(loopage)"] += 1;
3997
        increaseComplexityCount();
3998
        advance("(");
3999
        nonadjacent(this, t);
4000
        nospace();
4001
        expression(20);
4002
        if (nexttoken.id === "=") {
4003
            if (!option.boss)
4004
                warning("Expected a conditional expression and instead saw an assignment.");
4005
            advance("=");
4006
            expression(20);
4007
        }
4008
        advance(")", t);
4009
        nospace(prevtoken, token);
4010
        block(true, true);
4011
        funct["(breakage)"] -= 1;
4012
        funct["(loopage)"] -= 1;
4013
        return this;
4014
    }).labelled = true;
4015

    
4016
    blockstmt("with", function () {
4017
        var t = nexttoken;
4018
        if (directive["use strict"]) {
4019
            error("'with' is not allowed in strict mode.", token);
4020
        } else if (!option.withstmt) {
4021
            warning("Don't use 'with'.", token);
4022
        }
4023

    
4024
        advance("(");
4025
        nonadjacent(this, t);
4026
        nospace();
4027
        expression(0);
4028
        advance(")", t);
4029
        nospace(prevtoken, token);
4030
        block(true, true);
4031

    
4032
        return this;
4033
    });
4034

    
4035
    blockstmt("switch", function () {
4036
        var t = nexttoken,
4037
            g = false;
4038
        funct["(breakage)"] += 1;
4039
        advance("(");
4040
        nonadjacent(this, t);
4041
        nospace();
4042
        this.condition = expression(20);
4043
        advance(")", t);
4044
        nospace(prevtoken, token);
4045
        nonadjacent(token, nexttoken);
4046
        t = nexttoken;
4047
        advance("{");
4048
        nonadjacent(token, nexttoken);
4049
        indent += option.indent;
4050
        this.cases = [];
4051
        for (;;) {
4052
            switch (nexttoken.id) {
4053
            case "case":
4054
                switch (funct["(verb)"]) {
4055
                case "break":
4056
                case "case":
4057
                case "continue":
4058
                case "return":
4059
                case "switch":
4060
                case "throw":
4061
                    break;
4062
                default:
4063
                    // You can tell JSHint that you don't use break intentionally by
4064
                    // adding a comment /* falls through */ on a line just before
4065
                    // the next `case`.
4066
                    if (!ft.test(lines[nexttoken.line - 2])) {
4067
                        warning(
4068
                            "Expected a 'break' statement before 'case'.",
4069
                            token);
4070
                    }
4071
                }
4072
                indentation(-option.indent);
4073
                advance("case");
4074
                this.cases.push(expression(20));
4075
                increaseComplexityCount();
4076
                g = true;
4077
                advance(":");
4078
                funct["(verb)"] = "case";
4079
                break;
4080
            case "default":
4081
                switch (funct["(verb)"]) {
4082
                case "break":
4083
                case "continue":
4084
                case "return":
4085
                case "throw":
4086
                    break;
4087
                default:
4088
                    if (!ft.test(lines[nexttoken.line - 2])) {
4089
                        warning(
4090
                            "Expected a 'break' statement before 'default'.",
4091
                            token);
4092
                    }
4093
                }
4094
                indentation(-option.indent);
4095
                advance("default");
4096
                g = true;
4097
                advance(":");
4098
                break;
4099
            case "}":
4100
                indent -= option.indent;
4101
                indentation();
4102
                advance("}", t);
4103
                if (this.cases.length === 1 || this.condition.id === "true" ||
4104
                        this.condition.id === "false") {
4105
                    if (!option.onecase)
4106
                        warning("This 'switch' should be an 'if'.", this);
4107
                }
4108
                funct["(breakage)"] -= 1;
4109
                funct["(verb)"] = undefined;
4110
                return;
4111
            case "(end)":
4112
                error("Missing '{a}'.", nexttoken, "}");
4113
                return;
4114
            default:
4115
                if (g) {
4116
                    switch (token.id) {
4117
                    case ",":
4118
                        error("Each value should have its own case label.");
4119
                        return;
4120
                    case ":":
4121
                        g = false;
4122
                        statements();
4123
                        break;
4124
                    default:
4125
                        error("Missing ':' on a case clause.", token);
4126
                        return;
4127
                    }
4128
                } else {
4129
                    if (token.id === ":") {
4130
                        advance(":");
4131
                        error("Unexpected '{a}'.", token, ":");
4132
                        statements();
4133
                    } else {
4134
                        error("Expected '{a}' and instead saw '{b}'.",
4135
                            nexttoken, "case", nexttoken.value);
4136
                        return;
4137
                    }
4138
                }
4139
            }
4140
        }
4141
    }).labelled = true;
4142

    
4143
    stmt("debugger", function () {
4144
        if (!option.debug) {
4145
            warning("All 'debugger' statements should be removed.");
4146
        }
4147
        return this;
4148
    }).exps = true;
4149

    
4150
    (function () {
4151
        var x = stmt("do", function () {
4152
            funct["(breakage)"] += 1;
4153
            funct["(loopage)"] += 1;
4154
            increaseComplexityCount();
4155

    
4156
            this.first = block(true);
4157
            advance("while");
4158
            var t = nexttoken;
4159
            nonadjacent(token, t);
4160
            advance("(");
4161
            nospace();
4162
            expression(20);
4163
            if (nexttoken.id === "=") {
4164
                if (!option.boss)
4165
                    warning("Expected a conditional expression and instead saw an assignment.");
4166
                advance("=");
4167
                expression(20);
4168
            }
4169
            advance(")", t);
4170
            nospace(prevtoken, token);
4171
            funct["(breakage)"] -= 1;
4172
            funct["(loopage)"] -= 1;
4173
            return this;
4174
        });
4175
        x.labelled = true;
4176
        x.exps = true;
4177
    }());
4178

    
4179
    blockstmt("for", function () {
4180
        var s, t = nexttoken;
4181
        funct["(breakage)"] += 1;
4182
        funct["(loopage)"] += 1;
4183
        increaseComplexityCount();
4184
        advance("(");
4185
        nonadjacent(this, t);
4186
        nospace();
4187
        if (peek(nexttoken.id === "var" ? 1 : 0).id === "in") {
4188
            if (nexttoken.id === "var") {
4189
                advance("var");
4190
                varstatement.fud.call(varstatement, true);
4191
            } else {
4192
                switch (funct[nexttoken.value]) {
4193
                case "unused":
4194
                    funct[nexttoken.value] = "var";
4195
                    break;
4196
                case "var":
4197
                    break;
4198
                default:
4199
                    warning("Bad for in variable '{a}'.",
4200
                            nexttoken, nexttoken.value);
4201
                }
4202
                advance();
4203
            }
4204
            advance("in");
4205
            expression(20);
4206
            advance(")", t);
4207
            s = block(true, true);
4208
            if (option.forin && s && (s.length > 1 || typeof s[0] !== "object" ||
4209
                    s[0].value !== "if")) {
4210
                warning("The body of a for in should be wrapped in an if statement to filter " +
4211
                        "unwanted properties from the prototype.", this);
4212
            }
4213
            funct["(breakage)"] -= 1;
4214
            funct["(loopage)"] -= 1;
4215
            return this;
4216
        } else {
4217
            if (nexttoken.id !== ";") {
4218
                if (nexttoken.id === "var") {
4219
                    advance("var");
4220
                    varstatement.fud.call(varstatement);
4221
                } else {
4222
                    for (;;) {
4223
                        expression(0, "for");
4224
                        if (nexttoken.id !== ",") {
4225
                            break;
4226
                        }
4227
                        comma();
4228
                    }
4229
                }
4230
            }
4231
            nolinebreak(token);
4232
            advance(";");
4233
            if (nexttoken.id !== ";") {
4234
                expression(20);
4235
                if (nexttoken.id === "=") {
4236
                    if (!option.boss)
4237
                        warning("Expected a conditional expression and instead saw an assignment.");
4238
                    advance("=");
4239
                    expression(20);
4240
                }
4241
            }
4242
            nolinebreak(token);
4243
            advance(";");
4244
            if (nexttoken.id === ";") {
4245
                error("Expected '{a}' and instead saw '{b}'.",
4246
                        nexttoken, ")", ";");
4247
            }
4248
            if (nexttoken.id !== ")") {
4249
                for (;;) {
4250
                    expression(0, "for");
4251
                    if (nexttoken.id !== ",") {
4252
                        break;
4253
                    }
4254
                    comma();
4255
                }
4256
            }
4257
            advance(")", t);
4258
            nospace(prevtoken, token);
4259
            block(true, true);
4260
            funct["(breakage)"] -= 1;
4261
            funct["(loopage)"] -= 1;
4262
            return this;
4263
        }
4264
    }).labelled = true;
4265

    
4266

    
4267
    stmt("break", function () {
4268
        var v = nexttoken.value;
4269

    
4270
        if (funct["(breakage)"] === 0)
4271
            warning("Unexpected '{a}'.", nexttoken, this.value);
4272

    
4273
        if (!option.asi)
4274
            nolinebreak(this);
4275

    
4276
        if (nexttoken.id !== ";") {
4277
            if (token.line === nexttoken.line) {
4278
                if (funct[v] !== "label") {
4279
                    warning("'{a}' is not a statement label.", nexttoken, v);
4280
                } else if (scope[v] !== funct) {
4281
                    warning("'{a}' is out of scope.", nexttoken, v);
4282
                }
4283
                this.first = nexttoken;
4284
                advance();
4285
            }
4286
        }
4287
        reachable("break");
4288
        return this;
4289
    }).exps = true;
4290

    
4291

    
4292
    stmt("continue", function () {
4293
        var v = nexttoken.value;
4294

    
4295
        if (funct["(breakage)"] === 0)
4296
            warning("Unexpected '{a}'.", nexttoken, this.value);
4297

    
4298
        if (!option.asi)
4299
            nolinebreak(this);
4300

    
4301
        if (nexttoken.id !== ";") {
4302
            if (token.line === nexttoken.line) {
4303
                if (funct[v] !== "label") {
4304
                    warning("'{a}' is not a statement label.", nexttoken, v);
4305
                } else if (scope[v] !== funct) {
4306
                    warning("'{a}' is out of scope.", nexttoken, v);
4307
                }
4308
                this.first = nexttoken;
4309
                advance();
4310
            }
4311
        } else if (!funct["(loopage)"]) {
4312
            warning("Unexpected '{a}'.", nexttoken, this.value);
4313
        }
4314
        reachable("continue");
4315
        return this;
4316
    }).exps = true;
4317

    
4318

    
4319
    stmt("return", function () {
4320
        if (this.line === nexttoken.line) {
4321
            if (nexttoken.id === "(regexp)")
4322
                warning("Wrap the /regexp/ literal in parens to disambiguate the slash operator.");
4323

    
4324
            if (nexttoken.id !== ";" && !nexttoken.reach) {
4325
                nonadjacent(token, nexttoken);
4326
                if (peek().value === "=" && !option.boss) {
4327
                    warningAt("Did you mean to return a conditional instead of an assignment?",
4328
                              token.line, token.character + 1);
4329
                }
4330
                this.first = expression(0);
4331
            }
4332
        } else if (!option.asi) {
4333
            nolinebreak(this); // always warn (Line breaking error)
4334
        }
4335
        reachable("return");
4336
        return this;
4337
    }).exps = true;
4338

    
4339

    
4340
    stmt("throw", function () {
4341
        nolinebreak(this);
4342
        nonadjacent(token, nexttoken);
4343
        this.first = expression(20);
4344
        reachable("throw");
4345
        return this;
4346
    }).exps = true;
4347

    
4348
//  Superfluous reserved words
4349

    
4350
    reserve("class");
4351
    reserve("const");
4352
    reserve("enum");
4353
    reserve("export");
4354
    reserve("extends");
4355
    reserve("import");
4356
    reserve("super");
4357

    
4358
    reserve("let");
4359
    reserve("yield");
4360
    reserve("implements");
4361
    reserve("interface");
4362
    reserve("package");
4363
    reserve("private");
4364
    reserve("protected");
4365
    reserve("public");
4366
    reserve("static");
4367

    
4368

    
4369
// Parse JSON
4370

    
4371
    function jsonValue() {
4372

    
4373
        function jsonObject() {
4374
            var o = {}, t = nexttoken;
4375
            advance("{");
4376
            if (nexttoken.id !== "}") {
4377
                for (;;) {
4378
                    if (nexttoken.id === "(end)") {
4379
                        error("Missing '}' to match '{' from line {a}.",
4380
                                nexttoken, t.line);
4381
                    } else if (nexttoken.id === "}") {
4382
                        warning("Unexpected comma.", token);
4383
                        break;
4384
                    } else if (nexttoken.id === ",") {
4385
                        error("Unexpected comma.", nexttoken);
4386
                    } else if (nexttoken.id !== "(string)") {
4387
                        warning("Expected a string and instead saw {a}.",
4388
                                nexttoken, nexttoken.value);
4389
                    }
4390
                    if (o[nexttoken.value] === true) {
4391
                        warning("Duplicate key '{a}'.",
4392
                                nexttoken, nexttoken.value);
4393
                    } else if ((nexttoken.value === "__proto__" &&
4394
                        !option.proto) || (nexttoken.value === "__iterator__" &&
4395
                        !option.iterator)) {
4396
                        warning("The '{a}' key may produce unexpected results.",
4397
                            nexttoken, nexttoken.value);
4398
                    } else {
4399
                        o[nexttoken.value] = true;
4400
                    }
4401
                    advance();
4402
                    advance(":");
4403
                    jsonValue();
4404
                    if (nexttoken.id !== ",") {
4405
                        break;
4406
                    }
4407
                    advance(",");
4408
                }
4409
            }
4410
            advance("}");
4411
        }
4412

    
4413
        function jsonArray() {
4414
            var t = nexttoken;
4415
            advance("[");
4416
            if (nexttoken.id !== "]") {
4417
                for (;;) {
4418
                    if (nexttoken.id === "(end)") {
4419
                        error("Missing ']' to match '[' from line {a}.",
4420
                                nexttoken, t.line);
4421
                    } else if (nexttoken.id === "]") {
4422
                        warning("Unexpected comma.", token);
4423
                        break;
4424
                    } else if (nexttoken.id === ",") {
4425
                        error("Unexpected comma.", nexttoken);
4426
                    }
4427
                    jsonValue();
4428
                    if (nexttoken.id !== ",") {
4429
                        break;
4430
                    }
4431
                    advance(",");
4432
                }
4433
            }
4434
            advance("]");
4435
        }
4436

    
4437
        switch (nexttoken.id) {
4438
        case "{":
4439
            jsonObject();
4440
            break;
4441
        case "[":
4442
            jsonArray();
4443
            break;
4444
        case "true":
4445
        case "false":
4446
        case "null":
4447
        case "(number)":
4448
        case "(string)":
4449
            advance();
4450
            break;
4451
        case "-":
4452
            advance("-");
4453
            if (token.character !== nexttoken.from) {
4454
                warning("Unexpected space after '-'.", token);
4455
            }
4456
            adjacent(token, nexttoken);
4457
            advance("(number)");
4458
            break;
4459
        default:
4460
            error("Expected a JSON value.", nexttoken);
4461
        }
4462
    }
4463

    
4464

    
4465
    // The actual JSHINT function itself.
4466
    var itself = function (s, o, g) {
4467
        var a, i, k, x;
4468
        var optionKeys;
4469
        var newOptionObj = {};
4470

    
4471
        if (o && o.scope) {
4472
            JSHINT.scope = o.scope;
4473
        } else {
4474
            JSHINT.errors = [];
4475
            JSHINT.undefs = [];
4476
            JSHINT.internals = [];
4477
            JSHINT.blacklist = {};
4478
            JSHINT.scope = "(main)";
4479
        }
4480

    
4481
        predefined = Object.create(standard);
4482
        declared = Object.create(null);
4483
        combine(predefined, g || {});
4484

    
4485
        if (o) {
4486
            a = o.predef;
4487
            if (a) {
4488
                if (!Array.isArray(a) && typeof a === "object") {
4489
                    a = Object.keys(a);
4490
                }
4491
                a.forEach(function (item) {
4492
                    var slice;
4493
                    if (item[0] === "-") {
4494
                        slice = item.slice(1);
4495
                        JSHINT.blacklist[slice] = slice;
4496
                    } else {
4497
                        predefined[item] = true;
4498
                    }
4499
                });
4500
            }
4501

    
4502
            optionKeys = Object.keys(o);
4503
            for (x = 0; x < optionKeys.length; x++) {
4504
                newOptionObj[optionKeys[x]] = o[optionKeys[x]];
4505

    
4506
                if (optionKeys[x] === "newcap" && o[optionKeys[x]] === false)
4507
                    newOptionObj["(explicitNewcap)"] = true;
4508

    
4509
                if (optionKeys[x] === "indent")
4510
                    newOptionObj.white = true;
4511
            }
4512
        }
4513

    
4514
        option = newOptionObj;
4515

    
4516
        option.indent = option.indent || 4;
4517
        option.maxerr = option.maxerr || 50;
4518

    
4519
        tab = "";
4520
        for (i = 0; i < option.indent; i += 1) {
4521
            tab += " ";
4522
        }
4523
        indent = 1;
4524
        global = Object.create(predefined);
4525
        scope = global;
4526
        funct = {
4527
            "(global)":   true,
4528
            "(name)":     "(global)",
4529
            "(scope)":    scope,
4530
            "(breakage)": 0,
4531
            "(loopage)":  0,
4532
            "(tokens)":   {},
4533
            "(metrics)":   createMetrics(nexttoken)
4534
        };
4535
        functions = [funct];
4536
        urls = [];
4537
        stack = null;
4538
        member = {};
4539
        membersOnly = null;
4540
        implied = {};
4541
        inblock = false;
4542
        lookahead = [];
4543
        jsonmode = false;
4544
        warnings = 0;
4545
        lines = [];
4546
        unuseds = [];
4547

    
4548
        if (!isString(s) && !Array.isArray(s)) {
4549
            errorAt("Input is neither a string nor an array of strings.", 0);
4550
            return false;
4551
        }
4552

    
4553
        if (isString(s) && /^\s*$/g.test(s)) {
4554
            errorAt("Input is an empty string.", 0);
4555
            return false;
4556
        }
4557

    
4558
        if (s.length === 0) {
4559
            errorAt("Input is an empty array.", 0);
4560
            return false;
4561
        }
4562

    
4563
        lex.init(s);
4564

    
4565
        prereg = true;
4566
        directive = {};
4567

    
4568
        prevtoken = token = nexttoken = syntax["(begin)"];
4569

    
4570
        // Check options
4571
        for (var name in o) {
4572
            if (is_own(o, name)) {
4573
                checkOption(name, token);
4574
            }
4575
        }
4576

    
4577
        assume();
4578

    
4579
        // combine the passed globals after we've assumed all our options
4580
        combine(predefined, g || {});
4581

    
4582
        //reset values
4583
        comma.first = true;
4584
        quotmark = undefined;
4585

    
4586
        try {
4587
            advance();
4588
            switch (nexttoken.id) {
4589
            case "{":
4590
            case "[":
4591
                option.laxbreak = true;
4592
                jsonmode = true;
4593
                jsonValue();
4594
                break;
4595
            default:
4596
                directives();
4597
                if (directive["use strict"] && !option.globalstrict) {
4598
                    warning("Use the function form of \"use strict\".", prevtoken);
4599
                }
4600

    
4601
                statements();
4602
            }
4603
            advance((nexttoken && nexttoken.value !== ".")  ? "(end)" : undefined);
4604

    
4605
            var markDefined = function (name, context) {
4606
                do {
4607
                    if (typeof context[name] === "string") {
4608
                        // JSHINT marks unused variables as 'unused' and
4609
                        // unused function declaration as 'unction'. This
4610
                        // code changes such instances back 'var' and
4611
                        // 'closure' so that the code in JSHINT.data()
4612
                        // doesn't think they're unused.
4613

    
4614
                        if (context[name] === "unused")
4615
                            context[name] = "var";
4616
                        else if (context[name] === "unction")
4617
                            context[name] = "closure";
4618

    
4619
                        return true;
4620
                    }
4621

    
4622
                    context = context["(context)"];
4623
                } while (context);
4624

    
4625
                return false;
4626
            };
4627

    
4628
            var clearImplied = function (name, line) {
4629
                if (!implied[name])
4630
                    return;
4631

    
4632
                var newImplied = [];
4633
                for (var i = 0; i < implied[name].length; i += 1) {
4634
                    if (implied[name][i] !== line)
4635
                        newImplied.push(implied[name][i]);
4636
                }
4637

    
4638
                if (newImplied.length === 0)
4639
                    delete implied[name];
4640
                else
4641
                    implied[name] = newImplied;
4642
            };
4643

    
4644
            var warnUnused = function (name, token) {
4645
                var line = token.line;
4646
                var chr  = token.character;
4647

    
4648
                if (option.unused)
4649
                    warningAt("'{a}' is defined but never used.", line, chr, name);
4650

    
4651
                unuseds.push({
4652
                    name: name,
4653
                    line: line,
4654
                    character: chr
4655
                });
4656
            };
4657

    
4658
            var checkUnused = function (func, key) {
4659
                var type = func[key];
4660
                var token = func["(tokens)"][key];
4661

    
4662
                if (key.charAt(0) === "(")
4663
                    return;
4664

    
4665
                if (type !== "unused" && type !== "unction")
4666
                    return;
4667

    
4668
                // Params are checked separately from other variables.
4669
                if (func["(params)"] && func["(params)"].indexOf(key) !== -1)
4670
                    return;
4671

    
4672
                warnUnused(key, token);
4673
            };
4674

    
4675
            // Check queued 'x is not defined' instances to see if they're still undefined.
4676
            for (i = 0; i < JSHINT.undefs.length; i += 1) {
4677
                k = JSHINT.undefs[i].slice(0);
4678

    
4679
                if (markDefined(k[2].value, k[0])) {
4680
                    clearImplied(k[2].value, k[2].line);
4681
                } else {
4682
                    warning.apply(warning, k.slice(1));
4683
                }
4684
            }
4685

    
4686
            functions.forEach(function (func) {
4687
                for (var key in func) {
4688
                    if (is_own(func, key)) {
4689
                        checkUnused(func, key);
4690
                    }
4691
                }
4692

    
4693
                if (!func["(params)"])
4694
                    return;
4695

    
4696
                var params = func["(params)"].slice();
4697
                var param  = params.pop();
4698
                var type;
4699

    
4700
                while (param) {
4701
                    type = func[param];
4702

    
4703
                    // 'undefined' is a special case for (function (window, undefined) { ... })();
4704
                    // patterns.
4705

    
4706
                    if (param === "undefined")
4707
                        return;
4708

    
4709
                    if (type !== "unused" && type !== "unction")
4710
                        return;
4711

    
4712
                    warnUnused(param, func["(tokens)"][param]);
4713
                    param = params.pop();
4714
                }
4715
            });
4716

    
4717
            for (var key in declared) {
4718
                if (is_own(declared, key) && !is_own(global, key)) {
4719
                    warnUnused(key, declared[key]);
4720
                }
4721
            }
4722
        } catch (e) {
4723
            if (e) {
4724
                var nt = nexttoken || {};
4725
                JSHINT.errors.push({
4726
                    raw       : e.raw,
4727
                    reason    : e.message,
4728
                    line      : e.line || nt.line,
4729
                    character : e.character || nt.from
4730
                }, null);
4731
            }
4732
        }
4733

    
4734
        // Loop over the listed "internals", and check them as well.
4735

    
4736
        if (JSHINT.scope === "(main)") {
4737
            o = o || {};
4738

    
4739
            for (i = 0; i < JSHINT.internals.length; i += 1) {
4740
                k = JSHINT.internals[i];
4741
                o.scope = k.elem;
4742
                itself(k.value, o, g);
4743
            }
4744
        }
4745

    
4746
        return JSHINT.errors.length === 0;
4747
    };
4748

    
4749
    // Data summary.
4750
    itself.data = function () {
4751
        var data = {
4752
            functions: [],
4753
            options: option
4754
        };
4755
        var implieds = [];
4756
        var members = [];
4757
        var fu, f, i, j, n, globals;
4758

    
4759
        if (itself.errors.length) {
4760
            data.errors = itself.errors;
4761
        }
4762

    
4763
        if (jsonmode) {
4764
            data.json = true;
4765
        }
4766

    
4767
        for (n in implied) {
4768
            if (is_own(implied, n)) {
4769
                implieds.push({
4770
                    name: n,
4771
                    line: implied[n]
4772
                });
4773
            }
4774
        }
4775

    
4776
        if (implieds.length > 0) {
4777
            data.implieds = implieds;
4778
        }
4779

    
4780
        if (urls.length > 0) {
4781
            data.urls = urls;
4782
        }
4783

    
4784
        globals = Object.keys(scope);
4785
        if (globals.length > 0) {
4786
            data.globals = globals;
4787
        }
4788

    
4789
        for (i = 1; i < functions.length; i += 1) {
4790
            f = functions[i];
4791
            fu = {};
4792

    
4793
            for (j = 0; j < functionicity.length; j += 1) {
4794
                fu[functionicity[j]] = [];
4795
            }
4796

    
4797
            for (j = 0; j < functionicity.length; j += 1) {
4798
                if (fu[functionicity[j]].length === 0) {
4799
                    delete fu[functionicity[j]];
4800
                }
4801
            }
4802

    
4803
            fu.name = f["(name)"];
4804
            fu.param = f["(params)"];
4805
            fu.line = f["(line)"];
4806
            fu.character = f["(character)"];
4807
            fu.last = f["(last)"];
4808
            fu.lastcharacter = f["(lastcharacter)"];
4809
            data.functions.push(fu);
4810
        }
4811

    
4812
        if (unuseds.length > 0) {
4813
            data.unused = unuseds;
4814
        }
4815

    
4816
        members = [];
4817
        for (n in member) {
4818
            if (typeof member[n] === "number") {
4819
                data.member = member;
4820
                break;
4821
            }
4822
        }
4823

    
4824
        return data;
4825
    };
4826

    
4827
    itself.jshint = itself;
4828

    
4829
    return itself;
4830
}());
4831

    
4832
// Make JSHINT a Node module, if possible.
4833
if (typeof exports === "object" && exports) {
4834
    exports.JSHINT = JSHINT;
4835
}