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