Switch to unified view

a b/AlluraTesting/jslint/fulljslint.js
1
// jslint.js
2
// 2010-08-05
3
4
/*
5
Copyright (c) 2002 Douglas Crockford  (www.JSLint.com)
6
7
Permission is hereby granted, free of charge, to any person obtaining a copy of
8
this software and associated documentation files (the "Software"), to deal in
9
the Software without restriction, including without limitation the rights to
10
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
11
of the Software, and to permit persons to whom the Software is furnished to do
12
so, subject to the following conditions:
13
14
The above copyright notice and this permission notice shall be included in all
15
copies or substantial portions of the Software.
16
17
The Software shall be used for Good, not Evil.
18
19
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
SOFTWARE.
26
*/
27
28
/*
29
    JSLINT is a global function. It takes two parameters.
30
31
        var myResult = JSLINT(source, option);
32
33
    The first parameter is either a string or an array of strings. If it is a
34
    string, it will be split on '\n' or '\r'. If it is an array of strings, it
35
    is assumed that each string represents one line. The source can be a
36
    JavaScript text, or HTML text, or a Konfabulator text.
37
38
    The second parameter is an optional object of options which control the
39
    operation of JSLINT. Most of the options are booleans: They are all are
40
    optional and have a default value of false.
41
42
    If it checks out, JSLINT returns true. Otherwise, it returns false.
43
44
    If false, you can inspect JSLINT.errors to find out the problems.
45
    JSLINT.errors is an array of objects containing these members:
46
47
    {
48
        line      : The line (relative to 0) at which the lint was found
49
        character : The character (relative to 0) at which the lint was found
50
        reason    : The problem
51
        evidence  : The text line in which the problem occurred
52
        raw       : The raw message before the details were inserted
53
        a         : The first detail
54
        b         : The second detail
55
        c         : The third detail
56
        d         : The fourth detail
57
    }
58
59
    If a fatal error was found, a null will be the last element of the
60
    JSLINT.errors array.
61
62
    You can request a Function Report, which shows all of the functions
63
    and the parameters and vars that they use. This can be used to find
64
    implied global variables and other problems. The report is in HTML and
65
    can be inserted in an HTML <body>.
66
67
        var myReport = JSLINT.report(limited);
68
69
    If limited is true, then the report will be limited to only errors.
70
71
    You can request a data structure which contains JSLint's results.
72
73
        var myData = JSLINT.data();
74
75
    It returns a structure with this form:
76
77
    {
78
        errors: [
79
            {
80
                line: NUMBER,
81
                character: NUMBER,
82
                reason: STRING,
83
                evidence: STRING
84
            }
85
        ],
86
        functions: [
87
            name: STRING,
88
            line: NUMBER,
89
            last: NUMBER,
90
            param: [
91
                STRING
92
            ],
93
            closure: [
94
                STRING
95
            ],
96
            var: [
97
                STRING
98
            ],
99
            exception: [
100
                STRING
101
            ],
102
            outer: [
103
                STRING
104
            ],
105
            unused: [
106
                STRING
107
            ],
108
            global: [
109
                STRING
110
            ],
111
            label: [
112
                STRING
113
            ]
114
        ],
115
        globals: [
116
            STRING
117
        ],
118
        member: {
119
            STRING: NUMBER
120
        },
121
        unuseds: [
122
            {
123
                name: STRING,
124
                line: NUMBER
125
            }
126
        ],
127
        implieds: [
128
            {
129
                name: STRING,
130
                line: NUMBER
131
            }
132
        ],
133
        urls: [
134
            STRING
135
        ],
136
        json: BOOLEAN
137
    }
138
139
    Empty arrays will not be included.
140
141
*/
142
143
/*jslint
144
    evil: true, nomen: false, onevar: false, regexp: false, strict: true
145
*/
146
147
/*members "\b", "\t", "\n", "\f", "\r", "!=", "!==", "\"", "%",
148
    "(begin)", "(breakage)", "(context)", "(error)", "(global)",
149
    "(identifier)", "(last)", "(line)", "(loopage)", "(name)", "(onevar)",
150
    "(params)", "(scope)", "(verb)", "*", "+", "++", "-", "--", "\/",
151
    "<", "<=", "==", "===", ">", ">=", ADSAFE, ActiveXObject,
152
    Array, Boolean, COM, CScript, Canvas, CustomAnimation, Date, Debug, E,
153
    Enumerator, Error, EvalError, FadeAnimation, Flash, FormField, Frame,
154
    Function, HotKey, Image, JSON, LN10, LN2, LOG10E, LOG2E, MAX_VALUE,
155
    MIN_VALUE, Math, MenuItem, MoveAnimation, NEGATIVE_INFINITY, Number,
156
    Object, Option, PI, POSITIVE_INFINITY, Point, RangeError, Rectangle,
157
    ReferenceError, RegExp, ResizeAnimation, RotateAnimation, SQRT1_2,
158
    SQRT2, ScrollBar, String, Style, SyntaxError, System, Text, TextArea,
159
    Timer, TypeError, URIError, URL, VBArray, WScript, Web, Window, XMLDOM,
160
    XMLHttpRequest, "\\", a, abbr, acronym, addEventListener, address,
161
    adsafe, alert, aliceblue, animator, antiquewhite, appleScript, applet,
162
    apply, approved, aqua, aquamarine, area, arguments, arity, article,
163
    aside, audio, autocomplete, azure, b, background,
164
    "background-attachment", "background-color", "background-image",
165
    "background-position", "background-repeat", base, bdo, beep, beige, big,
166
    bisque, bitwise, black, blanchedalmond, block, blockquote, blue,
167
    blueviolet, blur, body, border, "border-bottom", "border-bottom-color",
168
    "border-bottom-style", "border-bottom-width", "border-collapse",
169
    "border-color", "border-left", "border-left-color", "border-left-style",
170
    "border-left-width", "border-right", "border-right-color",
171
    "border-right-style", "border-right-width", "border-spacing",
172
    "border-style", "border-top", "border-top-color", "border-top-style",
173
    "border-top-width", "border-width", bottom, br, brown, browser,
174
    burlywood, button, bytesToUIString, c, cadetblue, call, callee, caller,
175
    canvas, cap, caption, "caption-side", cases, center, charAt, charCodeAt,
176
    character, chartreuse, chocolate, chooseColor, chooseFile, chooseFolder,
177
    cite, clear, clearInterval, clearTimeout, clip, close, closeWidget,
178
    closed, closure, cm, code, col, colgroup, color, command, comment,
179
    condition, confirm, console, constructor, content, convertPathToHFS,
180
    convertPathToPlatform, coral, cornflowerblue, cornsilk,
181
    "counter-increment", "counter-reset", create, crimson, css, cursor,
182
    cyan, d, darkblue, darkcyan, darkgoldenrod, darkgray, darkgreen,
183
    darkkhaki, darkmagenta, darkolivegreen, darkorange, darkorchid, darkred,
184
    darksalmon, darkseagreen, darkslateblue, darkslategray, darkturquoise,
185
    darkviolet, data, datalist, dd, debug, decodeURI, decodeURIComponent,
186
    deeppink, deepskyblue, defaultStatus, defineClass, del, deserialize,
187
    details, devel, dfn, dialog, dimension, dimgray, dir, direction,
188
    display, div, dl, document, dodgerblue, dt, edition, else, em, embed,
189
    empty, "empty-cells", encodeURI, encodeURIComponent, entityify, eqeqeq,
190
    errors, es5, escape, eval, event, evidence, evil, ex, exception, exec, exps,
191
    fieldset, figure, filesystem, firebrick, first, float, floor,
192
    floralwhite, focus, focusWidget, font, "font-face", "font-family",
193
    "font-size", "font-size-adjust", "font-stretch", "font-style",
194
    "font-variant", "font-weight", footer, forestgreen, forin, form,
195
    fragment, frame, frames, frameset, from, fromCharCode, fuchsia, fud,
196
    funct, function, functions, g, gainsboro, gc, getComputedStyle,
197
    ghostwhite, global, globals, gold, goldenrod, gray, green, greenyellow,
198
    h1, h2, h3, h4, h5, h6, hasOwnProperty, head, header, height, help,
199
    hgroup, history, honeydew, hotpink, hr, 'hta:application', html,
200
    i, iTunes, id, identifier,
201
    iframe, img, immed, implieds, in, include, indent, indexOf, indianred,
202
    indigo, init, input, ins, isAlpha, isApplicationRunning, isDigit,
203
    isFinite, isNaN, ivory, join, jslint, json, kbd, keygen, khaki,
204
    konfabulatorVersion, label, labelled, lang, last, lavender,
205
    lavenderblush, lawngreen, laxbreak, lbp, led, left, legend,
206
    lemonchiffon, length, "letter-spacing", li, lib, lightblue, lightcoral,
207
    lightcyan, lightgoldenrodyellow, lightgreen, lightpink, lightsalmon,
208
    lightseagreen, lightskyblue, lightslategray, lightsteelblue,
209
    lightyellow, lime, limegreen, line, "line-height", linen, link,
210
    "list-style", "list-style-image", "list-style-position",
211
    "list-style-type", load, loadClass, location, log, m, magenta, map,
212
    margin, "margin-bottom", "margin-left", "margin-right", "margin-top",
213
    mark, "marker-offset", maroon, match, "max-height", "max-width", maxerr,
214
    maxlen, md5, media, mediumaquamarine, mediumblue, mediumorchid,
215
    mediumpurple, mediumseagreen, mediumslateblue, mediumspringgreen,
216
    mediumturquoise, mediumvioletred, member, menu, message, meta, meter,
217
    midnightblue, "min-height", "min-width", mintcream, mistyrose, mm,
218
    moccasin, moveBy, moveTo, name, nav, navajowhite, navigator, navy, new,
219
    newcap, noframes, nomen, noscript, nud, object, ol, oldlace, olive,
220
    olivedrab, on, onbeforeunload, onblur, onerror, onevar, onfocus, onload,
221
    onresize, onunload, opacity, open, openURL, opener, opera, optgroup,
222
    option, orange, orangered, orchid, outer, outline, "outline-color",
223
    "outline-style", "outline-width", output, overflow, "overflow-x",
224
    "overflow-y", p, padding, "padding-bottom", "padding-left",
225
    "padding-right", "padding-top", page, "page-break-after",
226
    "page-break-before", palegoldenrod, palegreen, paleturquoise,
227
    palevioletred, papayawhip, param, parent, parseFloat, parseInt,
228
    passfail, pc, peachpuff, peru, pink, play, plum, plusplus, pop,
229
    popupMenu, position, powderblue, pre, predef, preferenceGroups,
230
    preferences, print, progress, prompt, prototype, pt, purple, push, px,
231
    q, quit, quotes, random, range, raw, reach, readFile, readUrl, reason,
232
    red, regexp, reloadWidget, removeEventListener, replace, report,
233
    reserved, resizeBy, resizeTo, resolvePath, resumeUpdates, rhino, right,
234
    rosybrown, royalblue, rp, rt, ruby, runCommand, runCommandInBg,
235
    saddlebrown, safe, salmon, samp, sandybrown, saveAs, savePreferences,
236
    screen, script, scroll, scrollBy, scrollTo, seagreen, seal, search,
237
    seashell, section, select, serialize, setInterval, setTimeout, shift,
238
    showWidgetPreferences, sienna, silver, skyblue, slateblue, slategray,
239
    sleep, slice, small, snow, sort, source, span, spawn, speak, split,
240
    springgreen, src, stack, status, steelblue, strict, strong, style,
241
    styleproperty, sub, substr, sup, supplant, suppressUpdates, sync,
242
    system, table, "table-layout", tan, tbody, td, teal, tellWidget, test,
243
    "text-align", "text-decoration", "text-indent", "text-shadow",
244
    "text-transform", textarea, tfoot, th, thead, thistle, time, title,
245
    toLowerCase, toString, toUpperCase, toint32, token, tomato, top, tr, tt,
246
    turquoise, type, u, ul, undef, unescape, "unicode-bidi", unused,
247
    unwatch, updateNow, urls, value, valueOf, var, version,
248
    "vertical-align", video, violet, visibility, watch, wheat, white,
249
    "white-space", whitesmoke, widget, width, windows, "word-spacing",
250
    "word-wrap", yahooCheckLogin, yahooLogin, yahooLogout, yellow,
251
    yellowgreen, "z-index"
252
*/
253
254
// We build the application inside a function so that we produce only a single
255
// global variable. The function will be invoked, its return value is the JSLINT
256
// application itself.
257
258
"use strict";
259
260
var JSLINT = (function () {
261
    var adsafe_id,      // The widget's ADsafe id.
262
        adsafe_may,     // The widget may load approved scripts.
263
        adsafe_went,    // ADSAFE.go has been called.
264
        anonname,       // The guessed name for anonymous functions.
265
        approved,       // ADsafe approved urls.
266
267
        atrule = {
268
            media      : true,
269
            'font-face': true,
270
            page       : true
271
        },
272
273
// These are operators that should not be used with the ! operator.
274
275
        bang = {
276
            '<': true,
277
            '<=': true,
278
            '==': true,
279
            '===': true,
280
            '!==': true,
281
            '!=': true,
282
            '>': true,
283
            '>=': true,
284
            '+': true,
285
            '-': true,
286
            '*': true,
287
            '/': true,
288
            '%': true
289
        },
290
291
// These are members that should not be permitted in the safe subset.
292
293
        banned = {              // the member names that ADsafe prohibits.
294
            'arguments'     : true,
295
            callee          : true,
296
            caller          : true,
297
            constructor     : true,
298
            'eval'          : true,
299
            prototype       : true,
300
            stack           : true,
301
            unwatch         : true,
302
            valueOf         : true,
303
            watch           : true
304
        },
305
306
307
// These are the JSLint boolean options.
308
309
        boolOptions = {
310
            adsafe     : true, // if ADsafe should be enforced
311
            bitwise    : true, // if bitwise operators should not be allowed
312
            browser    : true, // if the standard browser globals should be predefined
313
            cap        : true, // if upper case HTML should be allowed
314
            css        : true, // if CSS workarounds should be tolerated
315
            debug      : true, // if debugger statements should be allowed
316
            devel      : true, // if logging should be allowed (console, alert, etc.)
317
            eqeqeq     : true, // if === should be required
318
            es5        : true, // if ES5 syntax should be allowed
319
            evil       : true, // if eval should be allowed
320
            forin      : true, // if for in statements must filter
321
            fragment   : true, // if HTML fragments should be allowed
322
            immed      : true, // if immediate invocations must be wrapped in parens
323
            laxbreak   : true, // if line breaks should not be checked
324
            newcap     : true, // if constructor names must be capitalized
325
            nomen      : true, // if names should be checked
326
            on         : true, // if HTML event handlers should be allowed
327
            onevar     : true, // if only one var statement per function should be allowed
328
            passfail   : true, // if the scan should stop on first error
329
            plusplus   : true, // if increment/decrement should not be allowed
330
            regexp     : true, // if the . should not be allowed in regexp literals
331
            rhino      : true, // if the Rhino environment globals should be predefined
332
            undef      : true, // if variables should be declared before used
333
            safe       : true, // if use of some browser features should be restricted
334
            windows    : true, // if MS Windows-specigic globals should be predefined
335
            strict     : true, // require the "use strict"; pragma
336
            sub        : true, // if all forms of subscript notation are tolerated
337
            white      : true, // if strict whitespace rules apply
338
            widget     : true  // if the Yahoo Widgets globals should be predefined
339
        },
340
341
// browser contains a set of global names which are commonly provided by a
342
// web browser environment.
343
344
        browser = {
345
            addEventListener: false,
346
            blur            : false,
347
            clearInterval   : false,
348
            clearTimeout    : false,
349
            close           : false,
350
            closed          : false,
351
            defaultStatus   : false,
352
            document        : false,
353
            event           : false,
354
            focus           : false,
355
            frames          : false,
356
            getComputedStyle: false,
357
            history         : false,
358
            Image           : false,
359
            length          : false,
360
            location        : false,
361
            moveBy          : false,
362
            moveTo          : false,
363
            name            : false,
364
            navigator       : false,
365
            onbeforeunload  : true,
366
            onblur          : true,
367
            onerror         : true,
368
            onfocus         : true,
369
            onload          : true,
370
            onresize        : true,
371
            onunload        : true,
372
            open            : false,
373
            opener          : false,
374
            Option          : false,
375
            parent          : false,
376
            print           : false,
377
            removeEventListener: false,
378
            resizeBy        : false,
379
            resizeTo        : false,
380
            screen          : false,
381
            scroll          : false,
382
            scrollBy        : false,
383
            scrollTo        : false,
384
            setInterval     : false,
385
            setTimeout      : false,
386
            status          : false,
387
            top             : false,
388
            XMLHttpRequest  : false
389
        },
390
391
        cssAttributeData,
392
        cssAny,
393
394
        cssColorData = {
395
            "aliceblue"             : true,
396
            "antiquewhite"          : true,
397
            "aqua"                  : true,
398
            "aquamarine"            : true,
399
            "azure"                 : true,
400
            "beige"                 : true,
401
            "bisque"                : true,
402
            "black"                 : true,
403
            "blanchedalmond"        : true,
404
            "blue"                  : true,
405
            "blueviolet"            : true,
406
            "brown"                 : true,
407
            "burlywood"             : true,
408
            "cadetblue"             : true,
409
            "chartreuse"            : true,
410
            "chocolate"             : true,
411
            "coral"                 : true,
412
            "cornflowerblue"        : true,
413
            "cornsilk"              : true,
414
            "crimson"               : true,
415
            "cyan"                  : true,
416
            "darkblue"              : true,
417
            "darkcyan"              : true,
418
            "darkgoldenrod"         : true,
419
            "darkgray"              : true,
420
            "darkgreen"             : true,
421
            "darkkhaki"             : true,
422
            "darkmagenta"           : true,
423
            "darkolivegreen"        : true,
424
            "darkorange"            : true,
425
            "darkorchid"            : true,
426
            "darkred"               : true,
427
            "darksalmon"            : true,
428
            "darkseagreen"          : true,
429
            "darkslateblue"         : true,
430
            "darkslategray"         : true,
431
            "darkturquoise"         : true,
432
            "darkviolet"            : true,
433
            "deeppink"              : true,
434
            "deepskyblue"           : true,
435
            "dimgray"               : true,
436
            "dodgerblue"            : true,
437
            "firebrick"             : true,
438
            "floralwhite"           : true,
439
            "forestgreen"           : true,
440
            "fuchsia"               : true,
441
            "gainsboro"             : true,
442
            "ghostwhite"            : true,
443
            "gold"                  : true,
444
            "goldenrod"             : true,
445
            "gray"                  : true,
446
            "green"                 : true,
447
            "greenyellow"           : true,
448
            "honeydew"              : true,
449
            "hotpink"               : true,
450
            "indianred"             : true,
451
            "indigo"                : true,
452
            "ivory"                 : true,
453
            "khaki"                 : true,
454
            "lavender"              : true,
455
            "lavenderblush"         : true,
456
            "lawngreen"             : true,
457
            "lemonchiffon"          : true,
458
            "lightblue"             : true,
459
            "lightcoral"            : true,
460
            "lightcyan"             : true,
461
            "lightgoldenrodyellow"  : true,
462
            "lightgreen"            : true,
463
            "lightpink"             : true,
464
            "lightsalmon"           : true,
465
            "lightseagreen"         : true,
466
            "lightskyblue"          : true,
467
            "lightslategray"        : true,
468
            "lightsteelblue"        : true,
469
            "lightyellow"           : true,
470
            "lime"                  : true,
471
            "limegreen"             : true,
472
            "linen"                 : true,
473
            "magenta"               : true,
474
            "maroon"                : true,
475
            "mediumaquamarine"      : true,
476
            "mediumblue"            : true,
477
            "mediumorchid"          : true,
478
            "mediumpurple"          : true,
479
            "mediumseagreen"        : true,
480
            "mediumslateblue"       : true,
481
            "mediumspringgreen"     : true,
482
            "mediumturquoise"       : true,
483
            "mediumvioletred"       : true,
484
            "midnightblue"          : true,
485
            "mintcream"             : true,
486
            "mistyrose"             : true,
487
            "moccasin"              : true,
488
            "navajowhite"           : true,
489
            "navy"                  : true,
490
            "oldlace"               : true,
491
            "olive"                 : true,
492
            "olivedrab"             : true,
493
            "orange"                : true,
494
            "orangered"             : true,
495
            "orchid"                : true,
496
            "palegoldenrod"         : true,
497
            "palegreen"             : true,
498
            "paleturquoise"         : true,
499
            "palevioletred"         : true,
500
            "papayawhip"            : true,
501
            "peachpuff"             : true,
502
            "peru"                  : true,
503
            "pink"                  : true,
504
            "plum"                  : true,
505
            "powderblue"            : true,
506
            "purple"                : true,
507
            "red"                   : true,
508
            "rosybrown"             : true,
509
            "royalblue"             : true,
510
            "saddlebrown"           : true,
511
            "salmon"                : true,
512
            "sandybrown"            : true,
513
            "seagreen"              : true,
514
            "seashell"              : true,
515
            "sienna"                : true,
516
            "silver"                : true,
517
            "skyblue"               : true,
518
            "slateblue"             : true,
519
            "slategray"             : true,
520
            "snow"                  : true,
521
            "springgreen"           : true,
522
            "steelblue"             : true,
523
            "tan"                   : true,
524
            "teal"                  : true,
525
            "thistle"               : true,
526
            "tomato"                : true,
527
            "turquoise"             : true,
528
            "violet"                : true,
529
            "wheat"                 : true,
530
            "white"                 : true,
531
            "whitesmoke"            : true,
532
            "yellow"                : true,
533
            "yellowgreen"           : true
534
        },
535
536
        cssBorderStyle,
537
        cssBreak,
538
539
        cssLengthData = {
540
            '%': true,
541
            'cm': true,
542
            'em': true,
543
            'ex': true,
544
            'in': true,
545
            'mm': true,
546
            'pc': true,
547
            'pt': true,
548
            'px': true
549
        },
550
551
        cssOverflow,
552
553
        devel = {
554
            alert           : false,
555
            confirm         : false,
556
            console         : false,
557
            Debug           : false,
558
            opera           : false,
559
            prompt          : false
560
        },
561
562
        escapes = {
563
            '\b': '\\b',
564
            '\t': '\\t',
565
            '\n': '\\n',
566
            '\f': '\\f',
567
            '\r': '\\r',
568
            '"' : '\\"',
569
            '/' : '\\/',
570
            '\\': '\\\\'
571
        },
572
573
        funct,          // The current function
574
575
        functionicity = [
576
            'closure', 'exception', 'global', 'label',
577
            'outer', 'unused', 'var'
578
        ],
579
580
        functions,      // All of the functions
581
582
        global,         // The global scope
583
        htmltag = {
584
            a:        {},
585
            abbr:     {},
586
            acronym:  {},
587
            address:  {},
588
            applet:   {},
589
            area:     {empty: true, parent: ' map '},
590
            article:  {},
591
            aside:    {},
592
            audio:    {},
593
            b:        {},
594
            base:     {empty: true, parent: ' head '},
595
            bdo:      {},
596
            big:      {},
597
            blockquote: {},
598
            body:     {parent: ' html noframes '},
599
            br:       {empty: true},
600
            button:   {},
601
            canvas:   {parent: ' body p div th td '},
602
            caption:  {parent: ' table '},
603
            center:   {},
604
            cite:     {},
605
            code:     {},
606
            col:      {empty: true, parent: ' table colgroup '},
607
            colgroup: {parent: ' table '},
608
            command:  {parent: ' menu '},
609
            datalist: {},
610
            dd:       {parent: ' dl '},
611
            del:      {},
612
            details:  {},
613
            dialog:   {},
614
            dfn:      {},
615
            dir:      {},
616
            div:      {},
617
            dl:       {},
618
            dt:       {parent: ' dl '},
619
            em:       {},
620
            embed:    {},
621
            fieldset: {},
622
            figure:   {},
623
            font:     {},
624
            footer:   {},
625
            form:     {},
626
            frame:    {empty: true, parent: ' frameset '},
627
            frameset: {parent: ' html frameset '},
628
            h1:       {},
629
            h2:       {},
630
            h3:       {},
631
            h4:       {},
632
            h5:       {},
633
            h6:       {},
634
            head:     {parent: ' html '},
635
            header:   {},
636
            hgroup:   {},
637
            hr:       {empty: true},
638
            'hta:application':
639
                      {empty: true, parent: ' head '},
640
            html:     {parent: '*'},
641
            i:        {},
642
            iframe:   {},
643
            img:      {empty: true},
644
            input:    {empty: true},
645
            ins:      {},
646
            kbd:      {},
647
            keygen:   {},
648
            label:    {},
649
            legend:   {parent: ' details fieldset figure '},
650
            li:       {parent: ' dir menu ol ul '},
651
            link:     {empty: true, parent: ' head '},
652
            map:      {},
653
            mark:     {},
654
            menu:     {},
655
            meta:     {empty: true, parent: ' head noframes noscript '},
656
            meter:    {},
657
            nav:      {},
658
            noframes: {parent: ' html body '},
659
            noscript: {},
660
            object:   {},
661
            ol:       {},
662
            optgroup: {parent: ' select '},
663
            option:   {parent: ' optgroup select '},
664
            output:   {},
665
            p:        {},
666
            param:    {parent: ' applet object '},
667
            pre:      {},
668
            progress: {},
669
            q:        {},
670
            rp:       {},
671
            rt:       {},
672
            ruby:     {},
673
            samp:     {},
674
            script:   {empty: true, parent: ' body div frame head iframe p pre span '},
675
            section:  {},
676
            select:   {},
677
            small:    {},
678
            span:     {},
679
            source:   {},
680
            strong:   {},
681
            style:    {parent: ' head ', empty: true},
682
            sub:      {},
683
            sup:      {},
684
            table:    {},
685
            tbody:    {parent: ' table '},
686
            td:       {parent: ' tr '},
687
            textarea: {},
688
            tfoot:    {parent: ' table '},
689
            th:       {parent: ' tr '},
690
            thead:    {parent: ' table '},
691
            time:     {},
692
            title:    {parent: ' head '},
693
            tr:       {parent: ' table tbody thead tfoot '},
694
            tt:       {},
695
            u:        {},
696
            ul:       {},
697
            'var':    {},
698
            video:    {}
699
        },
700
701
        ids,            // HTML ids
702
        implied,        // Implied globals
703
        inblock,
704
        indent,
705
        jsonmode,
706
        lines,
707
        lookahead,
708
        member,
709
        membersOnly,
710
        nexttoken,
711
        noreach,
712
        option,
713
        predefined,     // Global variables defined by option
714
        prereg,
715
        prevtoken,
716
717
        rhino = {
718
            defineClass : false,
719
            deserialize : false,
720
            gc          : false,
721
            help        : false,
722
            load        : false,
723
            loadClass   : false,
724
            print       : false,
725
            quit        : false,
726
            readFile    : false,
727
            readUrl     : false,
728
            runCommand  : false,
729
            seal        : false,
730
            serialize   : false,
731
            spawn       : false,
732
            sync        : false,
733
            toint32     : false,
734
            version     : false
735
        },
736
737
        scope,      // The current scope
738
739
        windows = {
740
            ActiveXObject: false,
741
            CScript      : false,
742
            Debug        : false,
743
            Enumerator   : false,
744
            System       : false,
745
            VBArray      : false,
746
            WScript      : false
747
        },
748
749
        src,
750
        stack,
751
752
// standard contains the global names that are provided by the
753
// ECMAScript standard.
754
755
        standard = {
756
            Array               : false,
757
            Boolean             : false,
758
            Date                : false,
759
            decodeURI           : false,
760
            decodeURIComponent  : false,
761
            encodeURI           : false,
762
            encodeURIComponent  : false,
763
            Error               : false,
764
            'eval'              : false,
765
            EvalError           : false,
766
            Function            : false,
767
            hasOwnProperty      : false,
768
            isFinite            : false,
769
            isNaN               : false,
770
            JSON                : false,
771
            Math                : false,
772
            Number              : false,
773
            Object              : false,
774
            parseInt            : false,
775
            parseFloat          : false,
776
            RangeError          : false,
777
            ReferenceError      : false,
778
            RegExp              : false,
779
            String              : false,
780
            SyntaxError         : false,
781
            TypeError           : false,
782
            URIError            : false
783
        },
784
785
        standard_member = {
786
            E                   : true,
787
            LN2                 : true,
788
            LN10                : true,
789
            LOG2E               : true,
790
            LOG10E              : true,
791
            PI                  : true,
792
            SQRT1_2             : true,
793
            SQRT2               : true,
794
            MAX_VALUE           : true,
795
            MIN_VALUE           : true,
796
            NEGATIVE_INFINITY   : true,
797
            POSITIVE_INFINITY   : true
798
        },
799
800
        strict_mode,
801
        syntax = {},
802
        tab,
803
        token,
804
        urls,
805
        warnings,
806
807
// widget contains the global names which are provided to a Yahoo
808
// (fna Konfabulator) widget.
809
810
        widget = {
811
            alert                   : true,
812
            animator                : true,
813
            appleScript             : true,
814
            beep                    : true,
815
            bytesToUIString         : true,
816
            Canvas                  : true,
817
            chooseColor             : true,
818
            chooseFile              : true,
819
            chooseFolder            : true,
820
            closeWidget             : true,
821
            COM                     : true,
822
            convertPathToHFS        : true,
823
            convertPathToPlatform   : true,
824
            CustomAnimation         : true,
825
            escape                  : true,
826
            FadeAnimation           : true,
827
            filesystem              : true,
828
            Flash                   : true,
829
            focusWidget             : true,
830
            form                    : true,
831
            FormField               : true,
832
            Frame                   : true,
833
            HotKey                  : true,
834
            Image                   : true,
835
            include                 : true,
836
            isApplicationRunning    : true,
837
            iTunes                  : true,
838
            konfabulatorVersion     : true,
839
            log                     : true,
840
            md5                     : true,
841
            MenuItem                : true,
842
            MoveAnimation           : true,
843
            openURL                 : true,
844
            play                    : true,
845
            Point                   : true,
846
            popupMenu               : true,
847
            preferenceGroups        : true,
848
            preferences             : true,
849
            print                   : true,
850
            prompt                  : true,
851
            random                  : true,
852
            Rectangle               : true,
853
            reloadWidget            : true,
854
            ResizeAnimation         : true,
855
            resolvePath             : true,
856
            resumeUpdates           : true,
857
            RotateAnimation         : true,
858
            runCommand              : true,
859
            runCommandInBg          : true,
860
            saveAs                  : true,
861
            savePreferences         : true,
862
            screen                  : true,
863
            ScrollBar               : true,
864
            showWidgetPreferences   : true,
865
            sleep                   : true,
866
            speak                   : true,
867
            Style                   : true,
868
            suppressUpdates         : true,
869
            system                  : true,
870
            tellWidget              : true,
871
            Text                    : true,
872
            TextArea                : true,
873
            Timer                   : true,
874
            unescape                : true,
875
            updateNow               : true,
876
            URL                     : true,
877
            Web                     : true,
878
            widget                  : true,
879
            Window                  : true,
880
            XMLDOM                  : true,
881
            XMLHttpRequest          : true,
882
            yahooCheckLogin         : true,
883
            yahooLogin              : true,
884
            yahooLogout             : true
885
        },
886
887
//  xmode is used to adapt to the exceptions in html parsing.
888
//  It can have these states:
889
//      false   .js script file
890
//      html
891
//      outer
892
//      script
893
//      style
894
//      scriptstring
895
//      styleproperty
896
897
        xmode,
898
        xquote,
899
900
// unsafe comment or string
901
        ax = /@cc|<\/?|script|\]*s\]|<\s*!|&lt/i,
902
// unsafe characters that are silently deleted by one or more browsers
903
// Whitelist Replacement Char, 0xfffd
904
        cx = /[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\ufffc\ufffe-\uffff]/,
905
// token
906
        tx = /^\s*([(){}\[.,:;'"~\?\]#@]|==?=?|\/(\*(jslint|members?|global)?|=|\/)?|\*[\/=]?|\+(?:=|\++)?|-(?:=|-+)?|%=?|&[&=]?|\|[|=]?|>>?>?=?|<([\/=!]|\!(\[|--)?|<=?)?|\^=?|\!=?=?|[a-zA-Z_$][a-zA-Z0-9_$]*|[0-9]+([xX][0-9a-fA-F]+|\.[0-9]*)?([eE][+\-]?[0-9]+)?)/,
907
// html token
908
        hx = /^\s*(['"=>\/&#]|<(?:\/|\!(?:--)?)?|[a-zA-Z][a-zA-Z0-9_\-:]*|[0-9]+|--)/,
909
// characters in strings that need escapement
910
        nx = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/,
911
        nxg = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
912
// outer html token
913
        ox = /[>&]|<[\/!]?|--/,
914
// star slash
915
        lx = /\*\/|\/\*/,
916
// identifier
917
        ix = /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/,
918
// javascript url
919
        jx = /^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i,
920
// url badness
921
        ux = /&|\+|\u00AD|\.\.|\/\*|%[^;]|base64|url|expression|data|mailto/i,
922
// style
923
        sx = /^\s*([{:#%.=,>+\[\]@()"';]|\*=?|\$=|\|=|\^=|~=|[a-zA-Z_][a-zA-Z0-9_\-]*|[0-9]+|<\/|\/\*)/,
924
        ssx = /^\s*([@#!"'};:\-%.=,+\[\]()*_]|[a-zA-Z][a-zA-Z0-9._\-]*|\/\*?|\d+(?:\.\d+)?|<\/)/,
925
// attributes characters
926
        //qx = /[^a-zA-Z0-9+\-_\/ ]/,
927
        qx = /[^a-zA-Z0-9+\-_\/ .]/, // We want dots in names, period
928
// query characters for ids
929
        //dx = /[\[\]\/\\"'*<>.&:(){}+=#]/,
930
        // allow . and /
931
        dx = /[\[\]\\"'*<>&:(){}+=#]/,
932
933
        rx = {
934
            outer: hx,
935
            html: hx,
936
            style: sx,
937
            styleproperty: ssx
938
        };
939
940
    function F() {}
941
942
    if (typeof Object.create !== 'function') {
943
        Object.create = function (o) {
944
            F.prototype = o;
945
            return new F();
946
        };
947
    }
948
949
950
    function is_own(object, name) {
951
        return Object.prototype.hasOwnProperty.call(object, name);
952
    }
953
954
955
    function combine(t, o) {
956
        var n;
957
        for (n in o) {
958
            if (is_own(o, n)) {
959
                t[n] = o[n];
960
            }
961
        }
962
    }
963
964
    String.prototype.entityify = function () {
965
        return this.
966
            replace(/&/g, '&amp;').
967
            replace(/</g, '&lt;').
968
            replace(/>/g, '&gt;');
969
    };
970
971
    String.prototype.isAlpha = function () {
972
        return (this >= 'a' && this <= 'z\uffff') ||
973
            (this >= 'A' && this <= 'Z\uffff');
974
    };
975
976
977
    String.prototype.isDigit = function () {
978
        return (this >= '0' && this <= '9');
979
    };
980
981
982
    String.prototype.supplant = function (o) {
983
        return this.replace(/\{([^{}]*)\}/g, function (a, b) {
984
            var r = o[b];
985
            return typeof r === 'string' || typeof r === 'number' ? r : a;
986
        });
987
    };
988
989
    String.prototype.name = function () {
990
991
// If the string looks like an identifier, then we can return it as is.
992
// If the string contains no control characters, no quote characters, and no
993
// backslash characters, then we can simply slap some quotes around it.
994
// Otherwise we must also replace the offending characters with safe
995
// sequences.
996
997
        if (ix.test(this)) {
998
            return this;
999
        }
1000
        if (nx.test(this)) {
1001
            return '"' + this.replace(nxg, function (a) {
1002
                var c = escapes[a];
1003
                if (c) {
1004
                    return c;
1005
                }
1006
                return '\\u' + ('0000' + a.charCodeAt().toString(16)).slice(-4);
1007
            }) + '"';
1008
        }
1009
        return '"' + this + '"';
1010
    };
1011
1012
1013
    function assume() {
1014
        if (!option.safe) {
1015
            if (option.rhino) {
1016
                combine(predefined, rhino);
1017
            }
1018
            if (option.devel) {
1019
                combine(predefined, devel);
1020
            }
1021
            if (option.browser) {
1022
                combine(predefined, browser);
1023
            }
1024
            if (option.windows) {
1025
                combine(predefined, windows);
1026
            }
1027
            if (option.widget) {
1028
                combine(predefined, widget);
1029
            }
1030
        }
1031
    }
1032
1033
1034
// Produce an error warning.
1035
1036
    function quit(m, l, ch) {
1037
        throw {
1038
            name: 'JSLintError',
1039
            line: l,
1040
            character: ch,
1041
            message: m + " (" + Math.floor((l / lines.length) * 100) +
1042
                    "% scanned)."
1043
        };
1044
    }
1045
1046
    function warning(m, t, a, b, c, d) {
1047
        var ch, l, w;
1048
        t = t || nexttoken;
1049
        if (t.id === '(end)') {  // `~
1050
            t = token;
1051
        }
1052
        l = t.line || 0;
1053
        ch = t.from || 0;
1054
        w = {
1055
            id: '(error)',
1056
            raw: m,
1057
            evidence: lines[l - 1] || '',
1058
            line: l,
1059
            character: ch,
1060
            a: a,
1061
            b: b,
1062
            c: c,
1063
            d: d
1064
        };
1065
        w.reason = m.supplant(w);
1066
        JSLINT.errors.push(w);
1067
        if (option.passfail) {
1068
            quit('Stopping. ', l, ch);
1069
        }
1070
        warnings += 1;
1071
        if (warnings >= option.maxerr) {
1072
            quit("Too many errors.", l, ch);
1073
        }
1074
        return w;
1075
    }
1076
1077
    function warningAt(m, l, ch, a, b, c, d) {
1078
        return warning(m, {
1079
            line: l,
1080
            from: ch
1081
        }, a, b, c, d);
1082
    }
1083
1084
    function error(m, t, a, b, c, d) {
1085
        var w = warning(m, t, a, b, c, d);
1086
        quit("Stopping, unable to continue.", w.line, w.character);
1087
    }
1088
1089
    function errorAt(m, l, ch, a, b, c, d) {
1090
        return error(m, {
1091
            line: l,
1092
            from: ch
1093
        }, a, b, c, d);
1094
    }
1095
1096
1097
1098
// lexical analysis
1099
1100
    var lex = (function lex() {
1101
        var character, from, line, s;
1102
1103
// Private lex methods
1104
1105
        function nextLine() {
1106
            var at;
1107
            if (line >= lines.length) {
1108
                return false;
1109
            }
1110
            character = 1;
1111
            s = lines[line];
1112
            line += 1;
1113
            at = s.search(/ \t/);
1114
            if (at >= 0) {
1115
                warningAt("Mixed spaces and tabs.", line, at + 1);
1116
            }
1117
            s = s.replace(/\t/g, tab);
1118
            at = s.search(cx);
1119
            if (at >= 0) {
1120
                warningAt("Unsafe character.", line, at);
1121
            }
1122
            if (option.maxlen && option.maxlen < s.length) {
1123
                warningAt("Line too long.", line, s.length);
1124
            }
1125
            return true;
1126
        }
1127
1128
// Produce a token object.  The token inherits from a syntax symbol.
1129
1130
        function it(type, value) {
1131
            var i, t;
1132
            if (type === '(color)') {
1133
                t = {type: type};
1134
            } else if (type === '(punctuator)' ||
1135
                    (type === '(identifier)' && is_own(syntax, value))) {
1136
                t = syntax[value] || syntax['(error)'];
1137
            } else {
1138
                t = syntax[type];
1139
            }
1140
            t = Object.create(t);
1141
            if (type === '(string)' || type === '(range)') {
1142
                if (jx.test(value)) {
1143
                    warningAt("Script URL.", line, from);
1144
                }
1145
            }
1146
            if (type === '(identifier)') {
1147
                t.identifier = true;
1148
                if (value === '__iterator__' || value === '__proto__') {
1149
                    errorAt("Reserved name '{a}'.",
1150
                        line, from, value);
1151
                } else if (option.nomen &&
1152
                        (value.charAt(0) === '_' ||
1153
                         value.charAt(value.length - 1) === '_')) {
1154
                    warningAt("Unexpected {a} in '{b}'.", line, from,
1155
                        "dangling '_'", value);
1156
                }
1157
            }
1158
            t.value = value;
1159
            t.line = line;
1160
            t.character = character;
1161
            t.from = from;
1162
            i = t.id;
1163
            if (i !== '(endline)') {
1164
                prereg = i &&
1165
                    (('(,=:[!&|?{};'.indexOf(i.charAt(i.length - 1)) >= 0) ||
1166
                    i === 'return');
1167
            }
1168
            return t;
1169
        }
1170
1171
// Public lex methods
1172
1173
        return {
1174
            init: function (source) {
1175
                if (typeof source === 'string') {
1176
                    lines = source.
1177
                        replace(/\r\n/g, '\n').
1178
                        replace(/\r/g, '\n').
1179
                        split('\n');
1180
                } else {
1181
                    lines = source;
1182
                }
1183
                line = 0;
1184
                nextLine();
1185
                from = 1;
1186
            },
1187
1188
            range: function (begin, end) {
1189
                var c, value = '';
1190
                from = character;
1191
                if (s.charAt(0) !== begin) {
1192
                    errorAt("Expected '{a}' and instead saw '{b}'.",
1193
                            line, character, begin, s.charAt(0));
1194
                }
1195
                for (;;) {
1196
                    s = s.slice(1);
1197
                    character += 1;
1198
                    c = s.charAt(0);
1199
                    switch (c) {
1200
                    case '':
1201
                        errorAt("Missing '{a}'.", line, character, c);
1202
                        break;
1203
                    case end:
1204
                        s = s.slice(1);
1205
                        character += 1;
1206
                        return it('(range)', value);
1207
                    case xquote:
1208
                    case '\\':
1209
                        warningAt("Unexpected '{a}'.", line, character, c);
1210
                    }
1211
                    value += c;
1212
                }
1213
1214
            },
1215
1216
// skip all content up to marker
1217
1218
            skip_till: function (end) {
1219
                            for (;;) {
1220
                                i = s.indexOf(end);
1221
                                if (i >= 0) {
1222
                                    break;
1223
                                }
1224
                                if (!nextLine()) {
1225
                                    errorAt("Unclosed {a} block.", line, character, end);
1226
                                }
1227
                            }
1228
                            character += i;
1229
                            s = s.substr(i);
1230
            },
1231
1232
// token -- this is called by advance to get the next token.
1233
1234
            token: function () {
1235
                var b, c, captures, d, depth, high, i, l, low, q, t;
1236
1237
                function match(x) {
1238
                    var r = x.exec(s), r1;
1239
                    if (r) {
1240
                        l = r[0].length;
1241
                        r1 = r[1];
1242
                        c = r1.charAt(0);
1243
                        s = s.substr(l);
1244
                        from = character + l - r1.length;
1245
                        character += l;
1246
                        return r1;
1247
                    }
1248
                }
1249
1250
                function string(x) {
1251
                    var c, j, r = '';
1252
1253
                    if (jsonmode && x !== '"') {
1254
                        warningAt("Strings must use doublequote.",
1255
                                line, character);
1256
                    }
1257
1258
                    if (xquote === x || (xmode === 'scriptstring' && !xquote)) {
1259
                        return it('(punctuator)', x);
1260
                    }
1261
1262
                    function esc(n) {
1263
                        var i = parseInt(s.substr(j + 1, n), 16);
1264
                        j += n;
1265
                        if (i >= 32 && i <= 126 &&
1266
                                i !== 34 && i !== 92 && i !== 39) {
1267
                            warningAt("Unnecessary escapement.", line, character);
1268
                        }
1269
                        character += n;
1270
                        c = String.fromCharCode(i);
1271
                    }
1272
                    j = 0;
1273
                    for (;;) {
1274
                        while (j >= s.length) {
1275
                            j = 0;
1276
                            if (xmode !== 'html' || !nextLine()) {
1277
                                errorAt("Unclosed string.", line, from);
1278
                            }
1279
                        }
1280
                        c = s.charAt(j);
1281
                        if (c === x) {
1282
                            character += 1;
1283
                            s = s.substr(j + 1);
1284
                            return it('(string)', r, x);
1285
                        }
1286
                        if (c < ' ') {
1287
                            if (c === '\n' || c === '\r') {
1288
                                break;
1289
                            }
1290
                            warningAt("Control character in string: {a}.",
1291
                                    line, character + j, s.slice(0, j));
1292
                        } else if (c === xquote) {
1293
                            warningAt("Bad HTML string", line, character + j);
1294
                        } else if (c === '<') {
1295
                            if (option.safe && xmode === 'html') {
1296
                                warningAt("ADsafe string violation.",
1297
                                        line, character + j);
1298
                            } else if (s.charAt(j + 1) === '/' && (xmode || option.safe)) {
1299
                                warningAt("Expected '<\\/' and instead saw '</'.", line, character);
1300
                            } else if (s.charAt(j + 1) === '!' && (xmode || option.safe)) {
1301
                                warningAt("Unexpected '<!' in a string.", line, character);
1302
                            }
1303
                        } else if (c === '\\') {
1304
                            if (xmode === 'html') {
1305
                                if (option.safe) {
1306
                                    warningAt("ADsafe string violation.",
1307
                                            line, character + j);
1308
                                }
1309
                            } else if (xmode === 'styleproperty') {
1310
                                j += 1;
1311
                                character += 1;
1312
                                c = s.charAt(j);
1313
                                if (c !== x) {
1314
                                    warningAt("Escapement in style string.",
1315
                                            line, character + j);
1316
                                }
1317
                            } else {
1318
                                j += 1;
1319
                                character += 1;
1320
                                c = s.charAt(j);
1321
                                switch (c) {
1322
                                case xquote:
1323
                                    warningAt("Bad HTML string", line,
1324
                                        character + j);
1325
                                    break;
1326
                                case '\\':
1327
                                case '\'':
1328
                                case '"':
1329
                                case '/':
1330
                                    break;
1331
                                case 'b':
1332
                                    c = '\b';
1333
                                    break;
1334
                                case 'f':
1335
                                    c = '\f';
1336
                                    break;
1337
                                case 'n':
1338
                                    c = '\n';
1339
                                    break;
1340
                                case 'r':
1341
                                    c = '\r';
1342
                                    break;
1343
                                case 't':
1344
                                    c = '\t';
1345
                                    break;
1346
                                case 'u':
1347
                                    esc(4);
1348
                                    break;
1349
                                case 'v':
1350
                                    c = '\v';
1351
                                    break;
1352
                                case 'x':
1353
                                    if (jsonmode) {
1354
                                        warningAt("Avoid \\x-.", line, character);
1355
                                    }
1356
                                    esc(2);
1357
                                    break;
1358
                                default:
1359
                                    warningAt("Bad escapement.", line, character);
1360
                                }
1361
                            }
1362
                        }
1363
                        r += c;
1364
                        character += 1;
1365
                        j += 1;
1366
                    }
1367
                }
1368
1369
                for (;;) {
1370
                    if (!s) {
1371
                        return it(nextLine() ? '(endline)' : '(end)', '');
1372
                    }
1373
                    while (xmode === 'outer') {
1374
                        i = s.search(ox);
1375
                        if (i === 0) {
1376
                            break;
1377
                        } else if (i > 0) {
1378
                            character += 1;
1379
                            s = s.slice(i);
1380
                            break;
1381
                        } else {
1382
                            if (!nextLine()) {
1383
                                return it('(end)', '');
1384
                            }
1385
                        }
1386
                    }
1387
//                     t = match(rx[xmode] || tx);
1388
//                     if (!t) {
1389
//                         if (xmode === 'html') {
1390
//                             return it('(error)', s.charAt(0));
1391
//                         } else {
1392
//                             t = '';
1393
//                             c = '';
1394
//                             while (s && s < '!') {
1395
//                                 s = s.substr(1);
1396
//                             }
1397
//                             if (s) {
1398
//                                 errorAt("Unexpected '{a}'.",
1399
//                                         line, character, s.substr(0, 1));
1400
//                             }
1401
//                         }
1402
                    t = match(rx[xmode] || tx);
1403
                    if (!t) {
1404
                        t = '';
1405
                        c = '';
1406
                        while (s && s < '!') {
1407
                            s = s.substr(1);
1408
                        }
1409
                        if (s) {
1410
                            if (xmode === 'html') {
1411
                                return it('(error)', s.charAt(0));
1412
                            } else {
1413
                                errorAt("Unexpected '{a}'.",
1414
                                        line, character, s.substr(0, 1));
1415
                            }
1416
                        }
1417
                    } else {
1418
1419
    //      identifier
1420
1421
                        if (c.isAlpha() || c === '_' || c === '$') {
1422
                            return it('(identifier)', t);
1423
                        }
1424
1425
    //      number
1426
1427
                        if (c.isDigit()) {
1428
                            if (xmode !== 'style' && !isFinite(Number(t))) {
1429
                                warningAt("Bad number '{a}'.",
1430
                                    line, character, t);
1431
                            }
1432
                            if (xmode !== 'style' &&
1433
                                     xmode !== 'styleproperty' &&
1434
                                     s.substr(0, 1).isAlpha()) {
1435
                                warningAt("Missing space after '{a}'.",
1436
                                        line, character, t);
1437
                            }
1438
                            if (c === '0') {
1439
                                d = t.substr(1, 1);
1440
                                if (d.isDigit()) {
1441
                                    if (token.id !== '.' && xmode !== 'styleproperty') {
1442
                                        warningAt("Don't use extra leading zeros '{a}'.",
1443
                                            line, character, t);
1444
                                    }
1445
                                } else if (jsonmode && (d === 'x' || d === 'X')) {
1446
                                    warningAt("Avoid 0x-. '{a}'.",
1447
                                            line, character, t);
1448
                                }
1449
                            }
1450
                            if (t.substr(t.length - 1) === '.') {
1451
                                warningAt(
1452
        "A trailing decimal point can be confused with a dot '{a}'.",
1453
                                        line, character, t);
1454
                            }
1455
                            return it('(number)', t);
1456
                        }
1457
                        switch (t) {
1458
1459
    //      string
1460
1461
                        case '"':
1462
                        case "'":
1463
                            return string(t);
1464
1465
    //      // comment
1466
1467
                        case '//':
1468
                            if (src || (xmode && xmode !== 'script')) {
1469
                                warningAt("Unexpected comment.", line, character);
1470
                            } else if (xmode === 'script' && /<\s*\//i.test(s)) {
1471
                                warningAt("Unexpected <\/ in comment.", line, character);
1472
                            } else if ((option.safe || xmode === 'script') && ax.test(s)) {
1473
                                warningAt("Dangerous comment.", line, character);
1474
                            }
1475
                            s = '';
1476
                            token.comment = true;
1477
                            break;
1478
1479
    //      /* comment
1480
1481
                        case '/*':
1482
                            if (src || (xmode && xmode !== 'script' && xmode !== 'style' && xmode !== 'styleproperty')) {
1483
                                warningAt("Unexpected comment.", line, character);
1484
                            }
1485
                            if (option.safe && ax.test(s)) {
1486
                                warningAt("ADsafe comment violation.", line, character);
1487
                            }
1488
                            for (;;) {
1489
                                i = s.search(lx);
1490
                                if (i >= 0) {
1491
                                    break;
1492
                                }
1493
                                if (!nextLine()) {
1494
                                    errorAt("Unclosed comment.", line, character);
1495
                                } else {
1496
                                    if (option.safe && ax.test(s)) {
1497
                                        warningAt("ADsafe comment violation.",
1498
                                                line, character);
1499
                                    }
1500
                                }
1501
                            }
1502
                            character += i + 2;
1503
                            if (s.substr(i, 1) === '/') {
1504
                                errorAt("Nested comment.", line, character);
1505
                            }
1506
                            s = s.substr(i + 2);
1507
                            token.comment = true;
1508
                            break;
1509
1510
    //      /*members /*jslint /*global
1511
1512
                        case '/*members':
1513
                        case '/*member':
1514
                        case '/*jslint':
1515
                        case '/*global':
1516
                        case '*/':
1517
                            return {
1518
                                value: t,
1519
                                type: 'special',
1520
                                line: line,
1521
                                character: character,
1522
                                from: from
1523
                            };
1524
1525
                        case '':
1526
                            break;
1527
    //      /
1528
                        case '/':
1529
                            if (token.id === '/=') {
1530
                                errorAt(
1531
"A regular expression literal can be confused with '/='.", line, from);
1532
                            }
1533
                            if (prereg) {
1534
                                depth = 0;
1535
                                captures = 0;
1536
                                l = 0;
1537
                                for (;;) {
1538
                                    b = true;
1539
                                    c = s.charAt(l);
1540
                                    l += 1;
1541
                                    switch (c) {
1542
                                    case '':
1543
                                        errorAt("Unclosed regular expression.",
1544
                                                line, from);
1545
                                        return;
1546
                                    case '/':
1547
                                        if (depth > 0) {
1548
                                            warningAt("Unescaped '{a}'.",
1549
                                                    line, from + l, '/');
1550
                                        }
1551
                                        c = s.substr(0, l - 1);
1552
                                        q = {
1553
                                            g: true,
1554
                                            i: true,
1555
                                            m: true
1556
                                        };
1557
                                        while (q[s.charAt(l)] === true) {
1558
                                            q[s.charAt(l)] = false;
1559
                                            l += 1;
1560
                                        }
1561
                                        character += l;
1562
                                        s = s.substr(l);
1563
                                        q = s.charAt(0);
1564
                                        if (q === '/' || q === '*') {
1565
                                            errorAt("Confusing regular expression.",
1566
                                                    line, from);
1567
                                        }
1568
                                        return it('(regexp)', c);
1569
                                    case '\\':
1570
                                        c = s.charAt(l);
1571
                                        if (c < ' ') {
1572
                                            warningAt(
1573
"Unexpected control character in regular expression.", line, from + l);
1574
                                        } else if (c === '<') {
1575
                                            warningAt(
1576
"Unexpected escaped character '{a}' in regular expression.", line, from + l, c);
1577
                                        }
1578
                                        l += 1;
1579
                                        break;
1580
                                    case '(':
1581
                                        depth += 1;
1582
                                        b = false;
1583
                                        if (s.charAt(l) === '?') {
1584
                                            l += 1;
1585
                                            switch (s.charAt(l)) {
1586
                                            case ':':
1587
                                            case '=':
1588
                                            case '!':
1589
                                                l += 1;
1590
                                                break;
1591
                                            default:
1592
                                                warningAt(
1593
"Expected '{a}' and instead saw '{b}'.", line, from + l, ':', s.charAt(l));
1594
                                            }
1595
                                        } else {
1596
                                            captures += 1;
1597
                                        }
1598
                                        break;
1599
                                    case '|':
1600
                                        b = false;
1601
                                        break;
1602
                                    case ')':
1603
                                        if (depth === 0) {
1604
                                            warningAt("Unescaped '{a}'.",
1605
                                                    line, from + l, ')');
1606
                                        } else {
1607
                                            depth -= 1;
1608
                                        }
1609
                                        break;
1610
                                    case ' ':
1611
                                        q = 1;
1612
                                        while (s.charAt(l) === ' ') {
1613
                                            l += 1;
1614
                                            q += 1;
1615
                                        }
1616
                                        if (q > 1) {
1617
                                            warningAt(
1618
"Spaces are hard to count. Use {{a}}.", line, from + l, q);
1619
                                        }
1620
                                        break;
1621
                                    case '[':
1622
                                        c = s.charAt(l);
1623
                                        if (c === '^') {
1624
                                            l += 1;
1625
                                            if (option.regexp) {
1626
                                                warningAt("Insecure '{a}'.",
1627
                                                        line, from + l, c);
1628
                                            }
1629
                                        }
1630
                                        q = false;
1631
                                        if (c === ']') {
1632
                                            warningAt("Empty class.", line,
1633
                                                    from + l - 1);
1634
                                            q = true;
1635
                                        }
1636
klass:                                  do {
1637
                                            c = s.charAt(l);
1638
                                            l += 1;
1639
                                            switch (c) {
1640
                                            case '[':
1641
                                            case '^':
1642
                                                warningAt("Unescaped '{a}'.",
1643
                                                        line, from + l, c);
1644
                                                q = true;
1645
                                                break;
1646
                                            case '-':
1647
                                                if (q) {
1648
                                                    q = false;
1649
                                                } else {
1650
                                                    warningAt("Unescaped '{a}'.",
1651
                                                            line, from + l, '-');
1652
                                                    q = true;
1653
                                                }
1654
                                                break;
1655
                                            case ']':
1656
                                                if (!q) {
1657
                                                    warningAt("Unescaped '{a}'.",
1658
                                                            line, from + l - 1, '-');
1659
                                                }
1660
                                                break klass;
1661
                                            case '\\':
1662
                                                c = s.charAt(l);
1663
                                                if (c < ' ') {
1664
                                                    warningAt(
1665
"Unexpected control character in regular expression.", line, from + l);
1666
                                                } else if (c === '<') {
1667
                                                    warningAt(
1668
"Unexpected escaped character '{a}' in regular expression.", line, from + l, c);
1669
                                                }
1670
                                                l += 1;
1671
                                                q = true;
1672
                                                break;
1673
                                            case '/':
1674
                                                warningAt("Unescaped '{a}'.",
1675
                                                        line, from + l - 1, '/');
1676
                                                q = true;
1677
                                                break;
1678
                                            case '<':
1679
                                                if (xmode === 'script') {
1680
                                                    c = s.charAt(l);
1681
                                                    if (c === '!' || c === '/') {
1682
                                                        warningAt(
1683
"HTML confusion in regular expression '<{a}'.", line, from + l, c);
1684
                                                    }
1685
                                                }
1686
                                                q = true;
1687
                                                break;
1688
                                            default:
1689
                                                q = true;
1690
                                            }
1691
                                        } while (c);
1692
                                        break;
1693
                                    case '.':
1694
                                        if (option.regexp) {
1695
                                            warningAt("Insecure '{a}'.", line,
1696
                                                    from + l, c);
1697
                                        }
1698
                                        break;
1699
                                    case ']':
1700
                                    case '?':
1701
                                    case '{':
1702
                                    case '}':
1703
                                    case '+':
1704
                                    case '*':
1705
                                        warningAt("Unescaped '{a}'.", line,
1706
                                                from + l, c);
1707
                                        break;
1708
                                    case '<':
1709
                                        if (xmode === 'script') {
1710
                                            c = s.charAt(l);
1711
                                            if (c === '!' || c === '/') {
1712
                                                warningAt(
1713
"HTML confusion in regular expression '<{a}'.", line, from + l, c);
1714
                                            }
1715
                                        }
1716
                                    }
1717
                                    if (b) {
1718
                                        switch (s.charAt(l)) {
1719
                                        case '?':
1720
                                        case '+':
1721
                                        case '*':
1722
                                            l += 1;
1723
                                            if (s.charAt(l) === '?') {
1724
                                                l += 1;
1725
                                            }
1726
                                            break;
1727
                                        case '{':
1728
                                            l += 1;
1729
                                            c = s.charAt(l);
1730
                                            if (c < '0' || c > '9') {
1731
                                                warningAt(
1732
"Expected a number and instead saw '{a}'.", line, from + l, c);
1733
                                            }
1734
                                            l += 1;
1735
                                            low = +c;
1736
                                            for (;;) {
1737
                                                c = s.charAt(l);
1738
                                                if (c < '0' || c > '9') {
1739
                                                    break;
1740
                                                }
1741
                                                l += 1;
1742
                                                low = +c + (low * 10);
1743
                                            }
1744
                                            high = low;
1745
                                            if (c === ',') {
1746
                                                l += 1;
1747
                                                high = Infinity;
1748
                                                c = s.charAt(l);
1749
                                                if (c >= '0' && c <= '9') {
1750
                                                    l += 1;
1751
                                                    high = +c;
1752
                                                    for (;;) {
1753
                                                        c = s.charAt(l);
1754
                                                        if (c < '0' || c > '9') {
1755
                                                            break;
1756
                                                        }
1757
                                                        l += 1;
1758
                                                        high = +c + (high * 10);
1759
                                                    }
1760
                                                }
1761
                                            }
1762
                                            if (s.charAt(l) !== '}') {
1763
                                                warningAt(
1764
"Expected '{a}' and instead saw '{b}'.", line, from + l, '}', c);
1765
                                            } else {
1766
                                                l += 1;
1767
                                            }
1768
                                            if (s.charAt(l) === '?') {
1769
                                                l += 1;
1770
                                            }
1771
                                            if (low > high) {
1772
                                                warningAt(
1773
"'{a}' should not be greater than '{b}'.", line, from + l, low, high);
1774
                                            }
1775
                                        }
1776
                                    }
1777
                                }
1778
                                c = s.substr(0, l - 1);
1779
                                character += l;
1780
                                s = s.substr(l);
1781
                                return it('(regexp)', c);
1782
                            }
1783
                            return it('(punctuator)', t);
1784
1785
    //      punctuator
1786
1787
                        case '<!--':
1788
                            l = line;
1789
                            c = character;
1790
                            for (;;) {
1791
                                i = s.indexOf('--');
1792
                                if (i >= 0) {
1793
                                    break;
1794
                                }
1795
                                i = s.indexOf('<!-');
1796
                                if (i >= 0) {
1797
                                    errorAt("Nested HTML comment.",
1798
                                        line, character + i);
1799
                                }
1800
                                if (!nextLine()) {
1801
                                    errorAt("Unclosed HTML comment.", l, c);
1802
                                }
1803
                            }
1804
                            l = s.indexOf('<!-');
1805
                            if (l >= 0 && l < i) {
1806
                                errorAt("Nested HTML comment.",
1807
                                    line, character + l);
1808
                            }
1809
                            character += i;
1810
                            if (s[i + 2] !== '>') {
1811
                                errorAt("Expected -->.", line, character);
1812
                            }
1813
                            character += 3;
1814
                            s = s.slice(i + 3);
1815
                            break;
1816
                        case '#':
1817
                            if (xmode === 'html' || xmode === 'styleproperty') {
1818
                                for (;;) {
1819
                                    c = s.charAt(0);
1820
                                    if ((c < '0' || c > '9') &&
1821
                                            (c < 'a' || c > 'f') &&
1822
                                            (c < 'A' || c > 'F')) {
1823
                                        break;
1824
                                    }
1825
                                    character += 1;
1826
                                    s = s.substr(1);
1827
                                    t += c;
1828
                                }
1829
                                if (t.length !== 4 && t.length !== 7) {
1830
                                    warningAt("Bad hex color '{a}'.", line,
1831
                                        from + l, t);
1832
                                }
1833
                                return it('(color)', t);
1834
                            }
1835
                            return it('(punctuator)', t);
1836
                        default:
1837
                            if (xmode === 'outer' && c === '&') {
1838
                                character += 1;
1839
                                s = s.substr(1);
1840
                                for (;;) {
1841
                                    c = s.charAt(0);
1842
                                    character += 1;
1843
                                    s = s.substr(1);
1844
                                    if (c === ';') {
1845
                                        break;
1846
                                    }
1847
                                    if (!((c >= '0' && c <= '9') ||
1848
                                            (c >= 'a' && c <= 'z') ||
1849
                                            c === '#')) {
1850
                                        errorAt("Bad entity", line, from + l,
1851
                                        character);
1852
                                    }
1853
                                }
1854
                                break;
1855
                            }
1856
                            return it('(punctuator)', t);
1857
                        }
1858
                    }
1859
                }
1860
            }
1861
        };
1862
    }());
1863
1864
1865
    function addlabel(t, type) {
1866
1867
        if (option.safe && funct['(global)'] &&
1868
                typeof predefined[t] !== 'boolean') {
1869
            warning('ADsafe global: ' + t + '.', token);
1870
        } else if (t === 'hasOwnProperty') {
1871
            warning("'hasOwnProperty' is a really bad name.");
1872
        }
1873
1874
// Define t in the current function in the current scope.
1875
1876
        if (is_own(funct, t) && !funct['(global)']) {
1877
            warning(funct[t] === true ?
1878
                "'{a}' was used before it was defined." :
1879
                "'{a}' is already defined.",
1880
                nexttoken, t);
1881
        }
1882
        funct[t] = type;
1883
        if (funct['(global)']) {
1884
            global[t] = funct;
1885
            if (is_own(implied, t)) {
1886
                warning("'{a}' was used before it was defined.", nexttoken, t);
1887
                delete implied[t];
1888
            }
1889
        } else {
1890
            scope[t] = funct;
1891
        }
1892
    }
1893
1894
1895
    function doOption() {
1896
        var b, obj, filter, o = nexttoken.value, t, v;
1897
        switch (o) {
1898
        case '*/':
1899
            error("Unbegun comment.");
1900
            break;
1901
        case '/*members':
1902
        case '/*member':
1903
            o = '/*members';
1904
            if (!membersOnly) {
1905
                membersOnly = {};
1906
            }
1907
            obj = membersOnly;
1908
            break;
1909
        case '/*jslint':
1910
            if (option.safe) {
1911
                warning("ADsafe restriction.");
1912
            }
1913
            obj = option;
1914
            filter = boolOptions;
1915
            break;
1916
        case '/*global':
1917
            if (option.safe) {
1918
                warning("ADsafe restriction.");
1919
            }
1920
            obj = predefined;
1921
            break;
1922
        default:
1923
        }
1924
        t = lex.token();
1925
loop:   for (;;) {
1926
            for (;;) {
1927
                if (t.type === 'special' && t.value === '*/') {
1928
                    break loop;
1929
                }
1930
                if (t.id !== '(endline)' && t.id !== ',') {
1931
                    break;
1932
                }
1933
                t = lex.token();
1934
            }
1935
            if (t.type !== '(string)' && t.type !== '(identifier)' &&
1936
                    o !== '/*members') {
1937
                error("Bad option.", t);
1938
            }
1939
            v = lex.token();
1940
            if (v.id === ':') {
1941
                v = lex.token();
1942
                if (obj === membersOnly) {
1943
                    error("Expected '{a}' and instead saw '{b}'.",
1944
                            t, '*/', ':');
1945
                }
1946
                if (t.value === 'indent' && o === '/*jslint') {
1947
                    b = +v.value;
1948
                    if (typeof b !== 'number' || !isFinite(b) || b <= 0 ||
1949
                            Math.floor(b) !== b) {
1950
                        error("Expected a small integer and instead saw '{a}'.",
1951
                                v, v.value);
1952
                    }
1953
                    obj.white = true;
1954
                    obj.indent = b;
1955
                } else if (t.value === 'maxerr' && o === '/*jslint') {
1956
                    b = +v.value;
1957
                    if (typeof b !== 'number' || !isFinite(b) || b <= 0 ||
1958
                            Math.floor(b) !== b) {
1959
                        error("Expected a small integer and instead saw '{a}'.",
1960
                                v, v.value);
1961
                    }
1962
                    obj.maxerr = b;
1963
                } else if (t.value === 'maxlen' && o === '/*jslint') {
1964
                    b = +v.value;
1965
                    if (typeof b !== 'number' || !isFinite(b) || b <= 0 ||
1966
                            Math.floor(b) !== b) {
1967
                        error("Expected a small integer and instead saw '{a}'.",
1968
                                v, v.value);
1969
                    }
1970
                    obj.maxlen = b;
1971
                } else if (v.value === 'true') {
1972
                    obj[t.value] = true;
1973
                } else if (v.value === 'false') {
1974
                    obj[t.value] = false;
1975
                } else {
1976
                    error("Bad option value.", v);
1977
                }
1978
                t = lex.token();
1979
            } else {
1980
                if (o === '/*jslint') {
1981
                    error("Missing option value.", t);
1982
                }
1983
                obj[t.value] = false;
1984
                t = v;
1985
            }
1986
        }
1987
        if (filter) {
1988
            assume();
1989
        }
1990
    }
1991
1992
1993
// We need a peek function. If it has an argument, it peeks that much farther
1994
// ahead. It is used to distinguish
1995
//     for ( var i in ...
1996
// from
1997
//     for ( var i = ...
1998
1999
    function peek(p) {
2000
        var i = p || 0, j = 0, t;
2001
2002
        while (j <= i) {
2003
            t = lookahead[j];
2004
            if (!t) {
2005
                t = lookahead[j] = lex.token();
2006
            }
2007
            j += 1;
2008
        }
2009
        return t;
2010
    }
2011
2012
2013
2014
// Produce the next token. It looks for programming errors.
2015
2016
    function advance(id, t) {
2017
        switch (token.id) {
2018
        case '(number)':
2019
            if (nexttoken.id === '.') {
2020
                warning(
2021
"A dot following a number can be confused with a decimal point.", token);
2022
            }
2023
            break;
2024
        case '-':
2025
            if (nexttoken.id === '-' || nexttoken.id === '--') {
2026
                warning("Confusing minusses.");
2027
            }
2028
            break;
2029
        case '+':
2030
            if (nexttoken.id === '+' || nexttoken.id === '++') {
2031
                warning("Confusing plusses.");
2032
            }
2033
            break;
2034
        }
2035
        if (token.type === '(string)' || token.identifier) {
2036
            anonname = token.value;
2037
        }
2038
2039
        if (id && nexttoken.id !== id) {
2040
            if (t) {
2041
                if (nexttoken.id === '(end)') {
2042
                    warning("Unmatched '{a}'.", t, t.id);
2043
                } else {
2044
                    warning(
2045
"Expected '{a}' to match '{b}' from line {c} and instead saw '{d}'.",
2046
                            nexttoken, id, t.id, t.line, nexttoken.value);
2047
                }
2048
            } else if (nexttoken.type !== '(identifier)' ||
2049
                            nexttoken.value !== id) {
2050
                warning("Expected '{a}' and instead saw '{b}'.",
2051
                        nexttoken, id, nexttoken.value);
2052
            }
2053
        }
2054
        prevtoken = token;
2055
        token = nexttoken;
2056
        for (;;) {
2057
            nexttoken = lookahead.shift() || lex.token();
2058
            if (nexttoken.id === '(end)' || nexttoken.id === '(error)') {
2059
                return;
2060
            }
2061
            if (nexttoken.type === 'special') {
2062
                doOption();
2063
            } else {
2064
                if (nexttoken.id !== '(endline)') {
2065
                    break;
2066
                }
2067
            }
2068
        }
2069
    }
2070
2071
2072
// This is the heart of JSLINT, the Pratt parser. In addition to parsing, it
2073
// is looking for ad hoc lint patterns. We add to Pratt's model .fud, which is
2074
// like nud except that it is only used on the first token of a statement.
2075
// Having .fud makes it much easier to define JavaScript. I retained Pratt's
2076
// nomenclature.
2077
2078
// .nud     Null denotation
2079
// .fud     First null denotation
2080
// .led     Left denotation
2081
//  lbp     Left binding power
2082
//  rbp     Right binding power
2083
2084
// They are key to the parsing method called Top Down Operator Precedence.
2085
2086
    function parse(rbp, initial) {
2087
        var left;
2088
        if (nexttoken.id === '(end)') {
2089
            error("Unexpected early end of program.", token);
2090
        }
2091
        advance();
2092
        if (option.safe && typeof predefined[token.value] === 'boolean' &&
2093
                (nexttoken.id !== '(' && nexttoken.id !== '.')) {
2094
            warning('ADsafe violation.', token);
2095
        }
2096
        if (initial) {
2097
            anonname = 'anonymous';
2098
            funct['(verb)'] = token.value;
2099
        }
2100
        if (initial === true && token.fud) {
2101
            left = token.fud();
2102
        } else {
2103
            if (token.nud) {
2104
                left = token.nud();
2105
            } else {
2106
                if (nexttoken.type === '(number)' && token.id === '.') {
2107
                    warning(
2108
"A leading decimal point can be confused with a dot: '.{a}'.",
2109
                            token, nexttoken.value);
2110
                    advance();
2111
                    return token;
2112
                } else {
2113
                    error("Expected an identifier and instead saw '{a}'.",
2114
                            token, token.id);
2115
                }
2116
            }
2117
            while (rbp < nexttoken.lbp) {
2118
                advance();
2119
                if (token.led) {
2120
                    left = token.led(left);
2121
                } else {
2122
                    error("Expected an operator and instead saw '{a}'.",
2123
                        token, token.id);
2124
                }
2125
            }
2126
        }
2127
        return left;
2128
    }
2129
2130
2131
// Functions for conformance of style.
2132
2133
    function adjacent(left, right) {
2134
        left = left || token;
2135
        right = right || nexttoken;
2136
        if (option.white || xmode === 'styleproperty' || xmode === 'style') {
2137
            if (left.character !== right.from && left.line === right.line) {
2138
                warning("Unexpected space after '{a}'.", right, left.value);
2139
            }
2140
        }
2141
    }
2142
2143
    function nospace(left, right) {
2144
        left = left || token;
2145
        right = right || nexttoken;
2146
        if (option.white && !left.comment) {
2147
            if (left.line === right.line) {
2148
                adjacent(left, right);
2149
            }
2150
        }
2151
    }
2152
2153
2154
    function nonadjacent(left, right) {
2155
        if (option.white) {
2156
            left = left || token;
2157
            right = right || nexttoken;
2158
            if (left.line === right.line && left.character === right.from) {
2159
                warning("Missing space after '{a}'.",
2160
                        nexttoken, left.value);
2161
            }
2162
        }
2163
    }
2164
2165
    function nobreaknonadjacent(left, right) {
2166
        left = left || token;
2167
        right = right || nexttoken;
2168
        if (!option.laxbreak && left.line !== right.line) {
2169
            warning("Bad line breaking before '{a}'.", right, right.id);
2170
        } else if (option.white) {
2171
            left = left || token;
2172
            right = right || nexttoken;
2173
            if (left.character === right.from) {
2174
                warning("Missing space after '{a}'.",
2175
                        nexttoken, left.value);
2176
            }
2177
        }
2178
    }
2179
2180
    function indentation(bias) {
2181
        var i;
2182
        if (option.white && nexttoken.id !== '(end)') {
2183
            i = indent + (bias || 0);
2184
            if (nexttoken.from !== i) {
2185
                warning(
2186
"Expected '{a}' to have an indentation at {b} instead at {c}.",
2187
                        nexttoken, nexttoken.value, i, nexttoken.from);
2188
            }
2189
        }
2190
    }
2191
2192
    function nolinebreak(t) {
2193
        t = t || token;
2194
        if (t.line !== nexttoken.line) {
2195
            warning("Line breaking error '{a}'.", t, t.value);
2196
        }
2197
    }
2198
2199
2200
    function comma() {
2201
        if (token.line !== nexttoken.line) {
2202
            if (!option.laxbreak) {
2203
                warning("Bad line breaking before '{a}'.", token, nexttoken.id);
2204
            }
2205
        } else if (token.character !== nexttoken.from && option.white) {
2206
            warning("Unexpected space after '{a}'.", nexttoken, token.value);
2207
        }
2208
        advance(',');
2209
        nonadjacent(token, nexttoken);
2210
    }
2211
2212
2213
// Functional constructors for making the symbols that will be inherited by
2214
// tokens.
2215
2216
    function symbol(s, p) {
2217
        var x = syntax[s];
2218
        if (!x || typeof x !== 'object') {
2219
            syntax[s] = x = {
2220
                id: s,
2221
                lbp: p,
2222
                value: s
2223
            };
2224
        }
2225
        return x;
2226
    }
2227
2228
2229
    function delim(s) {
2230
        return symbol(s, 0);
2231
    }
2232
2233
2234
    function stmt(s, f) {
2235
        var x = delim(s);
2236
        x.identifier = x.reserved = true;
2237
        x.fud = f;
2238
        return x;
2239
    }
2240
2241
2242
    function blockstmt(s, f) {
2243
        var x = stmt(s, f);
2244
        x.block = true;
2245
        return x;
2246
    }
2247
2248
2249
    function reserveName(x) {
2250
        var c = x.id.charAt(0);
2251
        if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
2252
            x.identifier = x.reserved = true;
2253
        }
2254
        return x;
2255
    }
2256
2257
2258
    function prefix(s, f) {
2259
        var x = symbol(s, 150);
2260
        reserveName(x);
2261
        x.nud = (typeof f === 'function') ? f : function () {
2262
            this.right = parse(150);
2263
            this.arity = 'unary';
2264
            if (this.id === '++' || this.id === '--') {
2265
                if (option.plusplus) {
2266
                    warning("Unexpected use of '{a}'.", this, this.id);
2267
                } else if ((!this.right.identifier || this.right.reserved) &&
2268
                        this.right.id !== '.' && this.right.id !== '[') {
2269
                    warning("Bad operand.", this);
2270
                }
2271
            }
2272
            return this;
2273
        };
2274
        return x;
2275
    }
2276
2277
2278
    function type(s, f) {
2279
        var x = delim(s);
2280
        x.type = s;
2281
        x.nud = f;
2282
        return x;
2283
    }
2284
2285
2286
    function reserve(s, f) {
2287
        var x = type(s, f);
2288
        x.identifier = x.reserved = true;
2289
        return x;
2290
    }
2291
2292
2293
    function reservevar(s, v) {
2294
        return reserve(s, function () {
2295
            if (this.id === 'this' || this.id === 'arguments' ||
2296
                    this.id === 'eval') {
2297
                if (strict_mode && funct['(global)']) {
2298
                    warning("Strict violation.", this);
2299
                } else if (option.safe) {
2300
                    warning("ADsafe violation.", this);
2301
                }
2302
            }
2303
            return this;
2304
        });
2305
    }
2306
2307
2308
    function infix(s, f, p, w) {
2309
        var x = symbol(s, p);
2310
        reserveName(x);
2311
        x.led = function (left) {
2312
            if (!w) {
2313
                nobreaknonadjacent(prevtoken, token);
2314
                nonadjacent(token, nexttoken);
2315
            }
2316
            if (typeof f === 'function') {
2317
                return f(left, this);
2318
            } else {
2319
                this.left = left;
2320
                this.right = parse(p);
2321
                return this;
2322
            }
2323
        };
2324
        return x;
2325
    }
2326
2327
2328
    function relation(s, f) {
2329
        var x = symbol(s, 100);
2330
        x.led = function (left) {
2331
            nobreaknonadjacent(prevtoken, token);
2332
            nonadjacent(token, nexttoken);
2333
            var right = parse(100);
2334
            if ((left && left.id === 'NaN') || (right && right.id === 'NaN')) {
2335
                warning("Use the isNaN function to compare with NaN.", this);
2336
            } else if (f) {
2337
                f.apply(this, [left, right]);
2338
            }
2339
            if (left.id === '!') {
2340
                warning("Confusing use of '{a}'.", left, '!');
2341
            }
2342
            if (right.id === '!') {
2343
                warning("Confusing use of '{a}'.", left, '!');
2344
            }
2345
            this.left = left;
2346
            this.right = right;
2347
            return this;
2348
        };
2349
        return x;
2350
    }
2351
2352
2353
    function isPoorRelation(node) {
2354
        return node &&
2355
              ((node.type === '(number)' && +node.value === 0) ||
2356
               (node.type === '(string)' && node.value === ' ') ||
2357
                node.type === 'true' ||
2358
                node.type === 'false' ||
2359
                node.type === 'undefined' ||
2360
                node.type === 'null');
2361
    }
2362
2363
2364
    function assignop(s, f) {
2365
        symbol(s, 20).exps = true;
2366
        return infix(s, function (left, that) {
2367
            var l;
2368
            that.left = left;
2369
            if (predefined[left.value] === false &&
2370
                    scope[left.value]['(global)'] === true) {
2371
                warning('Read only.', left);
2372
            }
2373
            if (option.safe) {
2374
                l = left;
2375
                do {
2376
                    if (typeof predefined[l.value] === 'boolean') {
2377
                        warning('ADsafe violation.', l);
2378
                    }
2379
                    l = l.left;
2380
                } while (l);
2381
            }
2382
            if (left) {
2383
                if (left.id === '.' || left.id === '[') {
2384
                    if (!left.left || left.left.value === 'arguments') {
2385
                        warning('Bad assignment.', that);
2386
                    }
2387
                    that.right = parse(19);
2388
                    return that;
2389
                } else if (left.identifier && !left.reserved) {
2390
                    if (funct[left.value] === 'exception') {
2391
                        warning("Do not assign to the exception parameter.", left);
2392
                    }
2393
                    that.right = parse(19);
2394
                    return that;
2395
                }
2396
                if (left === syntax['function']) {
2397
                    warning(
2398
"Expected an identifier in an assignment and instead saw a function invocation.",
2399
                                token);
2400
                }
2401
            }
2402
            error("Bad assignment.", that);
2403
        }, 20);
2404
    }
2405
2406
    function bitwise(s, f, p) {
2407
        var x = symbol(s, p);
2408
        reserveName(x);
2409
        x.led = (typeof f === 'function') ? f : function (left) {
2410
            if (option.bitwise) {
2411
                warning("Unexpected use of '{a}'.", this, this.id);
2412
            }
2413
            this.left = left;
2414
            this.right = parse(p);
2415
            return this;
2416
        };
2417
        return x;
2418
    }
2419
2420
    function bitwiseassignop(s) {
2421
        symbol(s, 20).exps = true;
2422
        return infix(s, function (left, that) {
2423
            if (option.bitwise) {
2424
                warning("Unexpected use of '{a}'.", that, that.id);
2425
            }
2426
            nonadjacent(prevtoken, token);
2427
            nonadjacent(token, nexttoken);
2428
            if (left) {
2429
                if (left.id === '.' || left.id === '[' ||
2430
                        (left.identifier && !left.reserved)) {
2431
                    parse(19);
2432
                    return that;
2433
                }
2434
                if (left === syntax['function']) {
2435
                    warning(
2436
"Expected an identifier in an assignment, and instead saw a function invocation.",
2437
                                token);
2438
                }
2439
                return that;
2440
            }
2441
            error("Bad assignment.", that);
2442
        }, 20);
2443
    }
2444
2445
2446
    function suffix(s, f) {
2447
        var x = symbol(s, 150);
2448
        x.led = function (left) {
2449
            if (option.plusplus) {
2450
                warning("Unexpected use of '{a}'.", this, this.id);
2451
            } else if ((!left.identifier || left.reserved) &&
2452
                    left.id !== '.' && left.id !== '[') {
2453
                warning("Bad operand.", this);
2454
            }
2455
            this.left = left;
2456
            return this;
2457
        };
2458
        return x;
2459
    }
2460
2461
2462
    function optionalidentifier() {
2463
        if (nexttoken.identifier) {
2464
            advance();
2465
            if (option.safe && banned[token.value]) {
2466
                warning("ADsafe violation: '{a}'.", token, token.value);
2467
            } else if (token.reserved && !option.es5) {
2468
                warning("Expected an identifier and instead saw '{a}' (a reserved word).",
2469
                        token, token.id);
2470
            }
2471
            return token.value;
2472
        }
2473
    }
2474
2475
2476
    function identifier() {
2477
        var i = optionalidentifier();
2478
        if (i) {
2479
            return i;
2480
        }
2481
        if (token.id === 'function' && nexttoken.id === '(') {
2482
            warning("Missing name in function statement.");
2483
        } else {
2484
            error("Expected an identifier and instead saw '{a}'.",
2485
                    nexttoken, nexttoken.value);
2486
        }
2487
    }
2488
2489
    function reachable(s) {
2490
        var i = 0, t;
2491
        if (nexttoken.id !== ';' || noreach) {
2492
            return;
2493
        }
2494
        for (;;) {
2495
            t = peek(i);
2496
            if (t.reach) {
2497
                return;
2498
            }
2499
            if (t.id !== '(endline)') {
2500
                if (t.id === 'function') {
2501
                    warning(
2502
"Inner functions should be listed at the top of the outer function.", t);
2503
                    break;
2504
                }
2505
                warning("Unreachable '{a}' after '{b}'.", t, t.value, s);
2506
                break;
2507
            }
2508
            i += 1;
2509
        }
2510
    }
2511
2512
2513
    function statement(noindent) {
2514
        var i = indent, r, s = scope, t = nexttoken;
2515
2516
// We don't like the empty statement.
2517
2518
        if (t.id === ';') {
2519
            warning("Unnecessary semicolon.", t);
2520
            advance(';');
2521
            return;
2522
        }
2523
2524
// Is this a labelled statement?
2525
2526
        if (t.identifier && !t.reserved && peek().id === ':') {
2527
            advance();
2528
            advance(':');
2529
            scope = Object.create(s);
2530
            addlabel(t.value, 'label');
2531
            if (!nexttoken.labelled) {
2532
                warning("Label '{a}' on {b} statement.",
2533
                        nexttoken, t.value, nexttoken.value);
2534
            }
2535
            if (jx.test(t.value + ':')) {
2536
                warning("Label '{a}' looks like a javascript url.",
2537
                        t, t.value);
2538
            }
2539
            nexttoken.label = t.value;
2540
            t = nexttoken;
2541
        }
2542
2543
// Parse the statement.
2544
2545
        if (!noindent) {
2546
            indentation();
2547
        }
2548
        r = parse(0, true);
2549
2550
// Look for the final semicolon.
2551
2552
        if (!t.block) {
2553
            if (!r || !r.exps) {
2554
                warning(
2555
"Expected an assignment or function call and instead saw an expression.",
2556
                        token);
2557
            } else if (r.id === '(' && r.left.id === 'new') {
2558
                warning("Do not use 'new' for side effects.");
2559
            }
2560
            if (nexttoken.id !== ';') {
2561
                warningAt("Missing semicolon.", token.line,
2562
                        token.from + token.value.length);
2563
            } else {
2564
                adjacent(token, nexttoken);
2565
                advance(';');
2566
                nonadjacent(token, nexttoken);
2567
            }
2568
        }
2569
2570
// Restore the indentation.
2571
2572
        indent = i;
2573
        scope = s;
2574
        return r;
2575
    }
2576
2577
2578
    function use_strict() {
2579
        if (nexttoken.value === 'use strict') {
2580
            advance();
2581
            advance(';');
2582
            strict_mode = true;
2583
            return true;
2584
        } else {
2585
            return false;
2586
        }
2587
    }
2588
2589
2590
    function statements(begin) {
2591
        var a = [], f, p;
2592
        if (begin && !use_strict() && option.strict) {
2593
            warning('Missing "use strict" statement.', nexttoken);
2594
        }
2595
        if (option.adsafe) {
2596
            switch (begin) {
2597
            case 'script':
2598
                if (!adsafe_may) {
2599
                    if (nexttoken.value !== 'ADSAFE' ||
2600
                            peek(0).id !== '.' ||
2601
                            (peek(1).value !== 'id' &&
2602
                            peek(1).value !== 'go')) {
2603
                        error('ADsafe violation: Missing ADSAFE.id or ADSAFE.go.',
2604
                            nexttoken);
2605
                    }
2606
                }
2607
                if (nexttoken.value === 'ADSAFE' &&
2608
                        peek(0).id === '.' &&
2609
                        peek(1).value === 'id') {
2610
                    if (adsafe_may) {
2611
                        error('ADsafe violation.', nexttoken);
2612
                    }
2613
                    advance('ADSAFE');
2614
                    advance('.');
2615
                    advance('id');
2616
                    advance('(');
2617
                    if (nexttoken.value !== adsafe_id) {
2618
                        error('ADsafe violation: id does not match.', nexttoken);
2619
                    }
2620
                    advance('(string)');
2621
                    advance(')');
2622
                    advance(';');
2623
                    adsafe_may = true;
2624
                }
2625
                break;
2626
            case 'lib':
2627
                if (nexttoken.value === 'ADSAFE') {
2628
                    advance('ADSAFE');
2629
                    advance('.');
2630
                    advance('lib');
2631
                    advance('(');
2632
                    advance('(string)');
2633
                    comma();
2634
                    f = parse(0);
2635
                    if (f.id !== 'function') {
2636
                        error('The second argument to lib must be a function.', f);
2637
                    }
2638
                    p = f.funct['(params)'];
2639
                    p = p && p.join(', ');
2640
                    if (p && p !== 'lib') {
2641
                        error("Expected '{a}' and instead saw '{b}'.",
2642
                            f, '(lib)', '(' + p + ')');
2643
                    }
2644
                    advance(')');
2645
                    advance(';');
2646
                    return a;
2647
                } else {
2648
                    error("ADsafe lib violation.");
2649
                }
2650
            }
2651
        }
2652
        while (!nexttoken.reach && nexttoken.id !== '(end)') {
2653
            if (nexttoken.id === ';') {
2654
                warning("Unnecessary semicolon.");
2655
                advance(';');
2656
            } else {
2657
                a.push(statement());
2658
            }
2659
        }
2660
        return a;
2661
    }
2662
2663
2664
    function block(f) {
2665
        var a, b = inblock, old_indent = indent, s = scope, t;
2666
        inblock = f;
2667
        scope = Object.create(scope);
2668
        nonadjacent(token, nexttoken);
2669
        t = nexttoken;
2670
        if (nexttoken.id === '{') {
2671
            advance('{');
2672
            if (nexttoken.id !== '}' || token.line !== nexttoken.line) {
2673
                indent += option.indent;
2674
                while (!f && nexttoken.from > indent) {
2675
                    indent += option.indent;
2676
                }
2677
                if (!f) {
2678
                    use_strict();
2679
                }
2680
                a = statements();
2681
                indent -= option.indent;
2682
                indentation();
2683
            }
2684
            advance('}', t);
2685
            indent = old_indent;
2686
        } else {
2687
            warning("Expected '{a}' and instead saw '{b}'.",
2688
                    nexttoken, '{', nexttoken.value);
2689
            noreach = true;
2690
            a = [statement()];
2691
            noreach = false;
2692
        }
2693
        funct['(verb)'] = null;
2694
        scope = s;
2695
        inblock = b;
2696
        return a;
2697
    }
2698
2699
2700
// An identity function, used by string and number tokens.
2701
2702
    function idValue() {
2703
        return this;
2704
    }
2705
2706
2707
    function countMember(m) {
2708
        if (membersOnly && typeof membersOnly[m] !== 'boolean') {
2709
            warning("Unexpected /*member '{a}'.", token, m);
2710
        }
2711
        if (typeof member[m] === 'number') {
2712
            member[m] += 1;
2713
        } else {
2714
            member[m] = 1;
2715
        }
2716
    }
2717
2718
2719
    function note_implied(token) {
2720
        var name = token.value, line = token.line, a = implied[name];
2721
        if (typeof a === 'function') {
2722
            a = false;
2723
        }
2724
        if (!a) {
2725
            a = [line];
2726
            implied[name] = a;
2727
        } else if (a[a.length - 1] !== line) {
2728
            a.push(line);
2729
        }
2730
    }
2731
2732
// CSS parsing.
2733
2734
2735
    function cssName() {
2736
        if (nexttoken.identifier) {
2737
            advance();
2738
            return true;
2739
        }
2740
    }
2741
2742
    function cssNumber() {
2743
        if (nexttoken.id === '-') {
2744
            advance('-');
2745
            adjacent();
2746
            nolinebreak();
2747
        }
2748
        if (nexttoken.type === '(number)') {
2749
            advance('(number)');
2750
            return true;
2751
        }
2752
    }
2753
2754
    function cssString() {
2755
        if (nexttoken.type === '(string)') {
2756
            advance();
2757
            return true;
2758
        }
2759
    }
2760
2761
    function cssColor() {
2762
        var i, number, value;
2763
        if (nexttoken.identifier) {
2764
            value = nexttoken.value;
2765
            if (value === 'rgb' || value === 'rgba') {
2766
                advance();
2767
                advance('(');
2768
                for (i = 0; i < 3; i += 1) {
2769
                    if (i) {
2770
                        advance(',');
2771
                    }
2772
                    number = nexttoken.value;
2773
                    if (nexttoken.type !== '(number)' || number < 0) {
2774
                        warning("Expected a positive number and instead saw '{a}'",
2775
                            nexttoken, number);
2776
                        advance();
2777
                    } else {
2778
                        advance();
2779
                        if (nexttoken.id === '%') {
2780
                            advance('%');
2781
                            if (number > 100) {
2782
                                warning("Expected a percentage and instead saw '{a}'",
2783
                                    token, number);
2784
                            }
2785
                        } else {
2786
                            if (number > 255) {
2787
                                warning("Expected a small number and instead saw '{a}'",
2788
                                    token, number);
2789
                            }
2790
                        }
2791
                    }
2792
                }
2793
                if (value === 'rgba') {
2794
                    advance(',');
2795
                    number = +nexttoken.value;
2796
                    if (nexttoken.type !== '(number)' || number < 0 || number > 1) {
2797
                        warning("Expected a number between 0 and 1 and instead saw '{a}'",
2798
                            nexttoken, number);
2799
                    }
2800
                    advance();
2801
                    if (nexttoken.id === '%') {
2802
                        warning("Unexpected '%'.");
2803
                        advance('%');
2804
                    }
2805
                }
2806
                advance(')');
2807
                return true;
2808
            } else if (cssColorData[nexttoken.value] === true) {
2809
                advance();
2810
                return true;
2811
            }
2812
        } else if (nexttoken.type === '(color)') {
2813
            advance();
2814
            return true;
2815
        }
2816
        return false;
2817
    }
2818
2819
    function cssLength() {
2820
        if (nexttoken.id === '-') {
2821
            advance('-');
2822
            adjacent();
2823
            nolinebreak();
2824
        }
2825
        if (nexttoken.type === '(number)') {
2826
            advance();
2827
            if (nexttoken.type !== '(string)' &&
2828
                    cssLengthData[nexttoken.value] === true) {
2829
                adjacent();
2830
                advance();
2831
            } else if (+token.value !== 0) {
2832
                warning("Expected a linear unit and instead saw '{a}'.",
2833
                    nexttoken, nexttoken.value);
2834
            }
2835
            return true;
2836
        }
2837
        return false;
2838
    }
2839
2840
    function cssLineHeight() {
2841
        if (nexttoken.id === '-') {
2842
            advance('-');
2843
            adjacent();
2844
        }
2845
        if (nexttoken.type === '(number)') {
2846
            advance();
2847
            if (nexttoken.type !== '(string)' &&
2848
                    cssLengthData[nexttoken.value] === true) {
2849
                adjacent();
2850
                advance();
2851
            }
2852
            return true;
2853
        }
2854
        return false;
2855
    }
2856
2857
    function cssWidth() {
2858
        if (nexttoken.identifier) {
2859
            switch (nexttoken.value) {
2860
            case 'thin':
2861
            case 'medium':
2862
            case 'thick':
2863
                advance();
2864
                return true;
2865
            }
2866
        } else {
2867
            return cssLength();
2868
        }
2869
    }
2870
2871
    function cssMargin() {
2872
        if (nexttoken.identifier) {
2873
            if (nexttoken.value === 'auto') {
2874
                advance();
2875
                return true;
2876
            }
2877
        } else {
2878
            return cssLength();
2879
        }
2880
    }
2881
2882
    function cssAttr() {
2883
        if (nexttoken.identifier && nexttoken.value === 'attr') {
2884
            advance();
2885
            advance('(');
2886
            if (!nexttoken.identifier) {
2887
                warning("Expected a name and instead saw '{a}'.",
2888
                        nexttoken, nexttoken.value);
2889
            }
2890
            advance();
2891
            advance(')');
2892
            return true;
2893
        }
2894
        return false;
2895
    }
2896
2897
    function cssCommaList() {
2898
        while (nexttoken.id !== ';') {
2899
            if (!cssName() && !cssString()) {
2900
                warning("Expected a name and instead saw '{a}'.",
2901
                        nexttoken, nexttoken.value);
2902
            }
2903
            if (nexttoken.id !== ',') {
2904
                return true;
2905
            }
2906
            comma();
2907
        }
2908
    }
2909
2910
    function cssCounter() {
2911
        if (nexttoken.identifier && nexttoken.value === 'counter') {
2912
            advance();
2913
            advance('(');
2914
            if (!nexttoken.identifier) {
2915
            }
2916
            advance();
2917
            if (nexttoken.id === ',') {
2918
                comma();
2919
                if (nexttoken.type !== '(string)') {
2920
                    warning("Expected a string and instead saw '{a}'.",
2921
                        nexttoken, nexttoken.value);
2922
                }
2923
                advance();
2924
            }
2925
            advance(')');
2926
            return true;
2927
        }
2928
        if (nexttoken.identifier && nexttoken.value === 'counters') {
2929
            advance();
2930
            advance('(');
2931
            if (!nexttoken.identifier) {
2932
                warning("Expected a name and instead saw '{a}'.",
2933
                        nexttoken, nexttoken.value);
2934
            }
2935
            advance();
2936
            if (nexttoken.id === ',') {
2937
                comma();
2938
                if (nexttoken.type !== '(string)') {
2939
                    warning("Expected a string and instead saw '{a}'.",
2940
                        nexttoken, nexttoken.value);
2941
                }
2942
                advance();
2943
            }
2944
            if (nexttoken.id === ',') {
2945
                comma();
2946
                if (nexttoken.type !== '(string)') {
2947
                    warning("Expected a string and instead saw '{a}'.",
2948
                        nexttoken, nexttoken.value);
2949
                }
2950
                advance();
2951
            }
2952
            advance(')');
2953
            return true;
2954
        }
2955
        return false;
2956
    }
2957
2958
2959
    function cssShape() {
2960
        var i;
2961
        if (nexttoken.identifier && nexttoken.value === 'rect') {
2962
            advance();
2963
            advance('(');
2964
            for (i = 0; i < 4; i += 1) {
2965
                if (!cssLength()) {
2966
                    warning("Expected a number and instead saw '{a}'.",
2967
                        nexttoken, nexttoken.value);
2968
                    break;
2969
                }
2970
            }
2971
            advance(')');
2972
            return true;
2973
        }
2974
        return false;
2975
    }
2976
2977
    function cssUrl() {
2978
        var c, url;
2979
        if (nexttoken.identifier && nexttoken.value === 'url') {
2980
            nexttoken = lex.range('(', ')');
2981
            url = nexttoken.value;
2982
            c = url.charAt(0);
2983
            if (c === '"' || c === '\'') {
2984
                if (url.slice(-1) !== c) {
2985
                    warning("Bad url string.");
2986
                } else {
2987
                    url = url.slice(1, -1);
2988
                    if (url.indexOf(c) >= 0) {
2989
                        warning("Bad url string.");
2990
                    }
2991
                }
2992
            }
2993
            if (!url) {
2994
                warning("Missing url.");
2995
            }
2996
            advance();
2997
            if (option.safe && ux.test(url)) {
2998
                error("ADsafe URL violation.");
2999
            }
3000
            urls.push(url);
3001
            return true;
3002
        }
3003
        return false;
3004
    }
3005
3006
    cssAny = [cssUrl, function () {
3007
        for (;;) {
3008
            if (nexttoken.identifier) {
3009
                switch (nexttoken.value.toLowerCase()) {
3010
                case 'url':
3011
                    cssUrl();
3012
                    break;
3013
                case 'expression':
3014
                    warning("Unexpected expression '{a}'.",
3015
                        nexttoken, nexttoken.value);
3016
                    advance();
3017
                    break;
3018
                default:
3019
                    advance();
3020
                }
3021
            } else {
3022
                if (nexttoken.id === ';' || nexttoken.id === '!'  ||
3023
                        nexttoken.id === '(end)' || nexttoken.id === '}') {
3024
                    return true;
3025
                }
3026
                advance();
3027
            }
3028
        }
3029
    }];
3030
3031
    cssBorderStyle = [
3032
        'none', 'hidden', 'dotted', 'dashed', 'solid', 'double', 'ridge',
3033
        'inset', 'outset'
3034
    ];
3035
3036
    cssBreak = [
3037
        'auto', 'always', 'avoid', 'left', 'right'
3038
    ];
3039
3040
    cssOverflow = [
3041
        'auto', 'hidden', 'scroll', 'visible'
3042
    ];
3043
3044
    cssAttributeData = {
3045
        background: [
3046
            true, 'background-attachment', 'background-color',
3047
            'background-image', 'background-position', 'background-repeat'
3048
        ],
3049
        'background-attachment': ['scroll', 'fixed'],
3050
        'background-color': ['transparent', cssColor],
3051
        'background-image': ['none', cssUrl],
3052
        'background-position': [
3053
            2, [cssLength, 'top', 'bottom', 'left', 'right', 'center']
3054
        ],
3055
        'background-repeat': [
3056
            'repeat', 'repeat-x', 'repeat-y', 'no-repeat'
3057
        ],
3058
        'border': [true, 'border-color', 'border-style', 'border-width'],
3059
        'border-bottom': [
3060
            true, 'border-bottom-color', 'border-bottom-style',
3061
            'border-bottom-width'
3062
        ],
3063
        'border-bottom-color': cssColor,
3064
        'border-bottom-style': cssBorderStyle,
3065
        'border-bottom-width': cssWidth,
3066
        'border-collapse': ['collapse', 'separate'],
3067
        'border-color': ['transparent', 4, cssColor],
3068
        'border-left': [
3069
            true, 'border-left-color', 'border-left-style', 'border-left-width'
3070
        ],
3071
        'border-left-color': cssColor,
3072
        'border-left-style': cssBorderStyle,
3073
        'border-left-width': cssWidth,
3074
        'border-right': [
3075
            true, 'border-right-color', 'border-right-style',
3076
            'border-right-width'
3077
        ],
3078
        'border-right-color': cssColor,
3079
        'border-right-style': cssBorderStyle,
3080
        'border-right-width': cssWidth,
3081
        'border-spacing': [2, cssLength],
3082
        'border-style': [4, cssBorderStyle],
3083
        'border-top': [
3084
            true, 'border-top-color', 'border-top-style', 'border-top-width'
3085
        ],
3086
        'border-top-color': cssColor,
3087
        'border-top-style': cssBorderStyle,
3088
        'border-top-width': cssWidth,
3089
        'border-width': [4, cssWidth],
3090
        bottom: [cssLength, 'auto'],
3091
        'caption-side' : ['bottom', 'left', 'right', 'top'],
3092
        clear: ['both', 'left', 'none', 'right'],
3093
        clip: [cssShape, 'auto'],
3094
        color: cssColor,
3095
        content: [
3096
            'open-quote', 'close-quote', 'no-open-quote', 'no-close-quote',
3097
            cssString, cssUrl, cssCounter, cssAttr
3098
        ],
3099
        'counter-increment': [
3100
            cssName, 'none'
3101
        ],
3102
        'counter-reset': [
3103
            cssName, 'none'
3104
        ],
3105
        cursor: [
3106
            cssUrl, 'auto', 'crosshair', 'default', 'e-resize', 'help', 'move',
3107
            'n-resize', 'ne-resize', 'nw-resize', 'pointer', 's-resize',
3108
            'se-resize', 'sw-resize', 'w-resize', 'text', 'wait'
3109
        ],
3110
        direction: ['ltr', 'rtl'],
3111
        display: [
3112
            'block', 'compact', 'inline', 'inline-block', 'inline-table',
3113
            'list-item', 'marker', 'none', 'run-in', 'table', 'table-caption',
3114
            'table-cell', 'table-column', 'table-column-group',
3115
            'table-footer-group', 'table-header-group', 'table-row',
3116
            'table-row-group'
3117
        ],
3118
        'empty-cells': ['show', 'hide'],
3119
        'float': ['left', 'none', 'right'],
3120
        font: [
3121
            'caption', 'icon', 'menu', 'message-box', 'small-caption',
3122
            'status-bar', true, 'font-size', 'font-style', 'font-weight',
3123
            'font-family'
3124
        ],
3125
        'font-family': cssCommaList,
3126
        'font-size': [
3127
            'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large',
3128
            'xx-large', 'larger', 'smaller', cssLength
3129
        ],
3130
        'font-size-adjust': ['none', cssNumber],
3131
        'font-stretch': [
3132
            'normal', 'wider', 'narrower', 'ultra-condensed',
3133
            'extra-condensed', 'condensed', 'semi-condensed',
3134
            'semi-expanded', 'expanded', 'extra-expanded'
3135
        ],
3136
        'font-style': [
3137
            'normal', 'italic', 'oblique'
3138
        ],
3139
        'font-variant': [
3140
            'normal', 'small-caps'
3141
        ],
3142
        'font-weight': [
3143
            'normal', 'bold', 'bolder', 'lighter', cssNumber
3144
        ],
3145
        height: [cssLength, 'auto'],
3146
        left: [cssLength, 'auto'],
3147
        'letter-spacing': ['normal', cssLength],
3148
        'line-height': ['normal', cssLineHeight],
3149
        'list-style': [
3150
            true, 'list-style-image', 'list-style-position', 'list-style-type'
3151
        ],
3152
        'list-style-image': ['none', cssUrl],
3153
        'list-style-position': ['inside', 'outside'],
3154
        'list-style-type': [
3155
            'circle', 'disc', 'square', 'decimal', 'decimal-leading-zero',
3156
            'lower-roman', 'upper-roman', 'lower-greek', 'lower-alpha',
3157
            'lower-latin', 'upper-alpha', 'upper-latin', 'hebrew', 'katakana',
3158
            'hiragana-iroha', 'katakana-oroha', 'none'
3159
        ],
3160
        margin: [4, cssMargin],
3161
        'margin-bottom': cssMargin,
3162
        'margin-left': cssMargin,
3163
        'margin-right': cssMargin,
3164
        'margin-top': cssMargin,
3165
        'marker-offset': [cssLength, 'auto'],
3166
        'max-height': [cssLength, 'none'],
3167
        'max-width': [cssLength, 'none'],
3168
        'min-height': cssLength,
3169
        'min-width': cssLength,
3170
        opacity: cssNumber,
3171
        outline: [true, 'outline-color', 'outline-style', 'outline-width'],
3172
        'outline-color': ['invert', cssColor],
3173
        'outline-style': [
3174
            'dashed', 'dotted', 'double', 'groove', 'inset', 'none',
3175
            'outset', 'ridge', 'solid'
3176
        ],
3177
        'outline-width': cssWidth,
3178
        overflow: cssOverflow,
3179
        'overflow-x': cssOverflow,
3180
        'overflow-y': cssOverflow,
3181
        padding: [4, cssLength],
3182
        'padding-bottom': cssLength,
3183
        'padding-left': cssLength,
3184
        'padding-right': cssLength,
3185
        'padding-top': cssLength,
3186
        'page-break-after': cssBreak,
3187
        'page-break-before': cssBreak,
3188
        position: ['absolute', 'fixed', 'relative', 'static'],
3189
        quotes: [8, cssString],
3190
        right: [cssLength, 'auto'],
3191
        'table-layout': ['auto', 'fixed'],
3192
        'text-align': ['center', 'justify', 'left', 'right'],
3193
        'text-decoration': [
3194
            'none', 'underline', 'overline', 'line-through', 'blink'
3195
        ],
3196
        'text-indent': cssLength,
3197
        'text-shadow': ['none', 4, [cssColor, cssLength]],
3198
        'text-transform': ['capitalize', 'uppercase', 'lowercase', 'none'],
3199
        top: [cssLength, 'auto'],
3200
        'unicode-bidi': ['normal', 'embed', 'bidi-override'],
3201
        'vertical-align': [
3202
            'baseline', 'bottom', 'sub', 'super', 'top', 'text-top', 'middle',
3203
            'text-bottom', cssLength
3204
        ],
3205
        visibility: ['visible', 'hidden', 'collapse'],
3206
        'white-space': [
3207
            'normal', 'nowrap', 'pre', 'pre-line', 'pre-wrap', 'inherit'
3208
        ],
3209
        width: [cssLength, 'auto'],
3210
        'word-spacing': ['normal', cssLength],
3211
        'word-wrap': ['break-word', 'normal'],
3212
        'z-index': ['auto', cssNumber]
3213
    };
3214
3215
    function styleAttribute() {
3216
        var v;
3217
        while (nexttoken.id === '*' || nexttoken.id === '#' ||
3218
                nexttoken.value === '_') {
3219
            if (!option.css) {
3220
                warning("Unexpected '{a}'.", nexttoken, nexttoken.value);
3221
            }
3222
            advance();
3223
        }
3224
        if (nexttoken.id === '-') {
3225
            if (!option.css) {
3226
                warning("Unexpected '{a}'.", nexttoken, nexttoken.value);
3227
            }
3228
            advance('-');
3229
            if (!nexttoken.identifier) {
3230
                warning(
3231
"Expected a non-standard style attribute and instead saw '{a}'.",
3232
                    nexttoken, nexttoken.value);
3233
            }
3234
            advance();
3235
            return cssAny;
3236
        } else {
3237
            if (!nexttoken.identifier) {
3238
                warning("Excepted a style attribute, and instead saw '{a}'.",
3239
                    nexttoken, nexttoken.value);
3240
            } else {
3241
                if (is_own(cssAttributeData, nexttoken.value)) {
3242
                    v = cssAttributeData[nexttoken.value];
3243
                } else {
3244
                    v = cssAny;
3245
                    if (!option.css) {
3246
                        warning("Unrecognized style attribute '{a}'.",
3247
                                nexttoken, nexttoken.value);
3248
                    }
3249
                }
3250
            }
3251
            advance();
3252
            return v;
3253
        }
3254
    }
3255
3256
    function styleValue(v) {
3257
        var i = 0,
3258
            n,
3259
            once,
3260
            match,
3261
            round,
3262
            start = 0,
3263
            vi;
3264
        switch (typeof v) {
3265
        case 'function':
3266
            return v();
3267
        case 'string':
3268
            if (nexttoken.identifier && nexttoken.value === v) {
3269
                advance();
3270
                return true;
3271
            }
3272
            return false;
3273
        }
3274
        for (;;) {
3275
            if (i >= v.length) {
3276
                return false;
3277
            }
3278
            vi = v[i];
3279
            i += 1;
3280
            if (vi === true) {
3281
                break;
3282
            } else if (typeof vi === 'number') {
3283
                n = vi;
3284
                vi = v[i];
3285
                i += 1;
3286
            } else {
3287
                n = 1;
3288
            }
3289
            match = false;
3290
            while (n > 0) {
3291
                if (styleValue(vi)) {
3292
                    match = true;
3293
                    n -= 1;
3294
                } else {
3295
                    break;
3296
                }
3297
            }
3298
            if (match) {
3299
                return true;
3300
            }
3301
        }
3302
        start = i;
3303
        once = [];
3304
        for (;;) {
3305
            round = false;
3306
            for (i = start; i < v.length; i += 1) {
3307
                if (!once[i]) {
3308
                    if (styleValue(cssAttributeData[v[i]])) {
3309
                        match = true;
3310
                        round = true;
3311
                        once[i] = true;
3312
                        break;
3313
                    }
3314
                }
3315
            }
3316
            if (!round) {
3317
                return match;
3318
            }
3319
        }
3320
    }
3321
3322
    function styleChild() {
3323
        if (nexttoken.id === '(number)') {
3324
            advance();
3325
            if (nexttoken.value === 'n' && nexttoken.identifier) {
3326
                adjacent();
3327
                advance();
3328
                if (nexttoken.id === '+') {
3329
                    adjacent();
3330
                    advance('+');
3331
                    adjacent();
3332
                    advance('(number)');
3333
                }
3334
            }
3335
            return;
3336
        } else {
3337
            switch (nexttoken.value) {
3338
            case 'odd':
3339
            case 'even':
3340
                if (nexttoken.identifier) {
3341
                    advance();
3342
                    return;
3343
                }
3344
            }
3345
        }
3346
        warning("Unexpected token '{a}'.", nexttoken, nexttoken.value);
3347
    }
3348
3349
    function substyle() {
3350
        var v;
3351
        for (;;) {
3352
            if (nexttoken.id === '}' || nexttoken.id === '(end)' ||
3353
                    xquote && nexttoken.id === xquote) {
3354
                return;
3355
            }
3356
            while (nexttoken.id === ';') {
3357
                warning("Misplaced ';'.");
3358
                advance(';');
3359
            }
3360
            v = styleAttribute();
3361
            advance(':');
3362
            if (nexttoken.identifier && nexttoken.value === 'inherit') {
3363
                advance();
3364
            } else {
3365
                if (!styleValue(v)) {
3366
                    warning("Unexpected token '{a}'.", nexttoken,
3367
                        nexttoken.value);
3368
                    advance();
3369
                }
3370
            }
3371
            if (nexttoken.id === '!') {
3372
                advance('!');
3373
                adjacent();
3374
                if (nexttoken.identifier && nexttoken.value === 'important') {
3375
                    advance();
3376
                } else {
3377
                    warning("Expected '{a}' and instead saw '{b}'.",
3378
                        nexttoken, 'important', nexttoken.value);
3379
                }
3380
            }
3381
            if (nexttoken.id === '}' || nexttoken.id === xquote) {
3382
// Trailing ';' is optional if not disallowed - see http://www.w3.org/TR/css-style-attr/#syntax
3383
//                warning("Missing '{a}'.", nexttoken, ';');
3384
            } else {
3385
                advance(';');
3386
            }
3387
        }
3388
    }
3389
3390
    function styleSelector() {
3391
        if (nexttoken.identifier) {
3392
            if (!is_own(htmltag, nexttoken.value)) {
3393
                warning("Expected a tagName, and instead saw {a}.",
3394
                    nexttoken, nexttoken.value);
3395
            }
3396
            advance();
3397
        } else {
3398
            switch (nexttoken.id) {
3399
            case '>':
3400
            case '+':
3401
                advance();
3402
                styleSelector();
3403
                break;
3404
            case ':':
3405
                advance(':');
3406
                switch (nexttoken.value) {
3407
                case 'active':
3408
                case 'after':
3409
                case 'before':
3410
                case 'checked':
3411
                case 'disabled':
3412
                case 'empty':
3413
                case 'enabled':
3414
                case 'first-child':
3415
                case 'first-letter':
3416
                case 'first-line':
3417
                case 'first-of-type':
3418
                case 'focus':
3419
                case 'hover':
3420
                case 'last-of-type':
3421
                case 'link':
3422
                case 'only-of-type':
3423
                case 'root':
3424
                case 'target':
3425
                case 'visited':
3426
                    advance();
3427
                    break;
3428
                case 'lang':
3429
                    advance();
3430
                    advance('(');
3431
                    if (!nexttoken.identifier) {
3432
                        warning("Expected a lang code, and instead saw :{a}.",
3433
                            nexttoken, nexttoken.value);
3434
                    }
3435
                    advance(')');
3436
                    break;
3437
                case 'nth-child':
3438
                case 'nth-last-child':
3439
                case 'nth-last-of-type':
3440
                case 'nth-of-type':
3441
                    advance();
3442
                    advance('(');
3443
                    styleChild();
3444
                    advance(')');
3445
                    break;
3446
                case 'not':
3447
                    advance();
3448
                    advance('(');
3449
                    if (nexttoken.id === ':' && peek(0).value === 'not') {
3450
                        warning("Nested not.");
3451
                    }
3452
                    styleSelector();
3453
                    advance(')');
3454
                    break;
3455
                default:
3456
                    warning("Expected a pseudo, and instead saw :{a}.",
3457
                        nexttoken, nexttoken.value);
3458
                }
3459
                break;
3460
            case '#':
3461
                advance('#');
3462
                if (!nexttoken.identifier) {
3463
                    warning("Expected an id, and instead saw #{a}.",
3464
                        nexttoken, nexttoken.value);
3465
                }
3466
                advance();
3467
                break;
3468
            case '*':
3469
                advance('*');
3470
                break;
3471
            case '.':
3472
                advance('.');
3473
                if (!nexttoken.identifier) {
3474
                    warning("Expected a class, and instead saw #.{a}.",
3475
                        nexttoken, nexttoken.value);
3476
                }
3477
                advance();
3478
                break;
3479
            case '[':
3480
                advance('[');
3481
                if (!nexttoken.identifier) {
3482
                    warning("Expected an attribute, and instead saw [{a}].",
3483
                        nexttoken, nexttoken.value);
3484
                }
3485
                advance();
3486
                if (nexttoken.id === '=' || nexttoken.value === '~=' ||
3487
                        nexttoken.value === '$=' ||
3488
                        nexttoken.value === '|=' ||
3489
                        nexttoken.id === '*=' ||
3490
                        nexttoken.id === '^=') {
3491
                    advance();
3492
                    if (nexttoken.type !== '(string)') {
3493
                        warning("Expected a string, and instead saw {a}.",
3494
                            nexttoken, nexttoken.value);
3495
                    }
3496
                    advance();
3497
                }
3498
                advance(']');
3499
                break;
3500
            default:
3501
                error("Expected a CSS selector, and instead saw {a}.",
3502
                    nexttoken, nexttoken.value);
3503
            }
3504
        }
3505
    }
3506
3507
    function stylePattern() {
3508
        var name;
3509
        if (nexttoken.id === '{') {
3510
            warning("Expected a style pattern, and instead saw '{a}'.", nexttoken,
3511
                nexttoken.id);
3512
        } else if (nexttoken.id === '@') {
3513
            advance('@');
3514
            name = nexttoken.value;
3515
            if (nexttoken.identifier && atrule[name] === true) {
3516
                advance();
3517
                return name;
3518
            }
3519
            warning("Expected an at-rule, and instead saw @{a}.", nexttoken, name);
3520
        }
3521
        for (;;) {
3522
            styleSelector();
3523
            if (nexttoken.id === '</' || nexttoken.id === '{' ||
3524
                    nexttoken.id === '(end)') {
3525
                return '';
3526
            }
3527
            if (nexttoken.id === ',') {
3528
                comma();
3529
            }
3530
        }
3531
    }
3532
3533
    function styles() {
3534
        var i;
3535
        while (nexttoken.id === '@') {
3536
            i = peek();
3537
            if (i.identifier && i.value === 'import') {
3538
                advance('@');
3539
                advance();
3540
                if (!cssUrl()) {
3541
                    warning("Expected '{a}' and instead saw '{b}'.", nexttoken,
3542
                        'url', nexttoken.value);
3543
                    advance();
3544
                }
3545
                advance(';');
3546
            } else {
3547
                break;
3548
            }
3549
        }
3550
        while (nexttoken.id !== '</' && nexttoken.id !== '(end)') {
3551
            stylePattern();
3552
            xmode = 'styleproperty';
3553
            if (nexttoken.id === ';') {
3554
                advance(';');
3555
            } else {
3556
                advance('{');
3557
                substyle();
3558
                xmode = 'style';
3559
                advance('}');
3560
            }
3561
        }
3562
    }
3563
3564
3565
// HTML parsing.
3566
3567
    function doBegin(n) {
3568
        if (n !== 'html' && !option.fragment) {
3569
            if (n === 'div' && option.adsafe) {
3570
                error("ADSAFE: Use the fragment option.");
3571
            } else {
3572
                error("Expected '{a}' and instead saw '{b}'.",
3573
                    token, 'html', n);
3574
            }
3575
        }
3576
        if (option.adsafe) {
3577
            if (n === 'html') {
3578
                error(
3579
"Currently, ADsafe does not operate on whole HTML documents. It operates on <div> fragments and .js files.", token);
3580
            }
3581
            if (option.fragment) {
3582
                if (n !== 'div') {
3583
                    error("ADsafe violation: Wrap the widget in a div.", token);
3584
                }
3585
            } else {
3586
                error("Use the fragment option.", token);
3587
            }
3588
        }
3589
        option.browser = true;
3590
        assume();
3591
    }
3592
3593
    function doAttribute(n, a, v) {
3594
        var u, x;
3595
        if (a === 'id') {
3596
            u = typeof v === 'string' ? v.toUpperCase() : '';
3597
            if (ids[u] === true) {
3598
                warning("Duplicate id='{a}'.", nexttoken, v);
3599
            }
3600
            // No random syntax in ids
3601
            /*if (!/^[A-Za-z][A-Za-z0-9._:\-]*$/.test(v)) {
3602
                warning("Bad id: '{a}'.", nexttoken, v);
3603
            } else*/ if (option.adsafe) {
3604
                if (adsafe_id) {
3605
                    if (v.slice(0, adsafe_id.length) !== adsafe_id) {
3606
                        warning("ADsafe violation: An id must have a '{a}' prefix",
3607
                                nexttoken, adsafe_id);
3608
                    } else if (!/^[A-Z]+_[A-Z]+$/.test(v)) {
3609
                        warning("ADSAFE violation: bad id.");
3610
                    }
3611
                } else {
3612
                    adsafe_id = v;
3613
                    if (!/^[A-Z]+_$/.test(v)) {
3614
                        warning("ADSAFE violation: bad id.");
3615
                    }
3616
                }
3617
            }
3618
            x = v.search(dx);
3619
            if (x >= 0) {
3620
                warning("Unexpected character '{a}' in {b}.", token, v.charAt(x), a);
3621
            }
3622
            ids[u] = true;
3623
        } else if (/*a === 'class' || */a === 'type' || a === 'name') { // class' content is cdata
3624
            x = v.search(qx);
3625
            if (x >= 0) {
3626
                warning("Unexpected character '{a}' in {b}.", token, v.charAt(x), a);
3627
            }
3628
            ids[u] = true;
3629
        } else if (a === 'href' || a === 'background' ||
3630
                a === 'content' || a === 'data' ||
3631
                a.indexOf('src') >= 0 || a.indexOf('url') >= 0) {
3632
            if (option.safe && ux.test(v)) {
3633
                error("ADsafe URL violation.");
3634
            }
3635
            urls.push(v);
3636
        } else if (a === 'for') {
3637
            if (option.adsafe) {
3638
                if (adsafe_id) {
3639
                    if (v.slice(0, adsafe_id.length) !== adsafe_id) {
3640
                        warning("ADsafe violation: An id must have a '{a}' prefix",
3641
                                nexttoken, adsafe_id);
3642
                    } else if (!/^[A-Z]+_[A-Z]+$/.test(v)) {
3643
                        warning("ADSAFE violation: bad id.");
3644
                    }
3645
                } else {
3646
                    warning("ADSAFE violation: bad id.");
3647
                }
3648
            }
3649
        } else if (a === 'name') {
3650
            if (option.adsafe && v.indexOf('_') >= 0) {
3651
                warning("ADsafe name violation.");
3652
            }
3653
        }
3654
    }
3655
3656
    function doTag(n, a) {
3657
        var i, t = htmltag[n], x;
3658
        src = false;
3659
        if (!t) {
3660
            error("Unrecognized tag '<{a}>'.",
3661
                    nexttoken,
3662
                    n === n.toLowerCase() ? n :
3663
                        n + ' (capitalization error)');
3664
        }
3665
        if (stack.length > 0) {
3666
            if (n === 'html') {
3667
                error("Too many <html> tags.", token);
3668
            }
3669
            x = t.parent;
3670
            if (x) {
3671
                if (x.indexOf(' ' + stack[stack.length - 1].name + ' ') < 0) {
3672
                    error("A '<{a}>' must be within '<{b}>'.",
3673
                            token, n, x);
3674
                }
3675
            } else if (!option.adsafe && !option.fragment) {
3676
                i = stack.length;
3677
                do {
3678
                    if (i <= 0) {
3679
                        error("A '<{a}>' must be within '<{b}>'.",
3680
                                token, n, 'body');
3681
                    }
3682
                    i -= 1;
3683
                } while (stack[i].name !== 'body');
3684
            }
3685
        }
3686
        switch (n) {
3687
        case 'div':
3688
            if (option.adsafe && stack.length === 1 && !adsafe_id) {
3689
                warning("ADSAFE violation: missing ID_.");
3690
            }
3691
            break;
3692
        case 'script':
3693
            xmode = 'script';
3694
            advance('>');
3695
            indent = nexttoken.from;
3696
            if (a.lang) {
3697
                warning("lang is deprecated.", token);
3698
            }
3699
            if (option.adsafe && stack.length !== 1) {
3700
                warning("ADsafe script placement violation.", token);
3701
            }
3702
            if (a.src) {
3703
                if (option.adsafe && (!adsafe_may || !approved[a.src])) {
3704
                    warning("ADsafe unapproved script source.", token);
3705
                }
3706
                /*if (a.type) {
3707
                    warning("type is unnecessary.", token);
3708
                }*/
3709
            } else {
3710
3711
                if (a.type && a.type !== 'text/javascript') {
3712
                    lex.skip_till('</script>');
3713
                    advance();
3714
                } else {
3715
                    if (adsafe_went) {
3716
                        error("ADsafe script violation.", token);
3717
                    }
3718
                    statements('script');
3719
                }
3720
            }
3721
            xmode = 'html';
3722
            advance('</');
3723
            if (!nexttoken.identifier && nexttoken.value !== 'script') {
3724
                warning("Expected '{a}' and instead saw '{b}'.",
3725
                        nexttoken, 'script', nexttoken.value);
3726
            }
3727
            advance();
3728
            xmode = 'outer';
3729
            break;
3730
        case 'style':
3731
            xmode = 'style';
3732
            advance('>');
3733
            styles();
3734
            xmode = 'html';
3735
            advance('</');
3736
            if (!nexttoken.identifier && nexttoken.value !== 'style') {
3737
                warning("Expected '{a}' and instead saw '{b}'.",
3738
                        nexttoken, 'style', nexttoken.value);
3739
            }
3740
            advance();
3741
            xmode = 'outer';
3742
            break;
3743
        case 'input':
3744
            switch (a.type) {
3745
            case 'radio':
3746
            case 'checkbox':
3747
            case 'button':
3748
            case 'reset':
3749
            case 'submit':
3750
                break;
3751
            case 'text':
3752
            case 'file':
3753
            case 'password':
3754
            case 'file':
3755
            case 'hidden':
3756
            case 'image':
3757
                if (option.adsafe && a.autocomplete !== 'off') {
3758
                    warning("ADsafe autocomplete violation.");
3759
                }
3760
                break;
3761
            default:
3762
                warning("Bad input type.");
3763
            }
3764
            break;
3765
        case 'applet':
3766
        case 'body':
3767
        case 'embed':
3768
        case 'frame':
3769
        case 'frameset':
3770
        case 'head':
3771
        case 'iframe':
3772
        case 'noembed':
3773
        case 'noframes':
3774
        case 'object':
3775
        case 'param':
3776
            if (option.adsafe) {
3777
                warning("ADsafe violation: Disallowed tag: " + n);
3778
            }
3779
            break;
3780
        }
3781
    }
3782
3783
3784
    function closetag(n) {
3785
        return '</' + n + '>';
3786
    }
3787
3788
    function html() {
3789
        var a, attributes, e, n, q, t, v, w = option.white, wmode;
3790
        xmode = 'html';
3791
        xquote = '';
3792
        stack = null;
3793
        for (;;) {
3794
            switch (nexttoken.value) {
3795
            case '<':
3796
                xmode = 'html';
3797
                advance('<');
3798
                attributes = {};
3799
                t = nexttoken;
3800
                if (!t.identifier) {
3801
                    warning("Bad identifier {a}.", t, t.value);
3802
                }
3803
                n = t.value;
3804
                if (option.cap) {
3805
                    n = n.toLowerCase();
3806
                }
3807
                t.name = n;
3808
                advance();
3809
                if (!stack) {
3810
                    stack = [];
3811
                    doBegin(n);
3812
                }
3813
                v = htmltag[n];
3814
                if (typeof v !== 'object') {
3815
                    error("Unrecognized tag '<{a}>'.", t, n);
3816
                }
3817
                e = v.empty;
3818
                t.type = n;
3819
                for (;;) {
3820
                    if (nexttoken.id === '/') {
3821
                        advance('/');
3822
                        if (nexttoken.id !== '>') {
3823
                            warning("Expected '{a}' and instead saw '{b}'.",
3824
                                    nexttoken, '>', nexttoken.value);
3825
                        }
3826
                        break;
3827
                    }
3828
                    if (nexttoken.id && nexttoken.id.substr(0, 1) === '>') {
3829
                        break;
3830
                    }
3831
                    if (!nexttoken.identifier) {
3832
                        if (nexttoken.id === '(end)' || nexttoken.id === '(error)') {
3833
                            error("Missing '>'.", nexttoken);
3834
                        }
3835
                        warning("Bad identifier.");
3836
                    }
3837
// Don't try to enable white if we said no
3838
//                    option.white = true;
3839
                    nonadjacent(token, nexttoken);
3840
                    a = nexttoken.value;
3841
//                    option.white = w;
3842
                    advance();
3843
                    if (!option.cap && a !== a.toLowerCase()) {
3844
                        warning("Attribute '{a}' not all lower case.", nexttoken, a);
3845
                    }
3846
                    a = a.toLowerCase();
3847
                    xquote = '';
3848
                    if (is_own(attributes, a)) {
3849
                        warning("Attribute '{a}' repeated.", nexttoken, a);
3850
                    }
3851
                    if (a.slice(0, 2) === 'on') {
3852
                        if (!option.on) {
3853
                            warning("Avoid HTML event handlers.");
3854
                        }
3855
                        xmode = 'scriptstring';
3856
                        advance('=');
3857
                        q = nexttoken.id;
3858
                        if (q !== '"' && q !== "'") {
3859
                            error("Missing quote.");
3860
                        }
3861
                        xquote = q;
3862
                        wmode = option.white;
3863
                        option.white = false;
3864
                        advance(q);
3865
                        statements('on');
3866
                        option.white = wmode;
3867
                        if (nexttoken.id !== q) {
3868
                            error("Missing close quote on script attribute.");
3869
                        }
3870
                        xmode = 'html';
3871
                        xquote = '';
3872
                        advance(q);
3873
                        v = false;
3874
                    } else if (a === 'style') {
3875
                        xmode = 'scriptstring';
3876
                        advance('=');
3877
                        q = nexttoken.id;
3878
                        if (q !== '"' && q !== "'") {
3879
                            error("Missing quote.");
3880
                        }
3881
                        xmode = 'styleproperty';
3882
                        xquote = q;
3883
                        advance(q);
3884
                        substyle();
3885
                        xmode = 'html';
3886
                        xquote = '';
3887
                        advance(q);
3888
                        v = false;
3889
                    } else {
3890
                        if (nexttoken.id === '=') {
3891
                            advance('=');
3892
                            v = nexttoken.value;
3893
                            if (!nexttoken.identifier &&
3894
                                    nexttoken.id !== '"' &&
3895
                                    nexttoken.id !== '\'' &&
3896
                                    nexttoken.type !== '(string)' &&
3897
                                    nexttoken.type !== '(number)' &&
3898
                                    nexttoken.type !== '(color)') {
3899
                                warning("Expected an attribute value and instead saw '{a}'.", token, a);
3900
                            }
3901
                            advance();
3902
                        } else {
3903
                            v = true;
3904
                        }
3905
                    }
3906
                    attributes[a] = v;
3907
                    doAttribute(n, a, v);
3908
                }
3909
                doTag(n, attributes);
3910
                if (!e) {
3911
                    stack.push(t);
3912
                }
3913
                xmode = 'outer';
3914
                advance('>');
3915
                break;
3916
            case '</':
3917
                xmode = 'html';
3918
                advance('</');
3919
                if (!nexttoken.identifier) {
3920
                    warning("Bad identifier.");
3921
                }
3922
                n = nexttoken.value;
3923
                if (option.cap) {
3924
                    n = n.toLowerCase();
3925
                }
3926
                advance();
3927
                if (!stack) {
3928
                    error("Unexpected '{a}'.", nexttoken, closetag(n));
3929
                }
3930
                t = stack.pop();
3931
                if (!t) {
3932
                    error("Unexpected '{a}'.", nexttoken, closetag(n));
3933
                }
3934
                if (t.name !== n) {
3935
                    error("Expected '{a}' and instead saw '{b}'.",
3936
                            nexttoken, closetag(t.name), closetag(n));
3937
                }
3938
                if (nexttoken.id !== '>') {
3939
                    error("Missing '{a}'.", nexttoken, '>');
3940
                }
3941
                xmode = 'outer';
3942
                advance('>');
3943
                break;
3944
            case '<!':
3945
                if (option.safe) {
3946
                    warning("ADsafe HTML violation.");
3947
                }
3948
                xmode = 'html';
3949
                for (;;) {
3950
                    advance();
3951
                    if (nexttoken.id === '>' || nexttoken.id === '(end)') {
3952
                        break;
3953
                    }
3954
                    if (nexttoken.value.indexOf('--') >= 0) {
3955
                        warning("Unexpected --.");
3956
                    }
3957
                    if (nexttoken.value.indexOf('<') >= 0) {
3958
                        warning("Unexpected <.");
3959
                    }
3960
                    if (nexttoken.value.indexOf('>') >= 0) {
3961
                        warning("Unexpected >.");
3962
                    }
3963
                }
3964
                xmode = 'outer';
3965
                advance('>');
3966
                break;
3967
            case '(end)':
3968
                return;
3969
            default:
3970
                if (nexttoken.id === '(end)') {
3971
                    error("Missing '{a}'.", nexttoken,
3972
                            '</' + stack[stack.length - 1].value + '>');
3973
                } else {
3974
                    advance();
3975
                }
3976
            }
3977
            if (stack && stack.length === 0 && (option.adsafe ||
3978
                    !option.fragment || nexttoken.id === '(end)')) {
3979
                break;
3980
            }
3981
        }
3982
        if (nexttoken.id !== '(end)') {
3983
            error("Unexpected material after the end.");
3984
        }
3985
    }
3986
3987
3988
// Build the syntax table by declaring the syntactic elements of the language.
3989
3990
    type('(number)', idValue);
3991
    type('(string)', idValue);
3992
3993
    syntax['(identifier)'] = {
3994
        type: '(identifier)',
3995
        lbp: 0,
3996
        identifier: true,
3997
        nud: function () {
3998
            var v = this.value,
3999
                s = scope[v],
4000
                f;
4001
            if (typeof s === 'function') {
4002
                s = undefined;
4003
            } else if (typeof s === 'boolean') {
4004
                f = funct;
4005
                funct = functions[0];
4006
                addlabel(v, 'var');
4007
                s = funct;
4008
                funct = f;
4009
            }
4010
4011
// The name is in scope and defined in the current function.
4012
4013
            if (funct === s) {
4014
4015
//      Change 'unused' to 'var', and reject labels.
4016
4017
                switch (funct[v]) {
4018
                case 'unused':
4019
                    funct[v] = 'var';
4020
                    break;
4021
                case 'label':
4022
                    warning("'{a}' is a statement label.", token, v);
4023
                    break;
4024
                }
4025
4026
// The name is not defined in the function.  If we are in the global scope,
4027
// then we have an undefined variable.
4028
4029
            } else if (funct['(global)']) {
4030
                if (option.undef && predefined[v] !== 'boolean') {
4031
                    warning("'{a}' is not defined.", token, v);
4032
                }
4033
                note_implied(token);
4034
4035
// If the name is already defined in the current
4036
// function, but not as outer, then there is a scope error.
4037
4038
            } else {
4039
                switch (funct[v]) {
4040
                case 'closure':
4041
                case 'function':
4042
                case 'var':
4043
                case 'unused':
4044
                    warning("'{a}' used out of scope.", token, v);
4045
                    break;
4046
                case 'label':
4047
                    warning("'{a}' is a statement label.", token, v);
4048
                    break;
4049
                case 'outer':
4050
                case 'global':
4051
                    break;
4052
                default:
4053
4054
// If the name is defined in an outer function, make an outer entry, and if
4055
// it was unused, make it var.
4056
4057
                    if (s === true) {
4058
                        funct[v] = true;
4059
                    } else if (s === null) {
4060
                        warning("'{a}' is not allowed.", token, v);
4061
                        note_implied(token);
4062
                    } else if (typeof s !== 'object') {
4063
                        if (option.undef) {
4064
                            warning("'{a}' is not defined.", token, v);
4065
                        } else {
4066
                            funct[v] = true;
4067
                        }
4068
                        note_implied(token);
4069
                    } else {
4070
                        switch (s[v]) {
4071
                        case 'function':
4072
                        case 'var':
4073
                        case 'unused':
4074
                            s[v] = 'closure';
4075
                            funct[v] = s['(global)'] ? 'global' : 'outer';
4076
                            break;
4077
                        case 'closure':
4078
                        case 'parameter':
4079
                            funct[v] = s['(global)'] ? 'global' : 'outer';
4080
                            break;
4081
                        case 'label':
4082
                            warning("'{a}' is a statement label.", token, v);
4083
                        }
4084
                    }
4085
                }
4086
            }
4087
            return this;
4088
        },
4089
        led: function () {
4090
            error("Expected an operator and instead saw '{a}'.",
4091
                    nexttoken, nexttoken.value);
4092
        }
4093
    };
4094
4095
    type('(regexp)', function () {
4096
        return this;
4097
    });
4098
4099
4100
// ECMAScript parser
4101
4102
    delim('(endline)');
4103
    delim('(begin)');
4104
    delim('(end)').reach = true;
4105
    delim('</').reach = true;
4106
    delim('<!');
4107
    delim('<!--');
4108
    delim('-->');
4109
    delim('(error)').reach = true;
4110
    delim('}').reach = true;
4111
    delim(')');
4112
    delim(']');
4113
    delim('"').reach = true;
4114
    delim("'").reach = true;
4115
    delim(';');
4116
    delim(':').reach = true;
4117
    delim(',');
4118
    delim('#');
4119
    delim('@');
4120
    reserve('else');
4121
    reserve('case').reach = true;
4122
    reserve('catch');
4123
    reserve('default').reach = true;
4124
    reserve('finally');
4125
    reservevar('arguments');
4126
    reservevar('eval');
4127
    reservevar('false');
4128
    reservevar('Infinity');
4129
    reservevar('NaN');
4130
    reservevar('null');
4131
    reservevar('this');
4132
    reservevar('true');
4133
    reservevar('undefined');
4134
    assignop('=', 'assign', 20);
4135
    assignop('+=', 'assignadd', 20);
4136
    assignop('-=', 'assignsub', 20);
4137
    assignop('*=', 'assignmult', 20);
4138
    assignop('/=', 'assigndiv', 20).nud = function () {
4139
        error("A regular expression literal can be confused with '/='.");
4140
    };
4141
    assignop('%=', 'assignmod', 20);
4142
    bitwiseassignop('&=', 'assignbitand', 20);
4143
    bitwiseassignop('|=', 'assignbitor', 20);
4144
    bitwiseassignop('^=', 'assignbitxor', 20);
4145
    bitwiseassignop('<<=', 'assignshiftleft', 20);
4146
    bitwiseassignop('>>=', 'assignshiftright', 20);
4147
    bitwiseassignop('>>>=', 'assignshiftrightunsigned', 20);
4148
    infix('?', function (left, that) {
4149
        that.left = left;
4150
        that.right = parse(10);
4151
        advance(':');
4152
        that['else'] = parse(10);
4153
        return that;
4154
    }, 30);
4155
4156
    infix('||', 'or', 40);
4157
    infix('&&', 'and', 50);
4158
    bitwise('|', 'bitor', 70);
4159
    bitwise('^', 'bitxor', 80);
4160
    bitwise('&', 'bitand', 90);
4161
    relation('==', function (left, right) {
4162
        if (option.eqeqeq) {
4163
            warning("Expected '{a}' and instead saw '{b}'.",
4164
                    this, '===', '==');
4165
        } else if (isPoorRelation(left)) {
4166
            warning("Use '{a}' to compare with '{b}'.",
4167
                this, '===', left.value);
4168
        } else if (isPoorRelation(right)) {
4169
            warning("Use '{a}' to compare with '{b}'.",
4170
                this, '===', right.value);
4171
        }
4172
        return this;
4173
    });
4174
    relation('===');
4175
    relation('!=', function (left, right) {
4176
        if (option.eqeqeq) {
4177
            warning("Expected '{a}' and instead saw '{b}'.",
4178
                    this, '!==', '!=');
4179
        } else if (isPoorRelation(left)) {
4180
            warning("Use '{a}' to compare with '{b}'.",
4181
                    this, '!==', left.value);
4182
        } else if (isPoorRelation(right)) {
4183
            warning("Use '{a}' to compare with '{b}'.",
4184
                    this, '!==', right.value);
4185
        }
4186
        return this;
4187
    });
4188
    relation('!==');
4189
    relation('<');
4190
    relation('>');
4191
    relation('<=');
4192
    relation('>=');
4193
    bitwise('<<', 'shiftleft', 120);
4194
    bitwise('>>', 'shiftright', 120);
4195
    bitwise('>>>', 'shiftrightunsigned', 120);
4196
    infix('in', 'in', 120);
4197
    infix('instanceof', 'instanceof', 120);
4198
    infix('+', function (left, that) {
4199
        var right = parse(130);
4200
        if (left && right && left.id === '(string)' && right.id === '(string)') {
4201
            left.value += right.value;
4202
            left.character = right.character;
4203
            if (jx.test(left.value)) {
4204
                warning("JavaScript URL.", left);
4205
            }
4206
            return left;
4207
        }
4208
        that.left = left;
4209
        that.right = right;
4210
        return that;
4211
    }, 130);
4212
    prefix('+', 'num');
4213
    prefix('+++', function () {
4214
        warning("Confusing pluses.");
4215
        this.right = parse(150);
4216
        this.arity = 'unary';
4217
        return this;
4218
    });
4219
    infix('+++', function (left) {
4220
        warning("Confusing pluses.");
4221
        this.left = left;
4222
        this.right = parse(130);
4223
        return this;
4224
    }, 130);
4225
    infix('-', 'sub', 130);
4226
    prefix('-', 'neg');
4227
    prefix('---', function () {
4228
        warning("Confusing minuses.");
4229
        this.right = parse(150);
4230
        this.arity = 'unary';
4231
        return this;
4232
    });
4233
    infix('---', function (left) {
4234
        warning("Confusing minuses.");
4235
        this.left = left;
4236
        this.right = parse(130);
4237
        return this;
4238
    }, 130);
4239
    infix('*', 'mult', 140);
4240
    infix('/', 'div', 140);
4241
    infix('%', 'mod', 140);
4242
4243
    suffix('++', 'postinc');
4244
    prefix('++', 'preinc');
4245
    syntax['++'].exps = true;
4246
4247
    suffix('--', 'postdec');
4248
    prefix('--', 'predec');
4249
    syntax['--'].exps = true;
4250
    prefix('delete', function () {
4251
        var p = parse(0);
4252
        if (!p || (p.id !== '.' && p.id !== '[')) {
4253
            warning("Expected '{a}' and instead saw '{b}'.",
4254
                    nexttoken, '.', nexttoken.value);
4255
        }
4256
        this.first = p;
4257
        return this;
4258
    }).exps = true;
4259
4260
4261
    prefix('~', function () {
4262
        if (option.bitwise) {
4263
            warning("Unexpected '{a}'.", this, '~');
4264
        }
4265
        parse(150);
4266
        return this;
4267
    });
4268
    prefix('!', function () {
4269
        this.right = parse(150);
4270
        this.arity = 'unary';
4271
        if (bang[this.right.id] === true) {
4272
            warning("Confusing use of '{a}'.", this, '!');
4273
        }
4274
        return this;
4275
    });
4276
    prefix('typeof', 'typeof');
4277
    prefix('new', function () {
4278
        var c = parse(155), i;
4279
        if (c && c.id !== 'function') {
4280
            if (c.identifier) {
4281
                c['new'] = true;
4282
                switch (c.value) {
4283
                case 'Object':
4284
                    warning("Use the object literal notation {}.", token);
4285
                    break;
4286
                case 'Array':
4287
                    if (nexttoken.id !== '(') {
4288
                        warning("Use the array literal notation [].", token);
4289
                    } else {
4290
                        advance('(');
4291
                        if (nexttoken.id === ')') {
4292
                            warning("Use the array literal notation [].", token);
4293
                        } else {
4294
                            i = parse(0);
4295
                            c.dimension = i;
4296
                            if ((i.id === '(number)' && /[.+\-Ee]/.test(i.value)) ||
4297
                                    (i.id === '-' && !i.right) ||
4298
                                    i.id === '(string)' || i.id === '[' ||
4299
                                    i.id === '{' || i.id === 'true' ||
4300
                                    i.id === 'false' ||
4301
                                    i.id === 'null' || i.id === 'undefined' ||
4302
                                    i.id === 'Infinity') {
4303
                                warning("Use the array literal notation [].", token);
4304
                            }
4305
                            if (nexttoken.id !== ')') {
4306
                                error("Use the array literal notation [].", token);
4307
                            }
4308
                        }
4309
                        advance(')');
4310
                    }
4311
                    this.first = c;
4312
                    return this;
4313
                case 'Number':
4314
                case 'String':
4315
                case 'Boolean':
4316
                case 'Math':
4317
                case 'JSON':
4318
                    warning("Do not use {a} as a constructor.", token, c.value);
4319
                    break;
4320
                case 'Function':
4321
                    if (!option.evil) {
4322
                        warning("The Function constructor is eval.");
4323
                    }
4324
                    break;
4325
                case 'Date':
4326
                case 'RegExp':
4327
                    break;
4328
                default:
4329
                    if (c.id !== 'function') {
4330
                        i = c.value.substr(0, 1);
4331
                        if (option.newcap && (i < 'A' || i > 'Z')) {
4332
                            warning(
4333
                    "A constructor name should start with an uppercase letter.",
4334
                                token);
4335
                        }
4336
                    }
4337
                }
4338
            } else {
4339
                if (c.id !== '.' && c.id !== '[' && c.id !== '(') {
4340
                    warning("Bad constructor.", token);
4341
                }
4342
            }
4343
        } else {
4344
            warning("Weird construction. Delete 'new'.", this);
4345
        }
4346
        adjacent(token, nexttoken);
4347
        if (nexttoken.id !== '(') {
4348
            warning("Missing '()' invoking a constructor.");
4349
        }
4350
        this.first = c;
4351
        return this;
4352
    });
4353
    syntax['new'].exps = true;
4354
4355
    infix('.', function (left, that) {
4356
        adjacent(prevtoken, token);
4357
        var m = identifier();
4358
        if (typeof m === 'string') {
4359
            countMember(m);
4360
        }
4361
        that.left = left;
4362
        that.right = m;
4363
        if (!option.evil && left && left.value === 'document' &&
4364
                (m === 'write' || m === 'writeln')) {
4365
            warning("document.write can be a form of eval.", left);
4366
        } else if (option.adsafe) {
4367
            if (left && left.value === 'ADSAFE') {
4368
                if (m === 'id' || m === 'lib') {
4369
                    warning("ADsafe violation.", that);
4370
                } else if (m === 'go') {
4371
                    if (xmode !== 'script') {
4372
                        warning("ADsafe violation.", that);
4373
                    } else if (adsafe_went || nexttoken.id !== '(' ||
4374
                            peek(0).id !== '(string)' ||
4375
                            peek(0).value !== adsafe_id ||
4376
                            peek(1).id !== ',') {
4377
                        error("ADsafe violation: go.", that);
4378
                    }
4379
                    adsafe_went = true;
4380
                    adsafe_may = false;
4381
                }
4382
            }
4383
        }
4384
        if (!option.evil && (m === 'eval' || m === 'execScript')) {
4385
            warning('eval is evil.');
4386
        } else if (option.safe) {
4387
            for (;;) {
4388
                if (banned[m] === true) {
4389
                    warning("ADsafe restricted word '{a}'.", token, m);
4390
                }
4391
                if (typeof predefined[left.value] !== 'boolean' ||
4392
                        nexttoken.id === '(') {
4393
                    break;
4394
                }
4395
                if (standard_member[m] === true) {
4396
                    if (nexttoken.id === '.') {
4397
                        warning("ADsafe violation.", that);
4398
                    }
4399
                    break;
4400
                }
4401
                if (nexttoken.id !== '.') {
4402
                    warning("ADsafe violation.", that);
4403
                    break;
4404
                }
4405
                advance('.');
4406
                token.left = that;
4407
                token.right = m;
4408
                that = token;
4409
                m = identifier();
4410
                if (typeof m === 'string') {
4411
                    countMember(m);
4412
                }
4413
            }
4414
        }
4415
        return that;
4416
    }, 160, true);
4417
4418
    infix('(', function (left, that) {
4419
        adjacent(prevtoken, token);
4420
        nospace();
4421
        var n = 0,
4422
            p = [];
4423
        if (left) {
4424
            if (left.type === '(identifier)') {
4425
                if (left.value.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)) {
4426
                    if (left.value !== 'Number' && left.value !== 'String' &&
4427
                            left.value !== 'Boolean' &&
4428
                            left.value !== 'Date') {
4429
                        if (left.value === 'Math') {
4430
                            warning("Math is not a function.", left);
4431
                        } else if (option.newcap) {
4432
                            warning(
4433
"Missing 'new' prefix when invoking a constructor.", left);
4434
                        }
4435
                    }
4436
                }
4437
            } else if (left.id === '.') {
4438
                if (option.safe && left.left.value === 'Math' &&
4439
                        left.right === 'random') {
4440
                    warning("ADsafe violation.", left);
4441
                }
4442
            }
4443
        }
4444
        if (nexttoken.id !== ')') {
4445
            for (;;) {
4446
                p[p.length] = parse(10);
4447
                n += 1;
4448
                if (nexttoken.id !== ',') {
4449
                    break;
4450
                }
4451
                comma();
4452
            }
4453
        }
4454
        advance(')');
4455
        if (option.immed && left.id === 'function' && nexttoken.id !== ')') {
4456
            warning("Wrap the entire immediate function invocation in parens.",
4457
                that);
4458
        }
4459
        nospace(prevtoken, token);
4460
        if (typeof left === 'object') {
4461
            if (left.value === 'parseInt' && n === 1) {
4462
                warning("Missing radix parameter.", left);
4463
            }
4464
            if (!option.evil) {
4465
                if (left.value === 'eval' || left.value === 'Function' ||
4466
                        left.value === 'execScript') {
4467
                    warning("eval is evil.", left);
4468
                } else if (p[0] && p[0].id === '(string)' &&
4469
                       (left.value === 'setTimeout' ||
4470
                        left.value === 'setInterval')) {
4471
                    warning(
4472
    "Implied eval is evil. Pass a function instead of a string.", left);
4473
                }
4474
            }
4475
            if (!left.identifier && left.id !== '.' && left.id !== '[' &&
4476
                    left.id !== '(' && left.id !== '&&' && left.id !== '||' &&
4477
                    left.id !== '?') {
4478
                warning("Bad invocation.", left);
4479
            }
4480
        }
4481
        that.left = left;
4482
        return that;
4483
    }, 155, true).exps = true;
4484
4485
    prefix('(', function () {
4486
        nospace();
4487
        var v = parse(0);
4488
        advance(')', this);
4489
        nospace(prevtoken, token);
4490
        if (option.immed && v.id === 'function') {
4491
            if (nexttoken.id === '(') {
4492
                warning(
4493
"Move the invocation into the parens that contain the function.", nexttoken);
4494
            } else {
4495
                warning(
4496
"Do not wrap function literals in parens unless they are to be immediately invoked.",
4497
                        this);
4498
            }
4499
        }
4500
        return v;
4501
    });
4502
4503
    infix('[', function (left, that) {
4504
        nospace();
4505
        var e = parse(0), s;
4506
        if (e && e.type === '(string)') {
4507
            if (option.safe && banned[e.value] === true) {
4508
                warning("ADsafe restricted word '{a}'.", that, e.value);
4509
            } else if (!option.evil &&
4510
                    (e.value === 'eval' || e.value === 'execScript')) {
4511
                warning("eval is evil.", that);
4512
            } else if (option.safe &&
4513
                    (e.value.charAt(0) === '_' || e.value.charAt(0) === '-')) {
4514
                warning("ADsafe restricted subscript '{a}'.", that, e.value);
4515
            }
4516
            countMember(e.value);
4517
            if (!option.sub && ix.test(e.value)) {
4518
                s = syntax[e.value];
4519
                if (!s || !s.reserved) {
4520
                    warning("['{a}'] is better written in dot notation.",
4521
                            e, e.value);
4522
                }
4523
            }
4524
        } else if (!e || e.type !== '(number)' || e.value < 0) {
4525
            if (option.safe) {
4526
                warning('ADsafe subscripting.');
4527
            }
4528
        }
4529
        advance(']', that);
4530
        nospace(prevtoken, token);
4531
        that.left = left;
4532
        that.right = e;
4533
        return that;
4534
    }, 160, true);
4535
4536
    prefix('[', function () {
4537
        var b = token.line !== nexttoken.line;
4538
        this.first = [];
4539
        if (b) {
4540
            indent += option.indent;
4541
            if (nexttoken.from === indent + option.indent) {
4542
                indent += option.indent;
4543
            }
4544
        }
4545
        while (nexttoken.id !== '(end)') {
4546
            while (nexttoken.id === ',') {
4547
                warning("Extra comma.");
4548
                advance(',');
4549
            }
4550
            if (nexttoken.id === ']') {
4551
                break;
4552
            }
4553
            if (b && token.line !== nexttoken.line) {
4554
                indentation();
4555
            }
4556
            this.first.push(parse(10));
4557
            if (nexttoken.id === ',') {
4558
                comma();
4559
                if (nexttoken.id === ']' && !option.es5) {
4560
                    warning("Extra comma.", token);
4561
                    break;
4562
                }
4563
            } else {
4564
                break;
4565
            }
4566
        }
4567
        if (b) {
4568
            indent -= option.indent;
4569
            indentation();
4570
        }
4571
        advance(']', this);
4572
        return this;
4573
    }, 160);
4574
4575
4576
    function property_name() {
4577
        var id = optionalidentifier(true);
4578
        if (!id) {
4579
            if (nexttoken.id === '(string)') {
4580
                id = nexttoken.value;
4581
                if (option.adsafe &&
4582
                        (id.charAt(0) === '_' ||
4583
                         id.charAt(id.length - 1) === '_')) {
4584
                    warning("Unexpected {a} in '{b}'.", token,
4585
                        "dangling '_'", id);
4586
                }
4587
                advance();
4588
            } else if (nexttoken.id === '(number)') {
4589
                id = nexttoken.value.toString();
4590
                advance();
4591
            }
4592
        }
4593
        return id;
4594
    }
4595
4596
4597
    function functionparams() {
4598
        var i, t = nexttoken, p = [];
4599
        advance('(');
4600
        nospace();
4601
        if (nexttoken.id === ')') {
4602
            advance(')');
4603
            nospace(prevtoken, token);
4604
            return;
4605
        }
4606
        for (;;) {
4607
            i = identifier();
4608
            p.push(i);
4609
            addlabel(i, 'parameter');
4610
            if (nexttoken.id === ',') {
4611
                comma();
4612
            } else {
4613
                advance(')', t);
4614
                nospace(prevtoken, token);
4615
                return p;
4616
            }
4617
        }
4618
    }
4619
4620
4621
    function doFunction(i) {
4622
        var f, s = scope;
4623
        scope = Object.create(s);
4624
        funct = {
4625
            '(name)'    : i || '"' + anonname + '"',
4626
            '(line)'    : nexttoken.line,
4627
            '(context)' : funct,
4628
            '(breakage)': 0,
4629
            '(loopage)' : 0,
4630
            '(scope)'   : scope
4631
        };
4632
        f = funct;
4633
        token.funct = funct;
4634
        functions.push(funct);
4635
        if (i) {
4636
            addlabel(i, 'function');
4637
        }
4638
        funct['(params)'] = functionparams();
4639
4640
        block(false);
4641
        scope = s;
4642
        funct['(last)'] = token.line;
4643
        funct = funct['(context)'];
4644
        return f;
4645
    }
4646
4647
4648
    (function (x) {
4649
        x.nud = function () {
4650
            var b, f, i, j, p, seen = {}, t;
4651
            b = token.line !== nexttoken.line;
4652
            if (b) {
4653
                indent += option.indent;
4654
                if (nexttoken.from === indent + option.indent) {
4655
                    indent += option.indent;
4656
                }
4657
            }
4658
            for (;;) {
4659
                if (nexttoken.id === '}') {
4660
                    break;
4661
                }
4662
                if (b) {
4663
                    indentation();
4664
                }
4665
                if (nexttoken.value === 'get' && peek().id !== ':') {
4666
                    advance('get');
4667
                    if (!option.es5) {
4668
                        error("get/set are ES5 features.");
4669
                    }
4670
                    i = property_name();
4671
                    if (!i) {
4672
                        error("Missing property name.");
4673
                    }
4674
                    t = nexttoken;
4675
                    adjacent(token, nexttoken);
4676
                    f = doFunction(i);
4677
                    if (funct['(loopage)']) {
4678
                        warning("Don't make functions within a loop.", t);
4679
                    }
4680
                    p = f['(params)'];
4681
                    if (p) {
4682
                        warning("Unexpected parameter '{a}' in get {b} function.", t, p[0], i);
4683
                    }
4684
                    adjacent(token, nexttoken);
4685
                    advance(',');
4686
                    indentation();
4687
                    advance('set');
4688
                    j = property_name();
4689
                    if (i !== j) {
4690
                        error("Expected {a} and instead saw {b}.", token, i, j);
4691
                    }
4692
                    t = nexttoken;
4693
                    adjacent(token, nexttoken);
4694
                    f = doFunction(i);
4695
                    p = f['(params)'];
4696
                    if (!p || p.length !== 1 || p[0] !== 'value') {
4697
                        warning("Expected (value) in set {a} function.", t, i);
4698
                    }
4699
                } else {
4700
                    i = property_name();
4701
                    if (typeof i !== 'string') {
4702
                        break;
4703
                    }
4704
                    advance(':');
4705
                    nonadjacent(token, nexttoken);
4706
                    parse(10);
4707
                }
4708
                if (seen[i] === true) {
4709
                    warning("Duplicate member '{a}'.", nexttoken, i);
4710
                }
4711
                seen[i] = true;
4712
                countMember(i);
4713
                if (nexttoken.id === ',') {
4714
                    comma();
4715
                    if (nexttoken.id === ',') {
4716
                        warning("Extra comma.", token);
4717
                    } else if (nexttoken.id === '}' && !option.es5) {
4718
                        warning("Extra comma.", token);
4719
                    }
4720
                } else {
4721
                    break;
4722
                }
4723
            }
4724
            if (b) {
4725
                indent -= option.indent;
4726
                indentation();
4727
            }
4728
            advance('}', this);
4729
            return this;
4730
        };
4731
        x.fud = function () {
4732
            error("Expected to see a statement and instead saw a block.", token);
4733
        };
4734
    }(delim('{')));
4735
4736
4737
    function varstatement(prefix) {
4738
4739
// JavaScript does not have block scope. It only has function scope. So,
4740
// declaring a variable in a block can have unexpected consequences.
4741
4742
        var id, name, value;
4743
4744
        if (funct['(onevar)'] && option.onevar) {
4745
            warning("Too many var statements.");
4746
        } else if (!funct['(global)']) {
4747
            funct['(onevar)'] = true;
4748
        }
4749
        this.first = [];
4750
        for (;;) {
4751
            nonadjacent(token, nexttoken);
4752
            id = identifier();
4753
            if (funct['(global)'] && predefined[id] === false) {
4754
                warning("Redefinition of '{a}'.", token, id);
4755
            }
4756
            addlabel(id, 'unused');
4757
            if (prefix) {
4758
                break;
4759
            }
4760
            name = token;
4761
            this.first.push(token);
4762
            if (nexttoken.id === '=') {
4763
                nonadjacent(token, nexttoken);
4764
                advance('=');
4765
                nonadjacent(token, nexttoken);
4766
                if (nexttoken.id === 'undefined') {
4767
                    warning("It is not necessary to initialize '{a}' to 'undefined'.", token, id);
4768
                }
4769
                if (peek(0).id === '=' && nexttoken.identifier) {
4770
                    error("Variable {a} was not declared correctly.",
4771
                            nexttoken, nexttoken.value);
4772
                }
4773
                value = parse(0);
4774
                name.first = value;
4775
            }
4776
            if (nexttoken.id !== ',') {
4777
                break;
4778
            }
4779
            comma();
4780
        }
4781
        return this;
4782
    }
4783
4784
4785
    stmt('var', varstatement).exps = true;
4786
4787
4788
    blockstmt('function', function () {
4789
        if (inblock) {
4790
            warning(
4791
"Function statements cannot be placed in blocks. Use a function expression or move the statement to the top of the outer function.", token);
4792
4793
        }
4794
        var i = identifier();
4795
        adjacent(token, nexttoken);
4796
        addlabel(i, 'unused');
4797
        doFunction(i);
4798
        if (nexttoken.id === '(' && nexttoken.line === token.line) {
4799
            error(
4800
"Function statements are not invocable. Wrap the whole function invocation in parens.");
4801
        }
4802
        return this;
4803
    });
4804
4805
    prefix('function', function () {
4806
        var i = optionalidentifier();
4807
        if (i) {
4808
            adjacent(token, nexttoken);
4809
        } else {
4810
            nonadjacent(token, nexttoken);
4811
        }
4812
        doFunction(i);
4813
        if (funct['(loopage)']) {
4814
            warning("Don't make functions within a loop.");
4815
        }
4816
        return this;
4817
    });
4818
4819
    blockstmt('if', function () {
4820
        var t = nexttoken;
4821
        advance('(');
4822
        nonadjacent(this, t);
4823
        nospace();
4824
        parse(20);
4825
        if (nexttoken.id === '=') {
4826
            warning("Expected a conditional expression and instead saw an assignment.");
4827
            advance('=');
4828
            parse(20);
4829
        }
4830
        advance(')', t);
4831
        nospace(prevtoken, token);
4832
        block(true);
4833
        if (nexttoken.id === 'else') {
4834
            nonadjacent(token, nexttoken);
4835
            advance('else');
4836
            if (nexttoken.id === 'if' || nexttoken.id === 'switch') {
4837
                statement(true);
4838
            } else {
4839
                block(true);
4840
            }
4841
        }
4842
        return this;
4843
    });
4844
4845
    blockstmt('try', function () {
4846
        var b, e, s;
4847
        if (option.adsafe) {
4848
            warning("ADsafe try violation.", this);
4849
        }
4850
        block(false);
4851
        if (nexttoken.id === 'catch') {
4852
            advance('catch');
4853
            nonadjacent(token, nexttoken);
4854
            advance('(');
4855
            s = scope;
4856
            scope = Object.create(s);
4857
            e = nexttoken.value;
4858
            if (nexttoken.type !== '(identifier)') {
4859
                warning("Expected an identifier and instead saw '{a}'.",
4860
                    nexttoken, e);
4861
            } else {
4862
                addlabel(e, 'exception');
4863
            }
4864
            advance();
4865
            advance(')');
4866
            block(false);
4867
            b = true;
4868
            scope = s;
4869
        }
4870
        if (nexttoken.id === 'finally') {
4871
            advance('finally');
4872
            block(false);
4873
            return;
4874
        } else if (!b) {
4875
            error("Expected '{a}' and instead saw '{b}'.",
4876
                    nexttoken, 'catch', nexttoken.value);
4877
        }
4878
        return this;
4879
    });
4880
4881
    blockstmt('while', function () {
4882
        var t = nexttoken;
4883
        funct['(breakage)'] += 1;
4884
        funct['(loopage)'] += 1;
4885
        advance('(');
4886
        nonadjacent(this, t);
4887
        nospace();
4888
        parse(20);
4889
        if (nexttoken.id === '=') {
4890
            warning("Expected a conditional expression and instead saw an assignment.");
4891
            advance('=');
4892
            parse(20);
4893
        }
4894
        advance(')', t);
4895
        nospace(prevtoken, token);
4896
        block(true);
4897
        funct['(breakage)'] -= 1;
4898
        funct['(loopage)'] -= 1;
4899
        return this;
4900
    }).labelled = true;
4901
4902
    reserve('with');
4903
4904
    blockstmt('switch', function () {
4905
        var t = nexttoken,
4906
            g = false;
4907
        funct['(breakage)'] += 1;
4908
        advance('(');
4909
        nonadjacent(this, t);
4910
        nospace();
4911
        this.condition = parse(20);
4912
        advance(')', t);
4913
        nospace(prevtoken, token);
4914
        nonadjacent(token, nexttoken);
4915
        t = nexttoken;
4916
        advance('{');
4917
        nonadjacent(token, nexttoken);
4918
        indent += option.indent;
4919
        this.cases = [];
4920
        for (;;) {
4921
            switch (nexttoken.id) {
4922
            case 'case':
4923
                switch (funct['(verb)']) {
4924
                case 'break':
4925
                case 'case':
4926
                case 'continue':
4927
                case 'return':
4928
                case 'switch':
4929
                case 'throw':
4930
                    break;
4931
                default:
4932
                    warning(
4933
                        "Expected a 'break' statement before 'case'.",
4934
                        token);
4935
                }
4936
                indentation(-option.indent);
4937
                advance('case');
4938
                this.cases.push(parse(20));
4939
                g = true;
4940
                advance(':');
4941
                funct['(verb)'] = 'case';
4942
                break;
4943
            case 'default':
4944
                switch (funct['(verb)']) {
4945
                case 'break':
4946
                case 'continue':
4947
                case 'return':
4948
                case 'throw':
4949
                    break;
4950
                default:
4951
                    warning(
4952
                        "Expected a 'break' statement before 'default'.",
4953
                        token);
4954
                }
4955
                indentation(-option.indent);
4956
                advance('default');
4957
                g = true;
4958
                advance(':');
4959
                break;
4960
            case '}':
4961
                indent -= option.indent;
4962
                indentation();
4963
                advance('}', t);
4964
                if (this.cases.length === 1 || this.condition.id === 'true' ||
4965
                        this.condition.id === 'false') {
4966
                    warning("This 'switch' should be an 'if'.", this);
4967
                }
4968
                funct['(breakage)'] -= 1;
4969
                funct['(verb)'] = undefined;
4970
                return;
4971
            case '(end)':
4972
                error("Missing '{a}'.", nexttoken, '}');
4973
                return;
4974
            default:
4975
                if (g) {
4976
                    switch (token.id) {
4977
                    case ',':
4978
                        error("Each value should have its own case label.");
4979
                        return;
4980
                    case ':':
4981
                        statements();
4982
                        break;
4983
                    default:
4984
                        error("Missing ':' on a case clause.", token);
4985
                    }
4986
                } else {
4987
                    error("Expected '{a}' and instead saw '{b}'.",
4988
                        nexttoken, 'case', nexttoken.value);
4989
                }
4990
            }
4991
        }
4992
    }).labelled = true;
4993
4994
    stmt('debugger', function () {
4995
        if (!option.debug) {
4996
            warning("All 'debugger' statements should be removed.");
4997
        }
4998
        return this;
4999
    }).exps = true;
5000
5001
    (function () {
5002
        var x = stmt('do', function () {
5003
            funct['(breakage)'] += 1;
5004
            funct['(loopage)'] += 1;
5005
            this.first = block(true);
5006
            advance('while');
5007
            var t = nexttoken;
5008
            nonadjacent(token, t);
5009
            advance('(');
5010
            nospace();
5011
            parse(20);
5012
            if (nexttoken.id === '=') {
5013
                warning("Expected a conditional expression and instead saw an assignment.");
5014
                advance('=');
5015
                parse(20);
5016
            }
5017
            advance(')', t);
5018
            nospace(prevtoken, token);
5019
            funct['(breakage)'] -= 1;
5020
            funct['(loopage)'] -= 1;
5021
            return this;
5022
        });
5023
        x.labelled = true;
5024
        x.exps = true;
5025
    }());
5026
5027
    blockstmt('for', function () {
5028
        var f = option.forin, s, t = nexttoken;
5029
        funct['(breakage)'] += 1;
5030
        funct['(loopage)'] += 1;
5031
        advance('(');
5032
        nonadjacent(this, t);
5033
        nospace();
5034
        if (peek(nexttoken.id === 'var' ? 1 : 0).id === 'in') {
5035
            if (nexttoken.id === 'var') {
5036
                advance('var');
5037
                varstatement(true);
5038
            } else {
5039
                switch (funct[nexttoken.value]) {
5040
                case 'unused':
5041
                    funct[nexttoken.value] = 'var';
5042
                    break;
5043
                case 'var':
5044
                    break;
5045
                default:
5046
                    warning("Bad for in variable '{a}'.",
5047
                            nexttoken, nexttoken.value);
5048
                }
5049
                advance();
5050
            }
5051
            advance('in');
5052
            parse(20);
5053
            advance(')', t);
5054
            s = block(true);
5055
            if (!f && (s.length > 1 || typeof s[0] !== 'object' ||
5056
                    s[0].value !== 'if')) {
5057
                warning("The body of a for in should be wrapped in an if statement to filter unwanted properties from the prototype.", this);
5058
            }
5059
            funct['(breakage)'] -= 1;
5060
            funct['(loopage)'] -= 1;
5061
            return this;
5062
        } else {
5063
            if (nexttoken.id !== ';') {
5064
                if (nexttoken.id === 'var') {
5065
                    advance('var');
5066
                    varstatement();
5067
                } else {
5068
                    for (;;) {
5069
                        parse(0, 'for');
5070
                        if (nexttoken.id !== ',') {
5071
                            break;
5072
                        }
5073
                        comma();
5074
                    }
5075
                }
5076
            }
5077
            nolinebreak(token);
5078
            advance(';');
5079
            if (nexttoken.id !== ';') {
5080
                parse(20);
5081
                if (nexttoken.id === '=') {
5082
                    warning("Expected a conditional expression and instead saw an assignment.");
5083
                    advance('=');
5084
                    parse(20);
5085
                }
5086
            }
5087
            nolinebreak(token);
5088
            advance(';');
5089
            if (nexttoken.id === ';') {
5090
                error("Expected '{a}' and instead saw '{b}'.",
5091
                        nexttoken, ')', ';');
5092
            }
5093
            if (nexttoken.id !== ')') {
5094
                for (;;) {
5095
                    parse(0, 'for');
5096
                    if (nexttoken.id !== ',') {
5097
                        break;
5098
                    }
5099
                    comma();
5100
                }
5101
            }
5102
            advance(')', t);
5103
            nospace(prevtoken, token);
5104
            block(true);
5105
            funct['(breakage)'] -= 1;
5106
            funct['(loopage)'] -= 1;
5107
            return this;
5108
        }
5109
    }).labelled = true;
5110
5111
5112
    stmt('break', function () {
5113
        var v = nexttoken.value;
5114
        if (funct['(breakage)'] === 0) {
5115
            warning("Unexpected '{a}'.", nexttoken, this.value);
5116
        }
5117
        nolinebreak(this);
5118
        if (nexttoken.id !== ';') {
5119
            if (token.line === nexttoken.line) {
5120
                if (funct[v] !== 'label') {
5121
                    warning("'{a}' is not a statement label.", nexttoken, v);
5122
                } else if (scope[v] !== funct) {
5123
                    warning("'{a}' is out of scope.", nexttoken, v);
5124
                }
5125
                this.first = nexttoken;
5126
                advance();
5127
            }
5128
        }
5129
        reachable('break');
5130
        return this;
5131
    }).exps = true;
5132
5133
5134
    stmt('continue', function () {
5135
        var v = nexttoken.value;
5136
        if (funct['(breakage)'] === 0) {
5137
            warning("Unexpected '{a}'.", nexttoken, this.value);
5138
        }
5139
        nolinebreak(this);
5140
        if (nexttoken.id !== ';') {
5141
            if (token.line === nexttoken.line) {
5142
                if (funct[v] !== 'label') {
5143
                    warning("'{a}' is not a statement label.", nexttoken, v);
5144
                } else if (scope[v] !== funct) {
5145
                    warning("'{a}' is out of scope.", nexttoken, v);
5146
                }
5147
                this.first = nexttoken;
5148
                advance();
5149
            }
5150
        } else if (!funct['(loopage)']) {
5151
            warning("Unexpected '{a}'.", nexttoken, this.value);
5152
        }
5153
        reachable('continue');
5154
        return this;
5155
    }).exps = true;
5156
5157
5158
    stmt('return', function () {
5159
        nolinebreak(this);
5160
        if (nexttoken.id === '(regexp)') {
5161
            warning("Wrap the /regexp/ literal in parens to disambiguate the slash operator.");
5162
        }
5163
        if (nexttoken.id !== ';' && !nexttoken.reach) {
5164
            nonadjacent(token, nexttoken);
5165
            this.first = parse(20);
5166
        }
5167
        reachable('return');
5168
        return this;
5169
    }).exps = true;
5170
5171
5172
    stmt('throw', function () {
5173
        nolinebreak(this);
5174
        nonadjacent(token, nexttoken);
5175
        this.first = parse(20);
5176
        reachable('throw');
5177
        return this;
5178
    }).exps = true;
5179
5180
    reserve('void');
5181
5182
//  Superfluous reserved words
5183
5184
    reserve('class');
5185
    reserve('const');
5186
    reserve('enum');
5187
    reserve('export');
5188
    reserve('extends');
5189
    reserve('import');
5190
    reserve('super');
5191
5192
    reserve('let');
5193
    reserve('yield');
5194
    reserve('implements');
5195
    reserve('interface');
5196
    reserve('package');
5197
    reserve('private');
5198
    reserve('protected');
5199
    reserve('public');
5200
    reserve('static');
5201
5202
5203
// Parse JSON
5204
5205
    function jsonValue() {
5206
5207
        function jsonObject() {
5208
            var o = {}, t = nexttoken;
5209
            advance('{');
5210
            if (nexttoken.id !== '}') {
5211
                for (;;) {
5212
                    if (nexttoken.id === '(end)') {
5213
                        error("Missing '}' to match '{' from line {a}.",
5214
                                nexttoken, t.line);
5215
                    } else if (nexttoken.id === '}') {
5216
                        warning("Unexpected comma.", token);
5217
                        break;
5218
                    } else if (nexttoken.id === ',') {
5219
                        error("Unexpected comma.", nexttoken);
5220
                    } else if (nexttoken.id !== '(string)') {
5221
                        warning("Expected a string and instead saw {a}.",
5222
                                nexttoken, nexttoken.value);
5223
                    }
5224
                    if (o[nexttoken.value] === true) {
5225
                        warning("Duplicate key '{a}'.",
5226
                                nexttoken, nexttoken.value);
5227
                    } else if (nexttoken.value === '__proto__') {
5228
                        warning("Stupid key '{a}'.",
5229
                                nexttoken, nexttoken.value);
5230
                    } else {
5231
                        o[nexttoken.value] = true;
5232
                    }
5233
                    advance();
5234
                    advance(':');
5235
                    jsonValue();
5236
                    if (nexttoken.id !== ',') {
5237
                        break;
5238
                    }
5239
                    advance(',');
5240
                }
5241
            }
5242
            advance('}');
5243
        }
5244
5245
        function jsonArray() {
5246
            var t = nexttoken;
5247
            advance('[');
5248
            if (nexttoken.id !== ']') {
5249
                for (;;) {
5250
                    if (nexttoken.id === '(end)') {
5251
                        error("Missing ']' to match '[' from line {a}.",
5252
                                nexttoken, t.line);
5253
                    } else if (nexttoken.id === ']') {
5254
                        warning("Unexpected comma.", token);
5255
                        break;
5256
                    } else if (nexttoken.id === ',') {
5257
                        error("Unexpected comma.", nexttoken);
5258
                    }
5259
                    jsonValue();
5260
                    if (nexttoken.id !== ',') {
5261
                        break;
5262
                    }
5263
                    advance(',');
5264
                }
5265
            }
5266
            advance(']');
5267
        }
5268
5269
        switch (nexttoken.id) {
5270
        case '{':
5271
            jsonObject();
5272
            break;
5273
        case '[':
5274
            jsonArray();
5275
            break;
5276
        case 'true':
5277
        case 'false':
5278
        case 'null':
5279
        case '(number)':
5280
        case '(string)':
5281
            advance();
5282
            break;
5283
        case '-':
5284
            advance('-');
5285
            if (token.character !== nexttoken.from) {
5286
                warning("Unexpected space after '-'.", token);
5287
            }
5288
            adjacent(token, nexttoken);
5289
            advance('(number)');
5290
            break;
5291
        default:
5292
            error("Expected a JSON value.", nexttoken);
5293
        }
5294
    }
5295
5296
5297
// The actual JSLINT function itself.
5298
5299
    var itself = function (s, o) {
5300
        var a, i;
5301
        JSLINT.errors = [];
5302
        predefined = Object.create(standard);
5303
        if (o) {
5304
            a = o.predef;
5305
            if (a instanceof Array) {
5306
                for (i = 0; i < a.length; i += 1) {
5307
                    predefined[a[i]] = true;
5308
                }
5309
            }
5310
            if (o.adsafe) {
5311
                o.safe = true;
5312
            }
5313
            if (o.safe) {
5314
                o.browser =
5315
                o.css     =
5316
                o.debug   =
5317
                o.devel   =
5318
                o.evil    =
5319
                o.forin   =
5320
                o.on      =
5321
                o.rhino   =
5322
                o.windows =
5323
                o.sub     =
5324
                o.widget  = false;
5325
5326
                o.eqeqeq  =
5327
                o.nomen   =
5328
                o.safe    =
5329
                o.strict  =
5330
                o.undef   = true;
5331
5332
                predefined.Date =
5333
                predefined['eval'] =
5334
                predefined.Function =
5335
                predefined.Object = null;
5336
5337
                predefined.ADSAFE =
5338
                predefined.lib = false;
5339
            }
5340
            option = o;
5341
        } else {
5342
            option = {};
5343
        }
5344
        option.indent = option.indent || 4;
5345
        option.maxerr = option.maxerr || 50;
5346
        adsafe_id = '';
5347
        adsafe_may = false;
5348
        adsafe_went = false;
5349
        approved = {};
5350
        if (option.approved) {
5351
            for (i = 0; i < option.approved.length; i += 1) {
5352
                approved[option.approved[i]] = option.approved[i];
5353
            }
5354
        } else {
5355
            approved.test = 'test';
5356
        }
5357
        tab = '';
5358
        for (i = 0; i < option.indent; i += 1) {
5359
            tab += ' ';
5360
        }
5361
        indent = 1;
5362
        global = Object.create(predefined);
5363
        scope = global;
5364
        funct = {
5365
            '(global)': true,
5366
            '(name)': '(global)',
5367
            '(scope)': scope,
5368
            '(breakage)': 0,
5369
            '(loopage)': 0
5370
        };
5371
        functions = [funct];
5372
        ids = {};
5373
        urls = [];
5374
        src = false;
5375
        xmode = false;
5376
        stack = null;
5377
        member = {};
5378
        membersOnly = null;
5379
        implied = {};
5380
        inblock = false;
5381
        lookahead = [];
5382
        jsonmode = false;
5383
        warnings = 0;
5384
        lex.init(s);
5385
        prereg = true;
5386
        strict_mode = false;
5387
5388
        prevtoken = token = nexttoken = syntax['(begin)'];
5389
        assume();
5390
5391
        try {
5392
            advance();
5393
            if (nexttoken.value.charAt(0) === '<') {
5394
                html();
5395
                if (option.adsafe && !adsafe_went) {
5396
                    warning("ADsafe violation: Missing ADSAFE.go.", this);
5397
                }
5398
            } else {
5399
                switch (nexttoken.id) {
5400
                case '{':
5401
                case '[':
5402
                    option.laxbreak = true;
5403
                    jsonmode = true;
5404
                    jsonValue();
5405
                    break;
5406
                case '@':
5407
                case '*':
5408
                case '#':
5409
                case '.':
5410
                case ':':
5411
                    xmode = 'style';
5412
                    advance();
5413
                    if (token.id !== '@' || !nexttoken.identifier ||
5414
                            nexttoken.value !== 'charset' || token.line !== 1 ||
5415
                            token.from !== 1) {
5416
                        error('A css file should begin with @charset "UTF-8";');
5417
                    }
5418
                    advance();
5419
                    if (nexttoken.type !== '(string)' &&
5420
                            nexttoken.value !== 'UTF-8') {
5421
                        error('A css file should begin with @charset "UTF-8";');
5422
                    }
5423
                    advance();
5424
                    advance(';');
5425
                    styles();
5426
                    break;
5427
5428
                default:
5429
                    if (option.adsafe && option.fragment) {
5430
                        error("Expected '{a}' and instead saw '{b}'.",
5431
                            nexttoken, '<div>', nexttoken.value);
5432
                    }
5433
                    statements('lib');
5434
                }
5435
            }
5436
            advance('(end)');
5437
        } catch (e) {
5438
            if (e) {
5439
                JSLINT.errors.push({
5440
                    reason    : e.message,
5441
                    line      : e.line || nexttoken.line,
5442
                    character : e.character || nexttoken.from
5443
                }, null);
5444
            }
5445
        }
5446
        return JSLINT.errors.length === 0;
5447
    };
5448
5449
    function is_array(o) {
5450
        return Object.prototype.toString.apply(o) === '[object Array]';
5451
    }
5452
5453
    function to_array(o) {
5454
        var a = [], k;
5455
        for (k in o) {
5456
            if (is_own(o, k)) {
5457
                a.push(k);
5458
            }
5459
        }
5460
        return a;
5461
    }
5462
5463
5464
// Data summary.
5465
5466
    itself.data = function () {
5467
5468
        var data = {functions: []}, fu, globals, implieds = [], f, i, j,
5469
            members = [], n, unused = [], v;
5470
        if (itself.errors.length) {
5471
            data.errors = itself.errors;
5472
        }
5473
5474
        if (jsonmode) {
5475
            data.json = true;
5476
        }
5477
5478
        for (n in implied) {
5479
            if (is_own(implied, n)) {
5480
                implieds.push({
5481
                    name: n,
5482
                    line: implied[n]
5483
                });
5484
            }
5485
        }
5486
        if (implieds.length > 0) {
5487
            data.implieds = implieds;
5488
        }
5489
5490
        if (urls.length > 0) {
5491
            data.urls = urls;
5492
        }
5493
5494
        globals = to_array(scope);
5495
        if (globals.length > 0) {
5496
            data.globals = globals;
5497
        }
5498
5499
        for (i = 1; i < functions.length; i += 1) {
5500
            f = functions[i];
5501
            fu = {};
5502
            for (j = 0; j < functionicity.length; j += 1) {
5503
                fu[functionicity[j]] = [];
5504
            }
5505
            for (n in f) {
5506
                if (is_own(f, n) && n.charAt(0) !== '(') {
5507
                    v = f[n];
5508
                    if (is_array(fu[v])) {
5509
                        fu[v].push(n);
5510
                        if (v === 'unused') {
5511
                            unused.push({
5512
                                name: n,
5513
                                line: f['(line)'],
5514
                                'function': f['(name)']
5515
                            });
5516
                        }
5517
                    }
5518
                }
5519
            }
5520
            for (j = 0; j < functionicity.length; j += 1) {
5521
                if (fu[functionicity[j]].length === 0) {
5522
                    delete fu[functionicity[j]];
5523
                }
5524
            }
5525
            fu.name = f['(name)'];
5526
            fu.param = f['(params)'];
5527
            fu.line = f['(line)'];
5528
            fu.last = f['(last)'];
5529
            data.functions.push(fu);
5530
        }
5531
5532
        if (unused.length > 0) {
5533
            data.unused = unused;
5534
        }
5535
5536
        members = [];
5537
        for (n in member) {
5538
            if (typeof member[n] === 'number') {
5539
                data.member = member;
5540
                break;
5541
            }
5542
        }
5543
5544
        return data;
5545
    };
5546
5547
    itself.report = function (option) {
5548
        var data = itself.data();
5549
5550
        var a = [], c, e, err, f, i, k, l, m = '', n, o = [], s;
5551
5552
        function detail(h, array) {
5553
            var b, i, singularity;
5554
            if (array) {
5555
                o.push('<div><i>' + h + '</i> ');
5556
                array = array.sort();
5557
                for (i = 0; i < array.length; i += 1) {
5558
                    if (array[i] !== singularity) {
5559
                        singularity = array[i];
5560
                        o.push((b ? ', ' : '') + singularity);
5561
                        b = true;
5562
                    }
5563
                }
5564
                o.push('</div>');
5565
            }
5566
        }
5567
5568
5569
        if (data.errors || data.implieds || data.unused) {
5570
            err = true;
5571
            o.push('<div id=errors><i>Error:</i>');
5572
            if (data.errors) {
5573
                for (i = 0; i < data.errors.length; i += 1) {
5574
                    c = data.errors[i];
5575
                    if (c) {
5576
                        e = c.evidence || '';
5577
                        o.push('<p>Problem' + (isFinite(c.line) ? ' at line ' +
5578
                                c.line + ' character ' + c.character : '') +
5579
                                ': ' + c.reason.entityify() +
5580
                                '</p><p class=evidence>' +
5581
                                (e && (e.length > 80 ? e.slice(0, 77) + '...' :
5582
                                e).entityify()) + '</p>');
5583
                    }
5584
                }
5585
            }
5586
5587
            if (data.implieds) {
5588
                s = [];
5589
                for (i = 0; i < data.implieds.length; i += 1) {
5590
                    s[i] = '<code>' + data.implieds[i].name + '</code>&nbsp;<i>' +
5591
                        data.implieds[i].line + '</i>';
5592
                }
5593
                o.push('<p><i>Implied global:</i> ' + s.join(', ') + '</p>');
5594
            }
5595
5596
            if (data.unused) {
5597
                s = [];
5598
                for (i = 0; i < data.unused.length; i += 1) {
5599
                    s[i] = '<code><u>' + data.unused[i].name + '</u></code>&nbsp;<i>' +
5600
                        data.unused[i].line + '</i> <code>' +
5601
                        data.unused[i]['function'] + '</code>';
5602
                }
5603
                o.push('<p><i>Unused variable:</i> ' + s.join(', ') + '</p>');
5604
            }
5605
            if (data.json) {
5606
                o.push('<p>JSON: bad.</p>');
5607
            }
5608
            o.push('</div>');
5609
        }
5610
5611
        if (!option) {
5612
5613
            o.push('<br><div id=functions>');
5614
5615
            if (data.urls) {
5616
                detail("URLs<br>", data.urls, '<br>');
5617
            }
5618
5619
            if (xmode === 'style') {
5620
                o.push('<p>CSS.</p>');
5621
            } else if (data.json && !err) {
5622
                o.push('<p>JSON: good.</p>');
5623
            } else if (data.globals) {
5624
                o.push('<div><i>Global</i> ' +
5625
                        data.globals.sort().join(', ') + '</div>');
5626
            } else {
5627
                o.push('<div><i>No new global variables introduced.</i></div>');
5628
            }
5629
5630
            for (i = 0; i < data.functions.length; i += 1) {
5631
                f = data.functions[i];
5632
5633
                o.push('<br><div class=function><i>' + f.line + '-' +
5634
                        f.last + '</i> ' + (f.name || '') + '(' +
5635
                        (f.param ? f.param.join(', ') : '') + ')</div>');
5636
                detail('<big><b>Unused</b></big>', f.unused);
5637
                detail('Closure', f.closure);
5638
                detail('Variable', f['var']);
5639
                detail('Exception', f.exception);
5640
                detail('Outer', f.outer);
5641
                detail('Global', f.global);
5642
                detail('Label', f.label);
5643
            }
5644
5645
            if (data.member) {
5646
                a = to_array(data.member);
5647
                if (a.length) {
5648
                    a = a.sort();
5649
                    m = '<br><pre id=members>/*members ';
5650
                    l = 10;
5651
                    for (i = 0; i < a.length; i += 1) {
5652
                        k = a[i];
5653
                        n = k.name();
5654
                        if (l + n.length > 72) {
5655
                            o.push(m + '<br>');
5656
                            m = '    ';
5657
                            l = 1;
5658
                        }
5659
                        l += n.length + 2;
5660
                        if (data.member[k] === 1) {
5661
                            n = '<i>' + n + '</i>';
5662
                        }
5663
                        if (i < a.length - 1) {
5664
                            n += ', ';
5665
                        }
5666
                        m += n;
5667
                    }
5668
                    o.push(m + '<br>*/</pre>');
5669
                }
5670
                o.push('</div>');
5671
            }
5672
        }
5673
        return o.join('');
5674
    };
5675
    itself.jslint = itself;
5676
5677
    itself.edition = '2010-08-05';
5678
5679
    return itself;
5680
5681
}());