~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to utilities/build/fulljslint.js

Merged in Ian's changes which introduce buildtools.

Show diffs side-by-side

added added

removed removed

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