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