1 /*global core*/
  2 // jslint.js
  3 // 2014-07-08
  4 
  5 // Copyright (c) 2002 Douglas Crockford  (www.JSLint.com)
  6 
  7 // Permission is hereby granted, free of charge, to any person obtaining a copy
  8 // of this software and associated documentation files (the "Software"), to deal
  9 // in the Software without restriction, including without limitation the rights
 10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 11 // copies of the Software, and to permit persons to whom the Software is
 12 // furnished to do so, subject to the following conditions:
 13 
 14 // The above copyright notice and this permission notice shall be included in
 15 // all copies or substantial portions of the Software.
 16 
 17 // The Software shall be used for Good, not Evil.
 18 
 19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 20 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 21 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 22 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 23 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 24 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 25 // SOFTWARE.
 26 
 27 // WARNING: JSLint will hurt your feelings.
 28 
 29 // JSLINT is a global function. It takes two parameters.
 30 
 31 //     var myResult = JSLINT(source, option);
 32 
 33 // The first parameter is either a string or an array of strings. If it is a
 34 // string, it will be split on '\n' or '\r'. If it is an array of strings, it
 35 // is assumed that each string represents one line. The source can be a
 36 // JavaScript text or a JSON text.
 37 
 38 // The second parameter is an optional object of options that control the
 39 // operation of JSLINT. Most of the options are booleans: They are all
 40 // optional and have a default value of false. One of the options, predef,
 41 // can be an array of names, which will be used to declare global variables,
 42 // or an object whose keys are used as global names, with a boolean value
 43 // that determines if they are assignable.
 44 
 45 // If it checks out, JSLINT returns true. Otherwise, it returns false.
 46 
 47 // If false, you can inspect JSLINT.errors to find out the problems.
 48 // JSLINT.errors is an array of objects containing these properties:
 49 
 50 //  {
 51 //      line      : The line (relative to 0) at which the lint was found
 52 //      character : The character (relative to 0) at which the lint was found
 53 //      reason    : The problem
 54 //      evidence  : The text line in which the problem occurred
 55 //      raw       : The raw message before the details were inserted
 56 //      a         : The first detail
 57 //      b         : The second detail
 58 //      c         : The third detail
 59 //      d         : The fourth detail
 60 //  }
 61 
 62 // If a stopping error was found, a null will be the last element of the
 63 // JSLINT.errors array. A stopping error means that JSLint was not confident
 64 // enough to continue. It does not necessarily mean that the error was
 65 // especially heinous.
 66 
 67 // You can request a data structure that contains JSLint's results.
 68 
 69 //     var myData = JSLINT.data();
 70 
 71 // It returns a structure with this form:
 72 
 73 //     {
 74 //         errors: [
 75 //             {
 76 //                 line: NUMBER,
 77 //                 character: NUMBER,
 78 //                 reason: STRING,
 79 //                 evidence: STRING
 80 //             }
 81 //         ],
 82 //         functions: [
 83 //             {
 84 //                 name: STRING,
 85 //                 line: NUMBER,
 86 //                 level: NUMBER,
 87 //                 parameter: [
 88 //                     STRING
 89 //                 ],
 90 //                 var: [
 91 //                     STRING
 92 //                 ],
 93 //                 exception: [
 94 //                     STRING
 95 //                 ],
 96 //                 closure: [
 97 //                     STRING
 98 //                 ],
 99 //                 outer: [
100 //                     STRING
101 //                 ],
102 //                 global: [
103 //                     STRING
104 //                 ],
105 //                 label: [
106 //                     STRING
107 //                 ]
108 //             }
109 //         ],
110 //         global: [
111 //             STRING
112 //         ],
113 //         member: {
114 //             STRING: NUMBER
115 //         },
116 //         json: BOOLEAN
117 //     }
118 
119 // You can request a Function Report, which shows all of the functions
120 // and the parameters and vars that they use. This can be used to find
121 // implied global variables and other problems. The report is in HTML and
122 // can be inserted into an HTML <body>. It should be given the result of the
123 // JSLINT.data function.
124 
125 //     var myReport = JSLINT.report(data);
126 
127 // You can request an HTML error report.
128 
129 //     var myErrorReport = JSLINT.error_report(data);
130 
131 // You can obtain an object containing all of the properties found in the
132 // file. JSLINT.property contains an object containing a key for each
133 // property used in the program, the value being the number of times that
134 // property name was used in the file.
135 
136 // You can request a properties report, which produces a list of the program's
137 // properties in the form of a /*properties*/ declaration.
138 
139 //      var myPropertyReport = JSLINT.properties_report(JSLINT.property);
140 
141 // You can obtain the parse tree that JSLint constructed while parsing. The
142 // latest tree is kept in JSLINT.tree. A nice stringification can be produced
143 // with
144 
145 //     JSON.stringify(JSLINT.tree, [
146 //         'string',  'arity', 'name',  'first',
147 //         'second', 'third', 'block', 'else'
148 //     ], 4));
149 
150 // You can request a context coloring table. It contains information that can be
151 // applied to the file that was analyzed. Context coloring colors functions
152 // based on their nesting level, and variables on the color of the functions
153 // in which they are defined.
154 
155 //      var myColorization = JSLINT.color(data);
156 
157 // It returns an array containing objects of this form:
158 
159 //      {
160 //          from: COLUMN,
161 //          thru: COLUMN,
162 //          line: ROW,
163 //          level: 0 or higher
164 //      }
165 
166 // JSLint provides three inline directives. They look like slashstar comments,
167 // and allow for setting options, declaring global variables, and establishing a
168 // set of allowed property names.
169 
170 // These directives respect function scope.
171 
172 // The jslint directive is a special comment that can set one or more options.
173 // For example:
174 
175 /*jslint
176     evil: true, nomen: true, regexp: true, todo: true
177 */
178 
179 // The current option set is
180 
181 //     ass        true, if assignment expressions should be allowed
182 //     bitwise    true, if bitwise operators should be allowed
183 //     browser    true, if the standard browser globals should be predefined
184 //     closure    true, if Google Closure idioms should be tolerated
185 //     continue   true, if the continuation statement should be tolerated
186 //     debug      true, if debugger statements should be allowed
187 //     defined    true, if already defined variables are allowed
188 //     devel      true, if logging should be allowed (console, alert, etc.)
189 //     emptyblock true, if empty blocks should be allowed
190 //     eqeq       true, if == should be allowed
191 //     evil       true, if eval should be allowed
192 //     forin      true, if for in statements need not filter
193 //     indent     the indentation factor
194 //     maxerr     the maximum number of errors to allow
195 //     maxlen     the maximum length of a source line
196 //     newcap     true, if constructor names capitalization is ignored
197 //     node       true, if Node.js globals should be predefined
198 //     nomen      true, if names may have dangling _
199 //     passfail   true, if the scan should stop on first error
200 //     plusplus   true, if increment/decrement should be allowed
201 //     properties true, if all property names must be declared with /*properties*/
202 //     regexp     true, if the . should be allowed in regexp literals
203 //     rhino      true, if the Rhino environment globals should be predefined
204 //     unparam    true, if unused parameters should be tolerated
205 //     sloppy     true, if the 'use strict'; pragma is optional
206 //     stupid     true, if really stupid practices are tolerated
207 //     sub        true, if all forms of subscript notation are tolerated
208 //     todo       true, if TODO comments are tolerated
209 //     unvar      true, if unused variables should be tolerated
210 //     vars       true, if multiple var statements per function should be allowed
211 //     white      true, if sloppy whitespace is tolerated
212 
213 // The properties directive declares an exclusive list of property names.
214 // Any properties named in the program that are not in the list will
215 // produce a warning.
216 
217 // For example:
218 
219 /*properties
220     defined, emptyblock, unvar, JSLINT, JSLint, core,
221     '\b', '\t', '\n', '\f', '\r', '!', '!=', '!==', '"', '%', '\'', '(begin)',
222     '(error)', '*', '+', '-', '/', '<', '<=', '==', '===', '>', '>=', '\\', a,
223     a_label, a_scope, already_defined, and, apply, arguments, arity, ass,
224     assign, assignment_expression, assignment_function_expression, at, avoid_a,
225     b, bad_assignment, bad_constructor, bad_in_a, bad_invocation, bad_new,
226     bad_number, bad_operand, bad_wrap, bitwise, block, break, breakage, browser,
227     c, call, charAt, charCodeAt, character, closure, code, color, combine_var,
228     comments, conditional_assignment, confusing_a, confusing_regexp,
229     constructor_name_a, continue, control_a, couch, create, d, dangling_a, data,
230     dead, debug, deleted, devel, disrupt, duplicate_a, edge, edition, elif,
231     else, empty_block, empty_case, empty_class, entityify, eqeq, error_report,
232     errors, evidence, evil, exception, exec, expected_a_at_b_c, expected_a_b,
233     expected_a_b_from_c_d, expected_id_a, expected_identifier_a,
234     expected_identifier_a_reserved, expected_number_a, expected_operator_a,
235     expected_positive_a, expected_small_a, expected_space_a_b,
236     expected_string_a, f, first, flag, floor, forEach, for_if, forin, from,
237     fromCharCode, fud, function, function_block, function_eval, function_loop,
238     function_statement, function_strict, functions, global, hasOwnProperty, id,
239     identifier, identifier_function, immed, implied_evil, indent, indexOf,
240     infix_in, init, insecure_a, isAlpha, isArray, isDigit, isNaN, join, jslint,
241     json, keys, kind, label, labeled, lbp, leading_decimal_a, led, left, length,
242     level, line, loopage, master, match, maxerr, maxlen, message, missing_a,
243     missing_a_after_b, missing_property, missing_space_a_b, missing_use_strict,
244     mode, move_invocation, move_var, n, name, name_function, nested_comment,
245     newcap, node, nomen, not, not_a_constructor, not_a_defined, not_a_function,
246     not_a_label, not_a_scope, not_greater, nud, number, octal_a, open, outer,
247     parameter, parameter_a_get_b, parameter_arguments_a, parameter_set_a,
248     params, paren, passfail, plusplus, pop, postscript, predef, properties,
249     properties_report, property, prototype, push, quote, r, radix, raw,
250     read_only, reason, redefinition_a_b, regexp, relation, replace, report,
251     reserved, reserved_a, rhino, right, scanned_a_b, scope, search, second,
252     shift, slash_equal, slice, sloppy, sort, split, statement, statement_block,
253     stop, stopping, strange_loop, strict, string, stupid, sub, subscript,
254     substr, supplant, sync_a, t, tag_a_in_b, test, third, thru, toString, todo,
255     todo_comment, token, tokens, too_long, too_many, trailing_decimal_a, tree,
256     unclosed, unclosed_comment, unclosed_regexp, unescaped_a, unexpected_a,
257     unexpected_char_a, unexpected_comment, unexpected_label_a,
258     unexpected_property_a, unexpected_space_a_b, unexpected_typeof_a,
259     uninitialized_a, unnecessary_else, unnecessary_initialize, unnecessary_use,
260     unparam, unreachable_a_b, unsafe, unused_a, url, use_array, use_braces,
261     use_nested_if, use_object, use_or, use_param, use_spaces, used,
262     used_before_a, var, var_a_not, var_loop, vars, varstatement, warn, warning,
263     was, weird_assignment, weird_condition, weird_new, weird_program,
264     weird_relation, weird_ternary, white, wrap, wrap_immediate, wrap_regexp,
265     write_is_wrong, writeable
266 */
267 
268 // The global directive is used to declare global variables that can
269 // be accessed by the program. If a declaration is true, then the variable
270 // is writeable. Otherwise, it is read-only.
271 
272 // We build the application inside a function so that we produce only a single
273 // global variable. That function will be invoked immediately, and its return
274 // value is the JSLINT function itself. That function is also an object that
275 // can contain data and other functions.
276 
277 var JSLINT = (function () {
278     'use strict';
279 
280     function array_to_object(array, value) {
281 
282 // Make an object from an array of keys and a common value.
283 
284         var i, length = array.length, object = Object.create(null);
285         for (i = 0; i < length; i += 1) {
286             object[array[i]] = value;
287         }
288         return object;
289     }
290 
291 
292     var allowed_option = {
293             ass       : true,
294             bitwise   : true,
295             browser   : true,
296             closure   : true,
297             continue  : true,
298             couch     : true,
299             debug     : true,
300             defined   : true,
301             devel     : true,
302             emptyblock: true,
303             eqeq      : true,
304             evil      : true,
305             forin     : true,
306             indent    :   10,
307             maxerr    : 1000,
308             maxlen    :  256,
309             newcap    : true,
310             node      : true,
311             nomen     : true,
312             passfail  : true,
313             plusplus  : true,
314             properties: true,
315             regexp    : true,
316             rhino     : true,
317             unparam   : true,
318             sloppy    : true,
319             stupid    : true,
320             sub       : true,
321             todo      : true,
322             unvar     : true,
323             vars      : true,
324             white     : true
325         },
326         anonname,       // The guessed name for anonymous functions.
327 
328 // These are operators that should not be used with the ! operator.
329 
330         bang = {
331             '<'  : true,
332             '<=' : true,
333             '==' : true,
334             '===': true,
335             '!==': true,
336             '!=' : true,
337             '>'  : true,
338             '>=' : true,
339             '+'  : true,
340             '-'  : true,
341             '*'  : true,
342             '/'  : true,
343             '%'  : true
344         },
345         begin,          // The root token
346         block_var,     // vars defined in the current block
347 
348 // browser contains a set of global names that are commonly provided by a
349 // web browser environment.
350 
351         browser = array_to_object([
352             'clearInterval', 'clearTimeout', 'document', 'event', 'FormData',
353             'frames', 'history', 'Image', 'localStorage', 'location', 'name',
354             'navigator', 'Option', 'parent', 'screen', 'sessionStorage',
355             'setInterval', 'setTimeout', 'Storage', 'window', 'XMLHttpRequest'
356         ], false),
357 
358 // bundle contains the text messages.
359 
360         bundle = {
361             a_label: "'{a}' is a statement label.",
362             a_scope: "'{a}' used out of scope.",
363             already_defined: "'{a}' is already defined.",
364             and: "The '&&' subexpression should be wrapped in parens.",
365             assignment_expression: "Unexpected assignment expression.",
366             assignment_function_expression: "Expected an assignment or " +
367                 "function call and instead saw an expression.",
368             avoid_a: "Avoid '{a}'.",
369             bad_assignment: "Bad assignment.",
370             bad_constructor: "Bad constructor.",
371             bad_in_a: "Bad for in variable '{a}'.",
372             bad_invocation: "Bad invocation.",
373             bad_new: "Do not use 'new' for side effects.",
374             bad_number: "Bad number '{a}'.",
375             bad_operand: "Bad operand.",
376             bad_wrap: "Do not wrap function literals in parens unless they " +
377                 "are to be immediately invoked.",
378             combine_var: "Combine this with the previous 'var' statement.",
379             conditional_assignment: "Expected a conditional expression and " +
380                 "instead saw an assignment.",
381             confusing_a: "Confusing use of '{a}'.",
382             confusing_regexp: "Confusing regular expression.",
383             constructor_name_a: "A constructor name '{a}' should start with " +
384                 "an uppercase letter.",
385             control_a: "Unexpected control character '{a}'.",
386             dangling_a: "Unexpected dangling '_' in '{a}'.",
387             deleted: "Only properties should be deleted.",
388             duplicate_a: "Duplicate '{a}'.",
389             empty_block: "Empty block.",
390             empty_case: "Empty case.",
391             empty_class: "Empty class.",
392             evil: "eval is evil.",
393             expected_a_b: "Expected '{a}' and instead saw '{b}'.",
394             expected_a_b_from_c_d: "Expected '{a}' to match '{b}' from line " +
395                 "{c} and instead saw '{d}'.",
396             expected_a_at_b_c: "Expected '{a}' at column {b}, not column {c}.",
397             expected_id_a: "Expected an id, and instead saw #{a}.",
398             expected_identifier_a: "Expected an identifier and instead saw '{a}'.",
399             expected_identifier_a_reserved: "Expected an identifier and " +
400                 "instead saw '{a}' (a reserved word).",
401             expected_number_a: "Expected a number and instead saw '{a}'.",
402             expected_operator_a: "Expected an operator and instead saw '{a}'.",
403             expected_positive_a: "Expected a positive number and instead saw '{a}'",
404             expected_small_a: "Expected a small positive integer and instead saw '{a}'",
405             expected_space_a_b: "Expected exactly one space between '{a}' and '{b}'.",
406             expected_string_a: "Expected a string and instead saw '{a}'.",
407             for_if: "The body of a for in should be wrapped in an if " +
408                 "statement to filter unwanted properties from the prototype.",
409             function_block: "Function statements should not be placed in blocks." +
410                 "Use a function expression or move the statement to the top of " +
411                 "the outer function.",
412             function_eval: "The Function constructor is eval.",
413             function_loop: "Don't make functions within a loop.",
414             function_statement: "Function statements are not invocable. " +
415                 "Wrap the whole function invocation in parens.",
416             function_strict: "Use the function form of 'use strict'.",
417             identifier_function: "Expected an identifier in an assignment " +
418                 "and instead saw a function invocation.",
419             implied_evil: "Implied eval is evil. Pass a function instead of a string.",
420             infix_in: "Unexpected 'in'. Compare with undefined, or use the " +
421                 "hasOwnProperty method instead.",
422             insecure_a: "Insecure '{a}'.",
423             isNaN: "Use the isNaN function to compare with NaN.",
424             leading_decimal_a: "A leading decimal point can be confused with a dot: '.{a}'.",
425             missing_a: "Missing '{a}'.",
426             missing_a_after_b: "Missing '{a}' after '{b}'.",
427             missing_property: "Missing property name.",
428             missing_space_a_b: "Missing space between '{a}' and '{b}'.",
429             missing_use_strict: "Missing 'use strict' statement.",
430             move_invocation: "Move the invocation into the parens that " +
431                 "contain the function.",
432             move_var: "Move 'var' declarations to the top of the function.",
433             name_function: "Missing name in function statement.",
434             nested_comment: "Nested comment.",
435             not: "Nested not.",
436             not_a_constructor: "Do not use {a} as a constructor.",
437             not_a_defined: "'{a}' has not been fully defined yet.",
438             not_a_function: "'{a}' is not a function.",
439             not_a_label: "'{a}' is not a label.",
440             not_a_scope: "'{a}' is out of scope.",
441             not_greater: "'{a}' should not be greater than '{b}'.",
442             octal_a: "Don't use octal: '{a}'. Use '\\u....' instead.",
443             parameter_arguments_a: "Do not mutate parameter '{a}' when using 'arguments'.",
444             parameter_a_get_b: "Unexpected parameter '{a}' in get {b} function.",
445             parameter_set_a: "Expected parameter (value) in set {a} function.",
446             radix: "Missing radix parameter.",
447             read_only: "Read only.",
448             redefinition_a_b: "Redefinition of '{a}' from line {b}.",
449             reserved_a: "Reserved name '{a}'.",
450             scanned_a_b: "{a} ({b}% scanned).",
451             slash_equal: "A regular expression literal can be confused with '/='.",
452             statement_block: "Expected to see a statement and instead saw a block.",
453             stopping: "Stopping.",
454             strange_loop: "Strange loop.",
455             strict: "Strict violation.",
456             subscript: "['{a}'] is better written in dot notation.",
457             sync_a: "Unexpected sync method: '{a}'.",
458             tag_a_in_b: "A '<{a}>' must be within '<{b}>'.",
459             todo_comment: "Unexpected TODO comment.",
460             too_long: "Line too long.",
461             too_many: "Too many errors.",
462             trailing_decimal_a: "A trailing decimal point can be confused " +
463                 "with a dot: '.{a}'.",
464             unclosed: "Unclosed string.",
465             unclosed_comment: "Unclosed comment.",
466             unclosed_regexp: "Unclosed regular expression.",
467             unescaped_a: "Unescaped '{a}'.",
468             unexpected_a: "Unexpected '{a}'.",
469             unexpected_char_a: "Unexpected character '{a}'.",
470             unexpected_comment: "Unexpected comment.",
471             unexpected_label_a: "Unexpected label '{a}'.",
472             unexpected_property_a: "Unexpected /*property*/ '{a}'.",
473             unexpected_space_a_b: "Unexpected space between '{a}' and '{b}'.",
474             unexpected_typeof_a: "Unexpected 'typeof'. " +
475                 "Use '===' to compare directly with {a}.",
476             uninitialized_a: "Uninitialized '{a}'.",
477             unnecessary_else: "Unnecessary 'else' after disruption.",
478             unnecessary_initialize: "It is not necessary to initialize '{a}' " +
479                 "to 'undefined'.",
480             unnecessary_use: "Unnecessary 'use strict'.",
481             unreachable_a_b: "Unreachable '{a}' after '{b}'.",
482             unsafe: "Unsafe character.",
483             unused_a: "Unused '{a}'.",
484             url: "JavaScript URL.",
485             use_array: "Use the array literal notation [].",
486             use_braces: "Spaces are hard to count. Use {{a}}.",
487             use_nested_if: "Expected 'else { if' and instead saw 'else if'.",
488             use_object: "Use the object literal notation {} or Object.create(null).",
489             use_or: "Use the || operator.",
490             use_param: "Use a named parameter.",
491             use_spaces: "Use spaces, not tabs.",
492             used_before_a: "'{a}' was used before it was defined.",
493             var_a_not: "Variable {a} was not declared correctly.",
494             var_loop: "Don't declare variables in a loop.",
495             weird_assignment: "Weird assignment.",
496             weird_condition: "Weird condition.",
497             weird_new: "Weird construction. Delete 'new'.",
498             weird_program: "Weird program.",
499             weird_relation: "Weird relation.",
500             weird_ternary: "Weird ternary.",
501             wrap_immediate: "Wrap an immediate function invocation in " +
502                 "parentheses to assist the reader in understanding that the " +
503                 "expression is the result of a function, and not the " +
504                 "function itself.",
505             wrap_regexp: "Wrap the /regexp/ literal in parens to " +
506                 "disambiguate the slash operator.",
507             write_is_wrong: "document.write can be a form of eval."
508         },
509         closure = array_to_object([
510             'goog'
511         ], false),
512         comments,
513         comments_off,
514         couch = array_to_object([
515             'emit', 'getRow', 'isArray', 'log', 'provides', 'registerType',
516             'require', 'send', 'start', 'sum', 'toJSON'
517         ], false),
518 
519         descapes = {
520             'b': '\b',
521             't': '\t',
522             'n': '\n',
523             'f': '\f',
524             'r': '\r',
525             '"': '"',
526             '/': '/',
527             '\\': '\\',
528             '!': '!'
529         },
530 
531         devel = array_to_object([
532             'alert', 'confirm', 'console', 'Debug', 'opera', 'prompt', 'WSH'
533         ], false),
534         directive,
535         escapes = {
536             '\b': '\\b',
537             '\t': '\\t',
538             '\n': '\\n',
539             '\f': '\\f',
540             '\r': '\\r',
541             '\'': '\\\'',
542             '"' : '\\"',
543             '/' : '\\/',
544             '\\': '\\\\'
545         },
546 
547         funct,          // The current function
548 
549         functions,      // All of the functions
550         global_funct,   // The global body
551         global_scope,   // The global scope
552         in_block,       // Where function statements are not allowed
553         indent,
554         itself,         // JSLINT itself
555         json_mode,
556         lex,            // the tokenizer
557         lines,
558         lookahead,
559         node = array_to_object([
560             'Buffer', 'clearImmediate', 'clearInterval', 'clearTimeout',
561             'console', 'exports', 'global', 'module', 'process',
562             'require', 'setImmediate', 'setInterval', 'setTimeout',
563             '__dirname', '__filename'
564         ], false),
565         node_js,
566         numbery = array_to_object(['indexOf', 'lastIndexOf', 'search'], true),
567         next_token,
568         option,
569         predefined,     // Global variables defined by option
570         prereg,
571         prev_token,
572         property,
573         protosymbol,
574         regexp_flag = array_to_object(['g', 'i', 'm'], true),
575         return_this = function return_this() {
576             return this;
577         },
578         rhino = array_to_object([
579             'defineClass', 'deserialize', 'gc', 'help', 'load', 'loadClass',
580             'print', 'quit', 'readFile', 'readUrl', 'runCommand', 'seal',
581             'serialize', 'spawn', 'sync', 'toint32', 'version'
582         ], false),
583 
584         scope,      // An object containing an object for each variable in scope
585         semicolon_coda = array_to_object([';', '"', '\'', ')'], true),
586 
587 // standard contains the global names that are provided by the
588 // ECMAScript standard.
589 
590         standard = array_to_object([
591             'Array', 'Boolean', 'Date', 'decodeURI', 'decodeURIComponent',
592             'encodeURI', 'encodeURIComponent', 'Error', 'eval', 'EvalError',
593             'Function', 'isFinite', 'isNaN', 'JSON', 'Map', 'Math', 'Number',
594             'Object', 'parseInt', 'parseFloat', 'Promise', 'Proxy',
595             'RangeError', 'ReferenceError', 'Reflect', 'RegExp', 'Set',
596             'String', 'Symbol', 'SyntaxError', 'System', 'TypeError',
597             'URIError', 'WeakMap', 'WeakSet'
598         ], false),
599 
600         strict_mode,
601         syntax = Object.create(null),
602         token,
603         tokens,
604         var_mode,
605         warnings,
606 
607 // Regular expressions. Some of these are stupidly long.
608 
609 // carriage return, carriage return linefeed, or linefeed
610         crlfx = /\r\n?|\n/,
611 // unsafe characters that are silently deleted by one or more browsers
612         cx = /[\u0000-\u0008\u000a-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/,
613 // identifier
614         ix = /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/,
615 // javascript url
616         jx = /^(?:javascript|jscript|ecmascript|vbscript)\s*:/i,
617 // star slash
618         lx = /\*\/|\/\*/,
619 // characters in strings that need escapement
620         nx = /[\u0000-\u001f'\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
621 // sync
622         syx = /Sync$/,
623 // comment todo
624         tox = /^\W*to\s*do(?:\W|$)/i,
625 // token
626         tx = /^\s*([(){}\[\]\?.,:;'"~#@`]|={1,3}|\/(\*(jslint|properties|property|members?|globals?)?|=|\/)?|\*[\/=]?|\+(?:=|\++)?|-(?:=|-+)?|[\^%]=?|&[&=]?|\|[|=]?|>{1,3}=?|<(?:[\/=!]|\!(\[|--)?|<=?)?|\!(\!|==?)?|[a-zA-Z_$][a-zA-Z0-9_$]*|[0-9]+(?:[xX][0-9a-fA-F]+|\.[0-9]*)?(?:[eE][+\-]?[0-9]+)?)/;
627 
628 
629     if (typeof String.prototype.entityify !== 'function') {
630         String.prototype.entityify = function () {
631             return this
632                 .replace(/&/g, '&')
633                 .replace(/</g, '<')
634                 .replace(/>/g, '>');
635         };
636     }
637 
638     if (typeof String.prototype.isAlpha !== 'function') {
639         String.prototype.isAlpha = function () {
640             return (this >= 'a' && this <= 'z\uffff') ||
641                 (this >= 'A' && this <= 'Z\uffff');
642         };
643     }
644 
645     if (typeof String.prototype.isDigit !== 'function') {
646         String.prototype.isDigit = function () {
647             return (this >= '0' && this <= '9');
648         };
649     }
650 
651     if (typeof String.prototype.supplant !== 'function') {
652         String.prototype.supplant = function (o) {
653             return this.replace(/\{([^{}]*)\}/g, function (a, b) {
654                 var replacement = o[b];
655                 return typeof replacement === 'string' ||
656                     typeof replacement === 'number' ? replacement : a;
657             });
658         };
659     }
660 
661 
662     function sanitize(a) {
663 
664 //  Escapify a troublesome character.
665 
666         return escapes[a] ||
667             '\\u' + ('0000' + a.charCodeAt().toString(16)).slice(-4);
668     }
669 
670 
671     function add_to_predefined(group) {
672         Object.keys(group).forEach(function (name) {
673             predefined[name] = group[name];
674         });
675     }
676 
677 
678     function assume() {
679         if (option.browser) {
680             add_to_predefined(browser);
681             option.browser = false;
682         }
683         if (option.closure) {
684             add_to_predefined(closure);
685         }
686         if (option.couch) {
687             add_to_predefined(couch);
688             option.couch = false;
689         }
690         if (option.devel) {
691             add_to_predefined(devel);
692             option.devel = false;
693         }
694         if (option.node) {
695             add_to_predefined(node);
696             option.node = false;
697             node_js = true;
698         }
699         if (option.rhino) {
700             add_to_predefined(rhino);
701             option.rhino = false;
702         }
703     }
704 
705 
706 // Produce an error warning.
707 
708     function artifact(tok) {
709         if (!tok) {
710             tok = next_token;
711         }
712         return tok.id === '(number)' ? tok.number : tok.string;
713     }
714 
715     function quit(message, line, character) {
716         throw {
717             name: 'JSLintError',
718             line: line,
719             character: character,
720             message: bundle.scanned_a_b.supplant({
721                 a: bundle[message] || message,
722                 b: Math.floor((line / lines.length) * 100)
723             })
724         };
725     }
726 
727     function warn(code, line, character, a, b, c, d) {
728         var warning = {         // ~~
729             id: '(error)',
730             raw: bundle[code] || code,
731             code: code,
732             evidence: lines[line - 1] || '',
733             line: line,
734             character: character,
735             a: a || artifact(this),
736             b: b,
737             c: c,
738             d: d
739         };
740         warning.reason = warning.raw.supplant(warning);
741         itself.errors.push(warning);
742         if (option.passfail) {
743             quit('stopping', line, character);
744         }
745         warnings += 1;
746         if (warnings >= option.maxerr) {
747             quit('too_many', line, character);
748         }
749         return warning;
750     }
751 
752     function stop(code, line, character, a, b, c, d) {
753         var warning = warn(code, line, character, a, b, c, d);
754         quit('stopping', warning.line, warning.character);
755     }
756 
757     function expected_at(at) {
758         if (!option.white && next_token.from !== at) {
759             next_token.warn('expected_a_at_b_c', '', at, next_token.from);
760         }
761     }
762 
763 // lexical analysis and token construction
764 
765     lex = (function lex() {
766         var character, c, from, length, line, pos, source_row;
767 
768 // Private lex methods
769 
770         function next_line() {
771             var at;
772             character = 1;
773             source_row = lines[line];
774             line += 1;
775             if (source_row === undefined) {
776                 return false;
777             }
778             at = source_row.search(/\t/);
779             if (at >= 0) {
780                 if (option.white) {
781                     source_row = source_row.replace(/\t/g, ' ');
782                 } else {
783                     warn('use_spaces', line, at + 1);
784                 }
785             }
786             at = source_row.search(cx);
787             if (at >= 0) {
788                 warn('unsafe', line, at);
789             }
790             if (option.maxlen && option.maxlen < source_row.length) {
791                 warn('too_long', line, source_row.length);
792             }
793             return true;
794         }
795 
796 // Produce a token object.  The token inherits from a syntax symbol.
797 
798         function it(type, value) {
799             var id, the_token;
800             if (type === '(string)') {
801                 if (jx.test(value)) {
802                     warn('url', line, from);
803                 }
804             }
805             the_token = Object.create(syntax[(
806                 type === '(punctuator)' || (type === '(identifier)' &&
807                         Object.prototype.hasOwnProperty.call(syntax, value))
808                     ? value
809                     : type
810             )] || syntax['(error)']);
811             if (type === '(identifier)') {
812                 the_token.identifier = true;
813                 if (value === '__iterator__' || value === '__proto__') {
814                     stop('reserved_a', line, from, value);
815                 } else if (!option.nomen &&
816                         (value.charAt(0) === '_' ||
817                         value.charAt(value.length - 1) === '_')) {
818                     warn('dangling_a', line, from, value);
819                 }
820             }
821             if (type === '(number)') {
822                 the_token.number = +value;
823             } else if (value !== undefined) {
824                 the_token.string = String(value);
825             }
826             the_token.line = line;
827             the_token.from = from;
828             the_token.thru = character;
829             if (comments.length) {
830                 the_token.comments = comments;
831                 comments = [];
832             }
833             id = the_token.id;
834             prereg = id && (
835                 ('(,=:[!&|?{};~+-*%^<>'.indexOf(id.charAt(id.length - 1)) >= 0) ||
836                 id === 'return' || id === 'case'
837             );
838             return the_token;
839         }
840 
841         function match(x) {
842             var exec = x.exec(source_row), first;
843             if (exec) {
844                 length = exec[0].length;
845                 first = exec[1];
846                 c = first.charAt(0);
847                 source_row = source_row.slice(length);
848                 from = character + length - first.length;
849                 character += length;
850                 return first;
851             }
852             for (;;) {
853                 if (!source_row) {
854                     if (!option.white) {
855                         warn('unexpected_char_a', line, character - 1, '(space)');
856                     }
857                     return;
858                 }
859                 c = source_row.charAt(0);
860                 if (c !== ' ') {
861                     break;
862                 }
863                 source_row = source_row.slice(1);
864                 character += 1;
865             }
866             stop('unexpected_char_a', line, character, c);
867 
868         }
869 
870         function string(x) {
871             var ch, at = 0, r = '', result;
872 
873             function hex(n) {
874                 var i = parseInt(source_row.substr(at + 1, n), 16);
875                 at += n;
876                 if (i >= 32 && i <= 126 &&
877                         i !== 34 && i !== 92 && i !== 39) {
878                     warn('unexpected_a', line, character, '\\');
879                 }
880                 character += n;
881                 ch = String.fromCharCode(i);
882             }
883 
884             if (json_mode && x !== '"') {
885                 warn('expected_a_b', line, character, '"', x);
886             }
887 
888             for (;;) {
889                 while (at >= source_row.length) {
890                     at = 0;
891                     if (!next_line()) {
892                         stop('unclosed', line - 1, from);
893                     }
894                 }
895                 ch = source_row.charAt(at);
896                 if (ch === x) {
897                     character += 1;
898                     source_row = source_row.slice(at + 1);
899                     result = it('(string)', r);
900                     result.quote = x;
901                     return result;
902                 }
903                 if (ch < ' ') {
904                     if (ch === '\n' || ch === '\r') {
905                         break;
906                     }
907                     warn('control_a', line, character + at,
908                         source_row.slice(0, at));
909                 } else if (ch === '\\') {
910                     at += 1;
911                     character += 1;
912                     ch = source_row.charAt(at);
913                     switch (ch) {
914                     case '':
915                         warn('unexpected_a', line, character, '\\');
916                         next_line();
917                         at = -1;
918                         break;
919                     case '\'':
920                         if (json_mode) {
921                             warn('unexpected_a', line, character, '\\\'');
922                         }
923                         break;
924                     case 'u':
925                         hex(4);
926                         break;
927                     case 'v':
928                         if (json_mode) {
929                             warn('unexpected_a', line, character, '\\v');
930                         }
931                         ch = '\v';
932                         break;
933                     case 'x':
934                         if (json_mode) {
935                             warn('unexpected_a', line, character, '\\x');
936                         }
937                         hex(2);
938                         break;
939                     default:
940                         if (typeof descapes[ch] !== 'string') {
941                             warn(ch >= '0' && ch <= '7' ? 'octal_a' : 'unexpected_a',
942                                 line, character, '\\' + ch);
943                         } else {
944                             ch = descapes[ch];
945                         }
946                     }
947                 }
948                 r += ch;
949                 character += 1;
950                 at += 1;
951             }
952         }
953 
954         function number(snippet) {
955             var digit;
956             if (source_row.charAt(0).isAlpha()) {
957                 warn('expected_space_a_b',
958                     line, character, c, source_row.charAt(0));
959             }
960             if (c === '0') {
961                 digit = snippet.charAt(1);
962                 if (digit.isDigit()) {
963                     if (token.id !== '.') {
964                         warn('unexpected_a', line, character, snippet);
965                     }
966                 } else if (json_mode && (digit === 'x' || digit === 'X')) {
967                     warn('unexpected_a', line, character, '0x');
968                 }
969             }
970             if (snippet.slice(snippet.length - 1) === '.') {
971                 warn('trailing_decimal_a', line, character, snippet);
972             }
973             digit = +snippet;
974             if (!isFinite(digit)) {
975                 warn('bad_number', line, character, snippet);
976             }
977             snippet = digit;
978             return it('(number)', snippet);
979         }
980 
981         function comment(snippet, type) {
982             if (comments_off) {
983                 warn('unexpected_comment', line, character);
984             } else if (!option.todo && tox.test(snippet)) {
985                 warn('todo_comment', line, character);
986             }
987             comments.push({
988                 id: type,
989                 from: from,
990                 thru: character,
991                 line: line,
992                 string: snippet
993             });
994         }
995 
996         function regexp() {
997             var at = 0,
998                 b,
999                 bit,
1000                 depth = 0,
1001                 flag = '',
1002                 high,
1003                 letter,
1004                 low,
1005                 potential,
1006                 quote,
1007                 result;
1008             for (;;) {
1009                 b = true;
1010                 c = source_row.charAt(at);
1011                 at += 1;
1012                 switch (c) {
1013                 case '':
1014                     stop('unclosed_regexp', line, from);
1015                     return;
1016                 case '/':
1017                     if (depth > 0) {
1018                         warn('unescaped_a', line, from + at, '/');
1019                     }
1020                     c = source_row.slice(0, at - 1);
1021                     potential = Object.create(regexp_flag);
1022                     for (;;) {
1023                         letter = source_row.charAt(at);
1024                         if (potential[letter] !== true) {
1025                             break;
1026                         }
1027                         potential[letter] = false;
1028                         at += 1;
1029                         flag += letter;
1030                     }
1031                     if (source_row.charAt(at).isAlpha()) {
1032                         stop('unexpected_a', line, from, source_row.charAt(at));
1033                     }
1034                     character += at;
1035                     source_row = source_row.slice(at);
1036                     quote = source_row.charAt(0);
1037                     if (quote === '/' || quote === '*') {
1038                         stop('confusing_regexp', line, from);
1039                     }
1040                     result = it('(regexp)', c);
1041                     result.flag = flag;
1042                     return result;
1043                 case '\\':
1044                     c = source_row.charAt(at);
1045                     if (c < ' ') {
1046                         warn('control_a', line, from + at, String(c));
1047                     } else if (c === '<') {
1048                         warn('unexpected_a', line, from + at, '\\');
1049                     }
1050                     at += 1;
1051                     break;
1052                 case '(':
1053                     depth += 1;
1054                     b = false;
1055                     if (source_row.charAt(at) === '?') {
1056                         at += 1;
1057                         switch (source_row.charAt(at)) {
1058                         case ':':
1059                         case '=':
1060                         case '!':
1061                             at += 1;
1062                             break;
1063                         default:
1064                             warn('expected_a_b', line, from + at,
1065                                 ':', source_row.charAt(at));
1066                         }
1067                     }
1068                     break;
1069                 case '|':
1070                     b = false;
1071                     break;
1072                 case ')':
1073                     if (depth === 0) {
1074                         warn('unescaped_a', line, from + at, ')');
1075                     } else {
1076                         depth -= 1;
1077                     }
1078                     break;
1079                 case ' ':
1080                     pos = 1;
1081                     while (source_row.charAt(at) === ' ') {
1082                         at += 1;
1083                         pos += 1;
1084                     }
1085                     if (pos > 1) {
1086                         warn('use_braces', line, from + at, pos);
1087                     }
1088                     break;
1089                 case '[':
1090                     c = source_row.charAt(at);
1091                     if (c === '^') {
1092                         at += 1;
1093                         if (!option.regexp) {
1094                             warn('insecure_a', line, from + at, c);
1095                         } else if (source_row.charAt(at) === ']') {
1096                             stop('unescaped_a', line, from + at, '^');
1097                         }
1098                     }
1099                     bit = false;
1100                     if (c === ']') {
1101                         warn('empty_class', line, from + at - 1);
1102                         bit = true;
1103                     }
1104 klass:              do {
1105                         c = source_row.charAt(at);
1106                         at += 1;
1107                         switch (c) {
1108                         case '[':
1109                         case '^':
1110                             warn('unescaped_a', line, from + at, c);
1111                             bit = true;
1112                             break;
1113                         case '-':
1114                             if (bit) {
1115                                 bit = false;
1116                             } else {
1117                                 warn('unescaped_a', line, from + at, '-');
1118                                 bit = true;
1119                             }
1120                             break;
1121                         case ']':
1122                             if (!bit) {
1123                                 warn('unescaped_a', line, from + at - 1, '-');
1124                             }
1125                             break klass;
1126                         case '\\':
1127                             c = source_row.charAt(at);
1128                             if (c < ' ') {
1129                                 warn('control_a', line, from + at, String(c));
1130                             } else if (c === '<') {
1131                                 warn('unexpected_a', line, from + at, '\\');
1132                             }
1133                             at += 1;
1134                             bit = true;
1135                             break;
1136                         case '/':
1137                             warn('unescaped_a', line, from + at - 1, '/');
1138                             bit = true;
1139                             break;
1140                         default:
1141                             bit = true;
1142                         }
1143                     } while (c);
1144                     break;
1145                 case '.':
1146                     if (!option.regexp) {
1147                         warn('insecure_a', line, from + at, c);
1148                     }
1149                     break;
1150                 case ']':
1151                 case '?':
1152                 case '{':
1153                 case '}':
1154                 case '+':
1155                 case '*':
1156                     warn('unescaped_a', line, from + at, c);
1157                     break;
1158                 }
1159                 if (b) {
1160                     switch (source_row.charAt(at)) {
1161                     case '?':
1162                     case '+':
1163                     case '*':
1164                         at += 1;
1165                         if (source_row.charAt(at) === '?') {
1166                             at += 1;
1167                         }
1168                         break;
1169                     case '{':
1170                         at += 1;
1171                         c = source_row.charAt(at);
1172                         if (c < '0' || c > '9') {
1173                             warn('expected_number_a', line,
1174                                 from + at, c);
1175                         }
1176                         at += 1;
1177                         low = +c;
1178                         for (;;) {
1179                             c = source_row.charAt(at);
1180                             if (c < '0' || c > '9') {
1181                                 break;
1182                             }
1183                             at += 1;
1184                             low = +c + (low * 10);
1185                         }
1186                         high = low;
1187                         if (c === ',') {
1188                             at += 1;
1189                             high = Infinity;
1190                             c = source_row.charAt(at);
1191                             if (c >= '0' && c <= '9') {
1192                                 at += 1;
1193                                 high = +c;
1194                                 for (;;) {
1195                                     c = source_row.charAt(at);
1196                                     if (c < '0' || c > '9') {
1197                                         break;
1198                                     }
1199                                     at += 1;
1200                                     high = +c + (high * 10);
1201                                 }
1202                             }
1203                         }
1204                         if (source_row.charAt(at) !== '}') {
1205                             warn('expected_a_b', line, from + at,
1206                                 '}', c);
1207                         } else {
1208                             at += 1;
1209                         }
1210                         if (source_row.charAt(at) === '?') {
1211                             at += 1;
1212                         }
1213                         if (low > high) {
1214                             warn('not_greater', line, from + at,
1215                                 low, high);
1216                         }
1217                         break;
1218                     }
1219                 }
1220             }
1221             c = source_row.slice(0, at - 1);
1222             character += at;
1223             source_row = source_row.slice(at);
1224             return it('(regexp)', c);
1225         }
1226 
1227 // Public lex methods
1228 
1229         return {
1230             init: function (source) {
1231                 if (typeof source === 'string') {
1232                     lines = source.split(crlfx);
1233                 } else {
1234                     lines = source;
1235                 }
1236                 line = 0;
1237                 next_line();
1238                 from = 1;
1239             },
1240 
1241 // token -- this is called by advance to get the next token.
1242 
1243             token: function () {
1244                 var first, i, snippet;
1245 
1246                 for (;;) {
1247                     while (!source_row) {
1248                         if (!next_line()) {
1249                             return it('(end)');
1250                         }
1251                     }
1252                     snippet = match(tx);
1253                     if (snippet) {
1254 
1255 //      identifier
1256 
1257                         first = snippet.charAt(0);
1258                         if (first.isAlpha() || first === '_' || first === '$') {
1259                             return it('(identifier)', snippet);
1260                         }
1261 
1262 //      number
1263 
1264                         if (first.isDigit()) {
1265                             return number(snippet);
1266                         }
1267                         switch (snippet) {
1268 
1269 //      string
1270 
1271                         case '"':
1272                         case "'":
1273                             return string(snippet);
1274 
1275 //      // comment
1276 
1277                         case '//':
1278                             comment(source_row, '//');
1279                             source_row = '';
1280                             break;
1281 
1282 //      /* comment
1283 
1284                         case '/*':
1285                             for (;;) {
1286                                 i = source_row.search(lx);
1287                                 if (i >= 0) {
1288                                     break;
1289                                 }
1290                                 character = source_row.length;
1291                                 comment(source_row);
1292                                 from = 0;
1293                                 if (!next_line()) {
1294                                     stop('unclosed_comment', line, character);
1295                                 }
1296                             }
1297                             comment(source_row.slice(0, i), '/*');
1298                             character += i + 2;
1299                             if (source_row.charAt(i) === '/') {
1300                                 stop('nested_comment', line, character);
1301                             }
1302                             source_row = source_row.slice(i + 2);
1303                             break;
1304 
1305                         case '':
1306                             break;
1307 //      /
1308                         case '/':
1309                             if (token.id === '/=') {
1310                                 stop('slash_equal', line, from);
1311                             }
1312                             return prereg
1313                                 ? regexp()
1314                                 : it('(punctuator)', snippet);
1315 
1316 //      punctuator
1317                         default:
1318                             return it('(punctuator)', snippet);
1319                         }
1320                     }
1321                 }
1322             }
1323         };
1324     }());
1325 
1326     function define(kind, token) {
1327 
1328 // Define a name.
1329 
1330         var name = token.string,
1331             master = scope[name];       // The current definition of the name
1332 
1333 // vars are created with a deadzone, so that the expression that initializes
1334 // the var cannot access the var. Functions are not writeable.
1335 
1336         token.dead = false;
1337         token.init = false;
1338         token.kind = kind;
1339         token.master = master;
1340         token.used = 0;
1341         token.writeable = true;
1342 
1343 // Global variables are a little weird. They can be defined multiple times.
1344 // Some predefined global vars are (or should) not be writeable.
1345 
1346         if (kind === 'var' && funct === global_funct) {
1347             if (!master) {
1348                 if (predefined[name] === false) {
1349                     token.writeable = false;
1350                 }
1351                 global_scope[name] = token;
1352             }
1353         } else {
1354 
1355 // It is an error if the name has already been defined in this scope, except
1356 // when reusing an exception variable name.
1357 
1358             if (master && !option.defined) {
1359                 if (master.function === funct) {
1360                     if (master.kind !== 'exception' || kind !== 'exception' ||
1361                             !master.dead) {
1362                         token.warn('already_defined', name);
1363                     }
1364                 } else if (master.function !== global_funct) {
1365                     if (kind === 'var') {
1366                         token.warn('redefinition_a_b', name, master.line);
1367                     }
1368                 }
1369             }
1370             scope[name] = token;
1371             if (kind === 'var') {
1372                 block_var.push(name);
1373             }
1374         }
1375     }
1376 
1377     function peek(distance) {
1378 
1379 // Peek ahead to a future token. The distance is how far ahead to look. The
1380 // default is the next token.
1381 
1382         var found, slot = 0;
1383 
1384         distance = distance || 0;
1385         while (slot <= distance) {
1386             found = lookahead[slot];
1387             if (!found) {
1388                 found = lookahead[slot] = lex.token();
1389             }
1390             slot += 1;
1391         }
1392         return found;
1393     }
1394 
1395 
1396     function advance(id, match) {
1397 
1398 // Produce the next token, also looking for programming errors.
1399 
1400         if (indent) {
1401 
1402 // If indentation checking was requested, then inspect all of the line breakings.
1403 // The var statement is tricky because the names might be aligned or not. We
1404 // look at the first line break after the var to determine the programmer's
1405 // intention.
1406 
1407             if (var_mode && next_token.line !== token.line) {
1408                 if ((var_mode !== indent || !next_token.edge) &&
1409                         next_token.from === indent.at -
1410                         (next_token.edge ? option.indent : 0)) {
1411                     var dent = indent;
1412                     for (;;) {
1413                         dent.at -= option.indent;
1414                         if (dent === var_mode) {
1415                             break;
1416                         }
1417                         dent = dent.was;
1418                     }
1419                     dent.open = false;
1420                 }
1421                 var_mode = null;
1422             }
1423             if (next_token.id === '?' && indent.mode === ':' &&
1424                     token.line !== next_token.line) {
1425                 indent.at -= option.indent;
1426             }
1427             if (indent.open) {
1428 
1429 // If the token is an edge.
1430 
1431                 if (next_token.edge) {
1432                     if (next_token.edge === 'label') {
1433                         expected_at(1);
1434                     } else if (next_token.edge === 'case' || indent.mode === 'statement') {
1435                         expected_at(indent.at - option.indent);
1436                     } else if (indent.mode !== 'array' || next_token.line !== token.line) {
1437                         expected_at(indent.at);
1438                     }
1439 
1440 // If the token is not an edge, but is the first token on the line.
1441 
1442                 } else if (next_token.line !== token.line) {
1443                     if (next_token.from < indent.at + (indent.mode ===
1444                             'expression' ? 0 : option.indent)) {
1445                         expected_at(indent.at + option.indent);
1446                     }
1447                     indent.wrap = true;
1448                 }
1449             } else if (next_token.line !== token.line) {
1450                 if (next_token.edge) {
1451                     expected_at(indent.at);
1452                 } else {
1453                     indent.wrap = true;
1454                     if (indent.mode === 'statement' || indent.mode === 'var') {
1455                         expected_at(indent.at + option.indent);
1456                     } else if (next_token.from < indent.at + (indent.mode ===
1457                             'expression' ? 0 : option.indent)) {
1458                         expected_at(indent.at + option.indent);
1459                     }
1460                 }
1461             }
1462         }
1463 
1464         switch (token.id) {
1465         case '(number)':
1466             if (next_token.id === '.') {
1467                 next_token.warn('trailing_decimal_a');
1468             }
1469             break;
1470         case '-':
1471             if (next_token.id === '-' || next_token.id === '--') {
1472                 next_token.warn('confusing_a');
1473             }
1474             break;
1475         case '+':
1476             if (next_token.id === '+' || next_token.id === '++') {
1477                 next_token.warn('confusing_a');
1478             }
1479             break;
1480         }
1481         if (token.id === '(string)' || token.identifier) {
1482             anonname = token.string;
1483         }
1484 
1485         if (id && next_token.id !== id) {
1486             if (match) {
1487                 next_token.warn('expected_a_b_from_c_d', id,
1488                     match.id, match.line, artifact());
1489             } else if (!next_token.identifier || next_token.string !== id) {
1490                 next_token.warn('expected_a_b', id, artifact());
1491             }
1492         }
1493         prev_token = token;
1494         token = next_token;
1495         next_token = lookahead.shift() || lex.token();
1496         next_token.function = funct;
1497         tokens.push(next_token);
1498     }
1499 
1500 
1501     function do_globals() {
1502         var name, writeable;
1503         for (;;) {
1504             if (next_token.id !== '(string)' && !next_token.identifier) {
1505                 return;
1506             }
1507             name = next_token.string;
1508             advance();
1509             writeable = false;
1510             if (next_token.id === ':') {
1511                 advance(':');
1512                 switch (next_token.id) {
1513                 case 'true':
1514                     writeable = predefined[name] !== false;
1515                     advance('true');
1516                     break;
1517                 case 'false':
1518                     advance('false');
1519                     break;
1520                 default:
1521                     next_token.stop('unexpected_a');
1522                 }
1523             }
1524             predefined[name] = writeable;
1525             if (next_token.id !== ',') {
1526                 return;
1527             }
1528             advance(',');
1529         }
1530     }
1531 
1532 
1533     function do_jslint() {
1534         var name, value;
1535         while (next_token.id === '(string)' || next_token.identifier) {
1536             name = next_token.string;
1537             if (!allowed_option[name]) {
1538                 next_token.stop('unexpected_a');
1539             }
1540             advance();
1541             if (next_token.id !== ':') {
1542                 next_token.stop('expected_a_b', ':', artifact());
1543             }
1544             advance(':');
1545             if (typeof allowed_option[name] === 'number') {
1546                 value = next_token.number;
1547                 if (value > allowed_option[name] || value <= 0 ||
1548                         Math.floor(value) !== value) {
1549                     next_token.stop('expected_small_a');
1550                 }
1551                 option[name] = value;
1552             } else {
1553                 if (next_token.id === 'true') {
1554                     option[name] = true;
1555                 } else if (next_token.id === 'false') {
1556                     option[name] = false;
1557                 } else {
1558                     next_token.stop('unexpected_a');
1559                 }
1560             }
1561             advance();
1562             if (next_token.id === ',') {
1563                 advance(',');
1564             }
1565         }
1566         assume();
1567     }
1568 
1569 
1570     function do_properties() {
1571         var name;
1572         option.properties = true;
1573         for (;;) {
1574             if (next_token.id !== '(string)' && !next_token.identifier) {
1575                 return;
1576             }
1577             name = next_token.string;
1578             advance();
1579             if (next_token.id === ':') {
1580                 for (;;) {
1581                     advance();
1582                     if (next_token.id !== '(string)' && !next_token.identifier) {
1583                         break;
1584                     }
1585                 }
1586             }
1587             property[name] = 0;
1588             if (next_token.id !== ',') {
1589                 return;
1590             }
1591             advance(',');
1592         }
1593     }
1594 
1595 
1596     directive = function directive() {
1597         var command = this.id,
1598             old_comments_off = comments_off,
1599             old_indent = indent;
1600         comments_off = true;
1601         indent = null;
1602         if (next_token.line === token.line && next_token.from === token.thru) {
1603             next_token.warn('missing_space_a_b', artifact(token), artifact());
1604         }
1605         if (lookahead.length > 0) {
1606             this.warn('unexpected_a');
1607         }
1608         switch (command) {
1609         case '/*properties':
1610         case '/*property':
1611         case '/*members':
1612         case '/*member':
1613             do_properties();
1614             break;
1615         case '/*jslint':
1616             do_jslint();
1617             break;
1618         case '/*globals':
1619         case '/*global':
1620             do_globals();
1621             break;
1622         default:
1623             this.stop('unexpected_a');
1624         }
1625         comments_off = old_comments_off;
1626         advance('*/');
1627         indent = old_indent;
1628     };
1629 
1630 
1631 // Indentation intention
1632 
1633     function edge(mode) {
1634         next_token.edge = indent ? indent.open && (mode || 'edge') : '';
1635     }
1636 
1637 
1638     function step_in(mode) {
1639         var open;
1640         if (typeof mode === 'number') {
1641             indent = {
1642                 at: +mode,
1643                 open: true,
1644                 was: indent
1645             };
1646         } else if (!indent) {
1647             indent = {
1648                 at: 1,
1649                 mode: 'statement',
1650                 open: true
1651             };
1652         } else if (mode === 'statement') {
1653             indent = {
1654                 at: indent.at,
1655                 open: true,
1656                 was: indent
1657             };
1658         } else {
1659             open = mode === 'var' || next_token.line !== token.line;
1660             indent = {
1661                 at: (open || mode === 'control'
1662                     ? indent.at + option.indent
1663                     : indent.at) + (indent.wrap ? option.indent : 0),
1664                 mode: mode,
1665                 open: open,
1666                 was: indent
1667             };
1668             if (mode === 'var' && open) {
1669                 var_mode = indent;
1670             }
1671         }
1672     }
1673 
1674     function step_out(id, symbol) {
1675         if (id) {
1676             if (indent && indent.open) {
1677                 indent.at -= option.indent;
1678                 edge();
1679             }
1680             advance(id, symbol);
1681         }
1682         if (indent) {
1683             indent = indent.was;
1684         }
1685     }
1686 
1687 // Functions for conformance of whitespace.
1688 
1689     function one_space(left, right) {
1690         left = left || token;
1691         right = right || next_token;
1692         if (right.id !== '(end)' && !option.white &&
1693                 (token.line !== right.line ||
1694                 token.thru + 1 !== right.from)) {
1695             right.warn('expected_space_a_b', artifact(token), artifact(right));
1696         }
1697     }
1698 
1699     function one_space_only(left, right) {
1700         left = left || token;
1701         right = right || next_token;
1702         if (right.id !== '(end)' && (left.line !== right.line ||
1703                 (!option.white && left.thru + 1 !== right.from))) {
1704             right.warn('expected_space_a_b', artifact(left), artifact(right));
1705         }
1706     }
1707 
1708     function no_space(left, right) {
1709         left = left || token;
1710         right = right || next_token;
1711         if ((!option.white) &&
1712                 left.thru !== right.from && left.line === right.line) {
1713             if (!(option.closure && right.comments.length === 1
1714                   && right.comments[0].string.substr(0, 7) === '*@type{')) {
1715                 right.warn('unexpected_space_a_b', artifact(left),
1716                            artifact(right));
1717             }
1718         }
1719     }
1720 
1721     function no_space_only(left, right) {
1722         left = left || token;
1723         right = right || next_token;
1724         if (right.id !== '(end)' && (left.line !== right.line ||
1725                 (!option.white && left.thru !== right.from))) {
1726             right.warn('unexpected_space_a_b', artifact(left), artifact(right));
1727         }
1728     }
1729 
1730     function spaces(left, right) {
1731         if (!option.white) {
1732             left = left || token;
1733             right = right || next_token;
1734             if (left.thru === right.from && left.line === right.line) {
1735                 right.warn('missing_space_a_b', artifact(left), artifact(right));
1736             }
1737         }
1738     }
1739 
1740     function comma() {
1741         if (next_token.id !== ',') {
1742             warn('expected_a_b', token.line, token.thru, ',', artifact());
1743         } else {
1744             if (!option.white) {
1745                 no_space_only();
1746             }
1747             advance(',');
1748             spaces();
1749         }
1750     }
1751 
1752 
1753     function semicolon() {
1754         if (next_token.id !== ';') {
1755             warn('expected_a_b', token.line, token.thru, ';', artifact());
1756         } else {
1757             if (!option.white) {
1758                 no_space_only();
1759             }
1760             advance(';');
1761             if (semicolon_coda[next_token.id] !== true) {
1762                 spaces();
1763             }
1764         }
1765     }
1766 
1767     function use_strict() {
1768         if (next_token.string === 'use strict') {
1769             if (strict_mode) {
1770                 next_token.warn('unnecessary_use');
1771             }
1772             edge();
1773             advance();
1774             semicolon();
1775             strict_mode = true;
1776             return true;
1777         }
1778         return false;
1779     }
1780 
1781 
1782     function are_similar(a, b) {
1783         if (a === b) {
1784             return true;
1785         }
1786         if (Array.isArray(a)) {
1787             if (Array.isArray(b) && a.length === b.length) {
1788                 var i;
1789                 for (i = 0; i < a.length; i += 1) {
1790                     if (!are_similar(a[i], b[i])) {
1791                         return false;
1792                     }
1793                 }
1794                 return true;
1795             }
1796             return false;
1797         }
1798         if (Array.isArray(b)) {
1799             return false;
1800         }
1801         if (a.id === '(number)' && b.id === '(number)') {
1802             return a.number === b.number;
1803         }
1804         if (a.arity === b.arity && a.string === b.string) {
1805             switch (a.arity) {
1806             case undefined:
1807                 return a.string === b.string;
1808             case 'prefix':
1809             case 'suffix':
1810                 return a.id === b.id && are_similar(a.first, b.first) &&
1811                     a.id !== '{' && a.id !== '[';
1812             case 'infix':
1813                 return are_similar(a.first, b.first) &&
1814                     are_similar(a.second, b.second);
1815             case 'ternary':
1816                 return are_similar(a.first, b.first) &&
1817                     are_similar(a.second, b.second) &&
1818                     are_similar(a.third, b.third);
1819             case 'function':
1820             case 'regexp':
1821                 return false;
1822             default:
1823                 return true;
1824             }
1825         }
1826         if (a.id === '.' && b.id === '[' && b.arity === 'infix') {
1827             return a.second.string === b.second.string && b.second.id === '(string)';
1828         }
1829         if (a.id === '[' && a.arity === 'infix' && b.id === '.') {
1830             return a.second.string === b.second.string && a.second.id === '(string)';
1831         }
1832         return false;
1833     }
1834 
1835 
1836 // This is the heart of JSLINT, the Pratt parser. In addition to parsing, it
1837 // is looking for ad hoc lint patterns. We add .fud to Pratt's model, which is
1838 // like .nud except that it is only used on the first token of a statement.
1839 // Having .fud makes it much easier to define statement-oriented languages like
1840 // JavaScript. I retained Pratt's nomenclature.
1841 
1842 // .nud     Null denotation
1843 // .fud     First null denotation
1844 // .led     Left denotation
1845 //  lbp     Left binding power
1846 //  rbp     Right binding power
1847 
1848 // They are elements of the parsing method called Top Down Operator Precedence.
1849 
1850     function expression(rbp, initial) {
1851 
1852 // rbp is the right binding power.
1853 // initial indicates that this is the first expression of a statement.
1854 
1855         var left;
1856         if (next_token.id === '(end)') {
1857             token.stop('unexpected_a', next_token.id);
1858         }
1859         advance();
1860         if (initial) {
1861             anonname = 'anonymous';
1862         }
1863         if (initial === true && token.fud) {
1864             left = token.fud();
1865         } else {
1866             if (token.nud) {
1867                 left = token.nud();
1868             } else {
1869                 if (next_token.id === '(number)' && token.id === '.') {
1870                     token.warn('leading_decimal_a', artifact());
1871                     advance();
1872                     return token;
1873                 }
1874                 token.stop('expected_identifier_a', artifact(token));
1875             }
1876             while (rbp < next_token.lbp) {
1877                 advance();
1878                 left = token.led(left);
1879             }
1880         }
1881         if (left && left.assign && !initial) {
1882             if (!option.ass) {
1883                 left.warn('assignment_expression');
1884             }
1885             if (left.id !== '=' && left.first.master) {
1886                 left.first.master.used = true;
1887             }
1888         }
1889         return left;
1890     }
1891 
1892     protosymbol = {
1893         nud: function () {
1894             this.stop('unexpected_a');
1895         },
1896         led: function () {
1897             this.stop('expected_operator_a');
1898         },
1899         warn: function (code, a, b, c, d) {
1900             if (!this.warning) {
1901                 this.warning = warn(code, this.line || 0, this.from || 0,
1902                     a || artifact(this), b, c, d);
1903             }
1904         },
1905         stop: function (code, a, b, c, d) {
1906             this.warning = undefined;
1907             this.warn(code, a, b, c, d);
1908             return quit('stopping', this.line, this.character);
1909         },
1910         lbp: 0
1911     };
1912 
1913 // Functional constructors for making the symbols that will be inherited by
1914 // tokens.
1915 
1916     function symbol(s, bp) {
1917         var x = syntax[s];
1918         if (!x) {
1919             x = Object.create(protosymbol);
1920             x.id = x.string = s;
1921             x.lbp = bp || 0;
1922             syntax[s] = x;
1923         }
1924         return x;
1925     }
1926 
1927     function postscript(x) {
1928         x.postscript = true;
1929         return x;
1930     }
1931 
1932     function ultimate(s) {
1933         var x = symbol(s, 0);
1934         x.from = 1;
1935         x.thru = 1;
1936         x.line = 0;
1937         x.edge = 'edge';
1938         x.string = s;
1939         return postscript(x);
1940     }
1941 
1942     function reserve_name(x) {
1943         var c = x.id.charAt(0);
1944         if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
1945             x.identifier = x.reserved = true;
1946         }
1947         return x;
1948     }
1949 
1950     function stmt(s, f) {
1951         var x = symbol(s);
1952         x.fud = f;
1953         return reserve_name(x);
1954     }
1955 
1956     function disrupt_stmt(s, f) {
1957         var x = stmt(s, f);
1958         x.disrupt = true;
1959     }
1960 
1961     function labeled_stmt(s, f) {
1962         var x = stmt(s, function labeled() {
1963             var the_statement;
1964             if (funct.breakage) {
1965                 funct.breakage.push(this);
1966             } else {
1967                 funct.breakage = [this];
1968             }
1969             the_statement = f.apply(this);
1970             if (funct.breakage.length > 1) {
1971                 funct.breakage.pop();
1972             } else {
1973                 delete funct.breakage;
1974             }
1975             return the_statement;
1976         });
1977         x.labeled = true;
1978     }
1979 
1980     function prefix(s, f) {
1981         var x = symbol(s, 150);
1982         reserve_name(x);
1983         x.nud = function () {
1984             var that = this;
1985             that.arity = 'prefix';
1986             if (typeof f === 'function') {
1987                 that = f(that);
1988                 if (that.arity !== 'prefix') {
1989                     return that;
1990                 }
1991             } else {
1992                 if (s === 'typeof') {
1993                     one_space();
1994                 } else {
1995                     no_space_only();
1996                 }
1997                 that.first = expression(150);
1998             }
1999             switch (that.id) {
2000             case '++':
2001             case '--':
2002                 if (!option.plusplus) {
2003                     that.warn('unexpected_a');
2004                 } else if ((!that.first.identifier || that.first.reserved) &&
2005                         that.first.id !== '.' && that.first.id !== '[') {
2006                     that.warn('bad_operand');
2007                 }
2008                 break;
2009             default:
2010                 if (that.first.arity === 'prefix' ||
2011                         that.first.arity === 'function') {
2012                     that.warn('unexpected_a');
2013                 }
2014             }
2015             return that;
2016         };
2017         return x;
2018     }
2019 
2020 
2021     function type(s, t, nud) {
2022         var x = symbol(s);
2023         x.arity = t;
2024         if (nud) {
2025             x.nud = nud;
2026         }
2027         return x;
2028     }
2029 
2030 
2031     function reserve(s, f) {
2032         var x = symbol(s);
2033         x.identifier = x.reserved = true;
2034         if (typeof f === 'function') {
2035             x.nud = f;
2036         }
2037         return x;
2038     }
2039 
2040 
2041     function constant(name) {
2042         var x = reserve(name);
2043         x.string = name;
2044         x.nud = return_this;
2045         return x;
2046     }
2047 
2048 
2049     function reservevar(s, v) {
2050         return reserve(s, function () {
2051             if (typeof v === 'function') {
2052                 v(this);
2053             }
2054             return this;
2055         });
2056     }
2057 
2058 
2059     function infix(s, p, f, w) {
2060         var x = symbol(s, p);
2061         reserve_name(x);
2062         x.led = function (left) {
2063             this.arity = 'infix';
2064             if (!w) {
2065                 spaces(prev_token, token);
2066                 spaces();
2067             }
2068             if (!option.bitwise && this.bitwise) {
2069                 this.warn('unexpected_a');
2070             }
2071             if (typeof f === 'function') {
2072                 return f(left, this);
2073             }
2074             this.first = left;
2075             this.second = expression(p);
2076             return this;
2077         };
2078         return x;
2079     }
2080 
2081     function expected_relation(node, message) {
2082         if (node.assign) {
2083             node.warn(message || 'conditional_assignment');
2084         }
2085         return node;
2086     }
2087 
2088     function expected_condition(node, message) {
2089         switch (node.id) {
2090         case '[':
2091         case '-':
2092             if (node.arity !== 'infix') {
2093                 node.warn(message || 'weird_condition');
2094             }
2095             break;
2096         case 'false':
2097         case 'function':
2098         case 'Infinity':
2099         case 'NaN':
2100         case 'null':
2101         case 'true':
2102         case 'undefined':
2103         case 'void':
2104         case '(number)':
2105         case '(regexp)':
2106         case '(string)':
2107         case '{':
2108         case '?':
2109         case '~':
2110             node.warn(message || 'weird_condition');
2111             break;
2112         case '(':
2113             if (node.first.id === 'new' ||
2114                     (node.first.string === 'Boolean') ||
2115                     (node.first.id === '.' &&
2116                         numbery[node.first.second.string] === true)) {
2117                 node.warn(message || 'weird_condition');
2118             }
2119             break;
2120         }
2121         return node;
2122     }
2123 
2124     function check_relation(node) {
2125         switch (node.arity) {
2126         case 'prefix':
2127             switch (node.id) {
2128             case '{':
2129             case '[':
2130                 node.warn('unexpected_a');
2131                 break;
2132             case '!':
2133                 node.warn('confusing_a');
2134                 break;
2135             }
2136             break;
2137         case 'function':
2138         case 'regexp':
2139             node.warn('unexpected_a');
2140             break;
2141         default:
2142             if (node.id  === 'NaN') {
2143                 node.warn('isNaN');
2144             } else if (node.relation) {
2145                 node.warn('weird_relation');
2146             }
2147         }
2148         return node;
2149     }
2150 
2151 
2152     function relation(s, eqeq) {
2153         var x = infix(s, 100, function (left, that) {
2154             check_relation(left);
2155             if (eqeq && !option.eqeq) {
2156                 that.warn('expected_a_b', eqeq, that.id);
2157             }
2158             var right = expression(100);
2159             if (are_similar(left, right) ||
2160                     ((left.id === '(string)' || left.id === '(number)') &&
2161                     (right.id === '(string)' || right.id === '(number)'))) {
2162                 that.warn('weird_relation');
2163             } else if (left.id === 'typeof') {
2164                 if (right.id !== '(string)') {
2165                     right.warn("expected_string_a", artifact(right));
2166                 } else if (right.string === 'undefined' ||
2167                         right.string === 'null') {
2168                     left.warn("unexpected_typeof_a", right.string);
2169                 }
2170             } else if (right.id === 'typeof') {
2171                 if (left.id !== '(string)') {
2172                     left.warn("expected_string_a", artifact(left));
2173                 } else if (left.string === 'undefined' ||
2174                         left.string === 'null') {
2175                     right.warn("unexpected_typeof_a", left.string);
2176                 }
2177             }
2178             that.first = left;
2179             that.second = check_relation(right);
2180             return that;
2181         });
2182         x.relation = true;
2183         return x;
2184     }
2185 
2186     function lvalue(that, s) {
2187         var master;
2188         if (that.identifier) {
2189             master = scope[that.string];
2190             if (master) {
2191                 if (scope[that.string].writeable !== true) {
2192                     that.warn('read_only');
2193                 }
2194                 master.used -= 1;
2195                 if (s === '=') {
2196                     master.init = true;
2197                 }
2198             } else if (that.reserved) {
2199                 that.warn('expected_identifier_a_reserved');
2200             }
2201         } else if (that.id === '.' || that.id === '[') {
2202             if (!that.first || that.first.string === 'arguments') {
2203                 that.warn('bad_assignment');
2204             }
2205         } else {
2206             that.warn('bad_assignment');
2207         }
2208     }
2209 
2210 
2211     function assignop(s, op) {
2212         var x = infix(s, 20, function (left, that) {
2213             var next;
2214             that.first = left;
2215             lvalue(left, s);
2216             that.second = expression(20);
2217             if (that.id === '=' && are_similar(that.first, that.second)) {
2218                 that.warn('weird_assignment');
2219             }
2220             next = that;
2221             while (next_token.id === '=') {
2222                 lvalue(next.second, '=');
2223                 next_token.first = next.second;
2224                 next.second = next_token;
2225                 next = next_token;
2226                 advance('=');
2227                 next.second = expression(20);
2228             }
2229             return that;
2230         });
2231         x.assign = true;
2232         if (op) {
2233             if (syntax[op].bitwise) {
2234                 x.bitwise = true;
2235             }
2236         }
2237         return x;
2238     }
2239 
2240 
2241     function bitwise(s, p) {
2242         var x = infix(s, p, 'number');
2243         x.bitwise = true;
2244         return x;
2245     }
2246 
2247 
2248     function suffix(s) {
2249         var x = symbol(s, 150);
2250         x.led = function (left) {
2251             no_space_only(prev_token, token);
2252             if (!option.plusplus) {
2253                 this.warn('unexpected_a');
2254             } else if ((!left.identifier || left.reserved) &&
2255                     left.id !== '.' && left.id !== '[') {
2256                 this.warn('bad_operand');
2257             }
2258             this.first = left;
2259             this.arity = 'suffix';
2260             return this;
2261         };
2262         return x;
2263     }
2264 
2265 
2266     function optional_identifier(variable) {
2267         if (next_token.identifier) {
2268             advance();
2269             if (token.reserved && variable) {
2270                 token.warn('expected_identifier_a_reserved');
2271             }
2272             return token.string;
2273         }
2274     }
2275 
2276 
2277     function identifier(variable) {
2278         var i = optional_identifier(variable);
2279         if (!i) {
2280             next_token.stop(token.id === 'function' && next_token.id === '('
2281                 ? 'name_function'
2282                 : 'expected_identifier_a');
2283         }
2284         return i;
2285     }
2286 
2287 
2288     function statement() {
2289 
2290         var label, preamble, the_statement;
2291 
2292 // We don't like the empty statement.
2293 
2294         if (next_token.id === ';') {
2295             next_token.warn('unexpected_a');
2296             semicolon();
2297             return;
2298         }
2299 
2300 // Is this a labeled statement?
2301 
2302         if (next_token.identifier && !next_token.reserved && peek().id === ':') {
2303             edge('label');
2304             label = next_token;
2305             advance();
2306             advance(':');
2307             define('label', label);
2308             if (next_token.labeled !== true || funct === global_funct) {
2309                 label.stop('unexpected_label_a');
2310             } else if (jx.test(label.string + ':')) {
2311                 label.warn('url');
2312             }
2313             next_token.label = label;
2314             label.init = true;
2315             label.statement = next_token;
2316         }
2317 
2318 // Parse the statement.
2319 
2320         preamble = next_token;
2321         if (token.id !== 'else') {
2322             edge();
2323         }
2324         step_in('statement');
2325         the_statement = expression(0, true);
2326         if (the_statement) {
2327 
2328 // Look for the final semicolon.
2329 
2330             if (the_statement.arity === 'statement') {
2331                 if (the_statement.id === 'switch' ||
2332                         (the_statement.block && the_statement.id !== 'do')) {
2333                     spaces();
2334                 } else {
2335                     semicolon();
2336                 }
2337             } else {
2338 
2339 // If this is an expression statement, determine if it is acceptable.
2340 // We do not like
2341 //      new Blah;
2342 // statements. If it is to be used at all, new should only be used to make
2343 // objects, not side effects. The expression statements we do like do
2344 // assignment or invocation or delete.
2345 
2346                 if (the_statement.id === '(') {
2347                     if (the_statement.first.id === 'new') {
2348                         next_token.warn('bad_new');
2349                     }
2350                 } else if (the_statement.id === '++' ||
2351                         the_statement.id === '--') {
2352                     lvalue(the_statement.first);
2353                 } else if (!the_statement.assign &&
2354                         the_statement.id !== 'delete') {
2355                     if (!option.closure || !preamble.comments) {
2356                         preamble.warn('assignment_function_expression');
2357                     }
2358                 }
2359                 semicolon();
2360             }
2361         }
2362         step_out();
2363         if (label) {
2364             label.dead = true;
2365         }
2366         return the_statement;
2367     }
2368 
2369 
2370     function statements() {
2371         var array = [], disruptor, the_statement;
2372 
2373 // A disrupt statement may not be followed by any other statement.
2374 // If the last statement is disrupt, then the sequence is disrupt.
2375 
2376         while (next_token.postscript !== true) {
2377             if (next_token.id === ';') {
2378                 next_token.warn('unexpected_a');
2379                 semicolon();
2380             } else {
2381                 if (next_token.string === 'use strict') {
2382                     if ((!node_js) || funct !== global_funct || array.length > 0) {
2383                         next_token.warn('function_strict');
2384                     }
2385                     use_strict();
2386                 }
2387                 if (disruptor) {
2388                     next_token.warn('unreachable_a_b', next_token.string,
2389                         disruptor.string);
2390                     disruptor = null;
2391                 }
2392                 the_statement = statement();
2393                 if (the_statement) {
2394                     array.push(the_statement);
2395                     if (the_statement.disrupt) {
2396                         disruptor = the_statement;
2397                         array.disrupt = true;
2398                     }
2399                 }
2400             }
2401         }
2402         return array;
2403     }
2404 
2405 
2406     function block(kind) {
2407 
2408 // A block is a sequence of statements wrapped in braces.
2409 
2410         var array,
2411             curly = next_token,
2412             old_block_var = block_var,
2413             old_in_block = in_block,
2414             old_strict_mode = strict_mode;
2415 
2416         in_block = kind !== 'function' && kind !== 'try' && kind !== 'catch';
2417         block_var = [];
2418         if (curly.id === '{') {
2419             spaces();
2420             advance('{');
2421             step_in();
2422             if (kind === 'function' && !use_strict() && !old_strict_mode &&
2423                     !option.sloppy && funct.level === 1) {
2424                 next_token.warn('missing_use_strict');
2425             }
2426             array = statements();
2427             strict_mode = old_strict_mode;
2428             step_out('}', curly);
2429         } else if (in_block) {
2430             curly.stop('expected_a_b', '{', artifact());
2431         } else {
2432             curly.warn('expected_a_b', '{', artifact());
2433             array = [statement()];
2434             array.disrupt = array[0].disrupt;
2435         }
2436         if (!(option.emptyblock || option.debug) && kind !== 'catch' && array.length === 0) {
2437             curly.warn('empty_block');
2438         }
2439         block_var.forEach(function (name) {
2440             scope[name].dead = true;
2441         });
2442         block_var = old_block_var;
2443         in_block = old_in_block;
2444         return array;
2445     }
2446 
2447 
2448     function tally_property(name) {
2449         if (option.properties && typeof property[name] !== 'number') {
2450             token.warn('unexpected_property_a', name);
2451         }
2452         if (property[name]) {
2453             property[name] += 1;
2454         } else {
2455             property[name] = 1;
2456         }
2457     }
2458 
2459 
2460 // ECMAScript parser
2461 
2462     (function () {
2463         var x = symbol('(identifier)');
2464         x.nud = function () {
2465             var name = this.string,
2466                 master = scope[name],
2467                 writeable;
2468 
2469 // If the master is not in scope, then we may have an undeclared variable.
2470 // Check the predefined list. If it was predefined, create the global
2471 // variable.
2472 
2473             if (!master) {
2474                 writeable = predefined[name];
2475                 if (typeof writeable === 'boolean') {
2476                     global_scope[name] = master = {
2477                         dead: false,
2478                         function: global_funct,
2479                         kind: 'var',
2480                         string: name,
2481                         writeable: writeable
2482                     };
2483 
2484 // But if the variable is not in scope, and is not predefined, and if we are not
2485 // in the global scope, then we have an undefined variable error.
2486 
2487                 } else {
2488                     token.warn('used_before_a');
2489                 }
2490             } else {
2491                 this.master = master;
2492             }
2493 
2494 // Annotate uses that cross scope boundaries.
2495 
2496             if (master) {
2497                 if (master.kind === 'label') {
2498                     this.warn('a_label');
2499                 } else {
2500                     if (master.dead === true || master.dead === funct) {
2501                         this.warn('a_scope');
2502                     }
2503                     master.used += 1;
2504                     if (master.function !== funct) {
2505                         if (master.function === global_funct) {
2506                             funct.global.push(name);
2507                         } else {
2508                             master.function.closure.push(name);
2509                             funct.outer.push(name);
2510                         }
2511                     }
2512                 }
2513             }
2514             return this;
2515         };
2516         x.identifier = true;
2517     }());
2518 
2519 
2520 // Build the syntax table by declaring the syntactic elements.
2521 
2522     type('(array)', 'array');
2523     type('(function)', 'function');
2524     type('(number)', 'number', return_this);
2525     type('(object)', 'object');
2526     type('(string)', 'string', return_this);
2527     type('(boolean)', 'boolean', return_this);
2528     type('(regexp)', 'regexp', return_this);
2529 
2530     ultimate('(begin)');
2531     ultimate('(end)');
2532     ultimate('(error)');
2533     postscript(symbol('}'));
2534     symbol(')');
2535     symbol(']');
2536     postscript(symbol('"'));
2537     postscript(symbol('\''));
2538     symbol(';');
2539     symbol(':');
2540     symbol(',');
2541     symbol('#');
2542     symbol('@');
2543     symbol('*/');
2544     postscript(reserve('case'));
2545     reserve('catch');
2546     postscript(reserve('default'));
2547     reserve('else');
2548     reserve('finally');
2549 
2550     reservevar('arguments', function (x) {
2551         if (strict_mode && funct === global_funct) {
2552             x.warn('strict');
2553         }
2554         funct.arguments = true;
2555     });
2556     reservevar('eval');
2557     constant('false', 'boolean');
2558     constant('Infinity', 'number');
2559     constant('NaN', 'number');
2560     constant('null', '');
2561     reservevar('this', function (x) {
2562         if (strict_mode && funct.statement && funct.name.charAt(0) > 'Z') {
2563             x.warn('strict');
2564         }
2565     });
2566     constant('true', 'boolean');
2567     constant('undefined', '');
2568 
2569     infix('?', 30, function (left, that) {
2570         step_in('?');
2571         that.first = expected_condition(expected_relation(left));
2572         that.second = expression(0);
2573         spaces();
2574         step_out();
2575         var colon = next_token;
2576         advance(':');
2577         step_in(':');
2578         spaces();
2579         that.third = expression(10);
2580         that.arity = 'ternary';
2581         if (are_similar(that.second, that.third)) {
2582             colon.warn('weird_ternary');
2583         } else if (are_similar(that.first, that.second)) {
2584             that.warn('use_or');
2585         }
2586         step_out();
2587         return that;
2588     });
2589 
2590     infix('||', 40, function (left, that) {
2591         function paren_check(that) {
2592             if (that.id === '&&' && !that.paren) {
2593                 that.warn('and');
2594             }
2595             return that;
2596         }
2597 
2598         that.first = paren_check(expected_condition(expected_relation(left)));
2599         that.second = paren_check(expected_relation(expression(40)));
2600         if (are_similar(that.first, that.second)) {
2601             that.warn('weird_condition');
2602         }
2603         return that;
2604     });
2605 
2606     infix('&&', 50, function (left, that) {
2607         that.first = expected_condition(expected_relation(left));
2608         that.second = expected_relation(expression(50));
2609         if (are_similar(that.first, that.second)) {
2610             that.warn('weird_condition');
2611         }
2612         return that;
2613     });
2614 
2615     prefix('void', function (that) {
2616         that.first = expression(0);
2617         that.warn('expected_a_b', 'undefined', 'void');
2618         return that;
2619     });
2620 
2621     bitwise('|', 70);
2622     bitwise('^', 80);
2623     bitwise('&', 90);
2624 
2625     relation('==', '===');
2626     relation('===');
2627     relation('!=', '!==');
2628     relation('!==');
2629     relation('<');
2630     relation('>');
2631     relation('<=');
2632     relation('>=');
2633 
2634     bitwise('<<', 120);
2635     bitwise('>>', 120);
2636     bitwise('>>>', 120);
2637 
2638     infix('in', 120, function (left, that) {
2639         that.warn('infix_in');
2640         that.left = left;
2641         that.right = expression(130);
2642         return that;
2643     });
2644     infix('instanceof', 120);
2645     infix('+', 130, function (left, that) {
2646         if (left.id === '(number)') {
2647             if (left.number === 0) {
2648                 left.warn('unexpected_a', '0');
2649             }
2650         } else if (left.id === '(string)') {
2651             if (left.string === '') {
2652                 left.warn('expected_a_b', 'String', '\'\'');
2653             }
2654         }
2655         var right = expression(130);
2656         if (right.id === '(number)') {
2657             if (right.number === 0) {
2658                 right.warn('unexpected_a', '0');
2659             }
2660         } else if (right.id === '(string)') {
2661             if (right.string === '') {
2662                 right.warn('expected_a_b', 'String', '\'\'');
2663             }
2664         }
2665         if (left.id === right.id) {
2666             if (left.id === '(string)' || left.id === '(number)') {
2667                 if (left.id === '(string)') {
2668                     left.string += right.string;
2669                     if (jx.test(left.string)) {
2670                         left.warn('url');
2671                     }
2672                 } else {
2673                     left.number += right.number;
2674                 }
2675                 left.thru = right.thru;
2676                 return left;
2677             }
2678         }
2679         that.first = left;
2680         that.second = right;
2681         return that;
2682     });
2683     prefix('+');
2684     prefix('+++', function () {
2685         token.warn('confusing_a');
2686         this.first = expression(150);
2687         this.arity = 'prefix';
2688         return this;
2689     });
2690     infix('+++', 130, function (left) {
2691         token.warn('confusing_a');
2692         this.first = left;
2693         this.second = expression(130);
2694         return this;
2695     });
2696     infix('-', 130, function (left, that) {
2697         if ((left.id === '(number)' && left.number === 0) || left.id === '(string)') {
2698             left.warn('unexpected_a');
2699         }
2700         var right = expression(130);
2701         if ((right.id === '(number)' && right.number === 0) || right.id === '(string)') {
2702             right.warn('unexpected_a');
2703         }
2704         if (left.id === right.id && left.id === '(number)') {
2705             left.number -= right.number;
2706             left.thru = right.thru;
2707             return left;
2708         }
2709         that.first = left;
2710         that.second = right;
2711         return that;
2712     });
2713     prefix('-');
2714     prefix('---', function () {
2715         token.warn('confusing_a');
2716         this.first = expression(150);
2717         this.arity = 'prefix';
2718         return this;
2719     });
2720     infix('---', 130, function (left) {
2721         token.warn('confusing_a');
2722         this.first = left;
2723         this.second = expression(130);
2724         return this;
2725     });
2726     infix('*', 140, function (left, that) {
2727         if ((left.id === '(number)' && (left.number === 0 || left.number === 1)) || left.id === '(string)') {
2728             left.warn('unexpected_a');
2729         }
2730         var right = expression(140);
2731         if ((right.id === '(number)' && (right.number === 0 || right.number === 1)) || right.id === '(string)') {
2732             right.warn('unexpected_a');
2733         }
2734         if (left.id === right.id && left.id === '(number)') {
2735             left.number *= right.number;
2736             left.thru = right.thru;
2737             return left;
2738         }
2739         that.first = left;
2740         that.second = right;
2741         return that;
2742     });
2743     infix('/', 140, function (left, that) {
2744         if ((left.id === '(number)' && left.number === 0) || left.id === '(string)') {
2745             left.warn('unexpected_a');
2746         }
2747         var right = expression(140);
2748         if ((right.id === '(number)' && (right.number === 0 || right.number === 1)) || right.id === '(string)') {
2749             right.warn('unexpected_a');
2750         }
2751         if (left.id === right.id && left.id === '(number)') {
2752             left.number /= right.number;
2753             left.thru = right.thru;
2754             return left;
2755         }
2756         that.first = left;
2757         that.second = right;
2758         return that;
2759     });
2760     infix('%', 140, function (left, that) {
2761         if ((left.id === '(number)' && (left.number === 0 || left.number === 1)) || left.id === '(string)') {
2762             left.warn('unexpected_a');
2763         }
2764         var right = expression(140);
2765         if ((right.id === '(number)' && right.number === 0) || right.id === '(string)') {
2766             right.warn('unexpected_a');
2767         }
2768         if (left.id === right.id && left.id === '(number)') {
2769             left.number %= right.number;
2770             left.thru = right.thru;
2771             return left;
2772         }
2773         that.first = left;
2774         that.second = right;
2775         return that;
2776     });
2777 
2778     suffix('++');
2779     prefix('++');
2780 
2781     suffix('--');
2782     prefix('--');
2783     prefix('delete', function (that) {
2784         one_space();
2785         var p = expression(0);
2786         if (!p || (p.id !== '.' && p.id !== '[')) {
2787             next_token.warn('deleted');
2788         }
2789         that.first = p;
2790         return that;
2791     });
2792 
2793 
2794     prefix('~', function (that) {
2795         no_space_only();
2796         if (!option.bitwise) {
2797             that.warn('unexpected_a');
2798         }
2799         that.first = expression(150);
2800         return that;
2801     });
2802     function banger(that) {
2803         no_space_only();
2804         that.first = expected_condition(expression(150));
2805         if (bang[that.first.id] === that || that.first.assign) {
2806             that.warn('confusing_a');
2807         }
2808         return that;
2809     }
2810     prefix('!', banger);
2811     prefix('!!', banger);
2812     prefix('typeof');
2813     prefix('new', function (that) {
2814         one_space();
2815         var c = expression(160), n, p, v;
2816         that.first = c;
2817         if (c.id !== 'function') {
2818             if (c.identifier) {
2819                 switch (c.string) {
2820                 case 'Object':
2821                     token.warn('use_object');
2822                     break;
2823                 case 'Array':
2824                     if (next_token.id === '(') {
2825                         p = next_token;
2826                         p.first = this;
2827                         advance('(');
2828                         if (next_token.id !== ')') {
2829                             n = expression(0);
2830                             p.second = [n];
2831                             if (n.id === '(string)' || next_token.id === ',') {
2832                                 p.warn('use_array');
2833                             }
2834                             while (next_token.id === ',') {
2835                                 advance(',');
2836                                 p.second.push(expression(0));
2837                             }
2838                         } else {
2839                             token.warn('use_array');
2840                         }
2841                         advance(')', p);
2842                         return p;
2843                     }
2844                     token.warn('use_array');
2845                     break;
2846                 case 'Number':
2847                 case 'String':
2848                 case 'Boolean':
2849                 case 'Math':
2850                 case 'JSON':
2851                     c.warn('not_a_constructor');
2852                     break;
2853                 case 'Function':
2854                     if (!option.evil) {
2855                         next_token.warn('function_eval');
2856                     }
2857                     break;
2858                 case 'Date':
2859                 case 'RegExp':
2860                 case 'this':
2861                     break;
2862                 default:
2863                     if (c.id !== 'function') {
2864                         v = c.string.charAt(0);
2865                         if (!option.newcap && (v < 'A' || v > 'Z')) {
2866                             token.warn('constructor_name_a');
2867                         }
2868                     }
2869                 }
2870             } else {
2871                 if (c.id !== '.' && c.id !== '[' && c.id !== '(') {
2872                     token.warn('bad_constructor');
2873                 }
2874             }
2875         } else {
2876             that.warn('weird_new');
2877         }
2878         if (next_token.id !== '(') {
2879             next_token.warn('missing_a', '()');
2880         }
2881         return that;
2882     });
2883 
2884     infix('(', 160, function (left, that) {
2885         var e, p;
2886         if (indent && indent.mode === 'expression') {
2887             no_space(prev_token, token);
2888         } else {
2889             no_space_only(prev_token, token);
2890         }
2891         if (!left.immed && left.id === 'function') {
2892             next_token.warn('wrap_immediate');
2893         }
2894         p = [];
2895         if (left.identifier) {
2896             if (left.string.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)) {
2897                 if (left.string !== 'Number' && left.string !== 'String' &&
2898                         left.string !== 'Boolean' && left.string !== 'Date') {
2899                     if (left.string === 'Math') {
2900                         left.warn('not_a_function');
2901                     } else if (left.string === 'Object') {
2902                         token.warn('use_object');
2903                     } else if (left.string === 'Array' || !option.newcap) {
2904                         left.warn('missing_a', 'new');
2905                     }
2906                 }
2907             } else if (left.string === 'JSON') {
2908                 left.warn('not_a_function');
2909             }
2910         } else if (left.id === '.') {
2911             if (left.second.string === 'split' &&
2912                     left.first.id === '(string)') {
2913                 left.second.warn('use_array');
2914             }
2915         }
2916         step_in();
2917         if (next_token.id !== ')') {
2918             no_space();
2919             for (;;) {
2920                 edge();
2921                 e = expression(10);
2922                 if (left.string === 'Boolean' && (e.id === '!' || e.id === '~')) {
2923                     e.warn('weird_condition');
2924                 }
2925                 p.push(e);
2926                 if (next_token.id !== ',') {
2927                     break;
2928                 }
2929                 comma();
2930             }
2931         }
2932         no_space();
2933         step_out(')', that);
2934         if (typeof left === 'object') {
2935             if (left.string === 'parseInt' && p.length === 1) {
2936                 left.warn('radix');
2937             } else if (left.string === 'String' && p.length >= 1 && p[0].id === '(string)') {
2938                 left.warn('unexpected_a');
2939             }
2940             if (!option.evil) {
2941                 if (left.string === 'eval' || left.string === 'Function' ||
2942                         left.string === 'execScript') {
2943                     left.warn('evil');
2944                 } else if (p[0] && p[0].id === '(string)' &&
2945                         (left.string === 'setTimeout' ||
2946                         left.string === 'setInterval')) {
2947                     left.warn('implied_evil');
2948                 }
2949             }
2950             if (!left.identifier && left.id !== '.' && left.id !== '[' &&
2951                     left.id !== '(' && left.id !== '&&' && left.id !== '||' &&
2952                     left.id !== '?') {
2953                 left.warn('bad_invocation');
2954             }
2955             if (left.id === '.') {
2956                 if (p.length > 0 &&
2957                         left.first && left.first.first &&
2958                         are_similar(p[0], left.first.first)) {
2959                     if (left.second.string === 'call' ||
2960                             (left.second.string === 'apply' && (p.length === 1 ||
2961                             (p[1].arity === 'prefix' && p[1].id === '[')))) {
2962                         left.second.warn('unexpected_a');
2963                     }
2964                 }
2965                 if (left.second.string === 'toString') {
2966                     if (left.first.id === '(string)' || left.first.id === '(number)') {
2967                         left.second.warn('unexpected_a');
2968                     }
2969                 }
2970             }
2971         }
2972         that.first = left;
2973         that.second = p;
2974         return that;
2975     }, true);
2976 
2977     prefix('(', function (that) {
2978         step_in('expression');
2979         no_space();
2980         edge();
2981         if (next_token.id === 'function') {
2982             next_token.immed = true;
2983         }
2984         var value = expression(0);
2985         value.paren = true;
2986         no_space();
2987         step_out(')', that);
2988         if (value.id === 'function') {
2989             switch (next_token.id) {
2990             case '(':
2991                 next_token.warn('move_invocation');
2992                 break;
2993             case '.':
2994             case '[':
2995                 next_token.warn('unexpected_a');
2996                 break;
2997             default:
2998                 that.warn('bad_wrap');
2999             }
3000         } else if (!value.arity) {
3001             if (!option.closure || !that.comments) {
3002                 that.warn('unexpected_a');
3003             }
3004         }
3005         return value;
3006     });
3007 
3008     infix('.', 170, function (left, that) {
3009         no_space(prev_token, token);
3010         no_space();
3011         var name = identifier();
3012         if (typeof name === 'string') {
3013             tally_property(name);
3014         }
3015         that.first = left;
3016         that.second = token;
3017         if (left && left.string === 'arguments' &&
3018                 (name === 'callee' || name === 'caller')) {
3019             left.warn('avoid_a', 'arguments.' + name);
3020         } else if (!option.evil && left && left.string === 'document' &&
3021                 (name === 'write' || name === 'writeln')) {
3022             left.warn('write_is_wrong');
3023         } else if (!option.stupid && syx.test(name)) {
3024             token.warn('sync_a');
3025         } else if (left && left.id === '{') {
3026             that.warn('unexpected_a');
3027         }
3028         if (!option.evil && (name === 'eval' || name === 'execScript')) {
3029             next_token.warn('evil');
3030         }
3031         return that;
3032     }, true);
3033 
3034     infix('[', 170, function (left, that) {
3035         var e, s;
3036         no_space_only(prev_token, token);
3037         no_space();
3038         step_in();
3039         edge();
3040         e = expression(0);
3041         switch (e.id) {
3042         case '(number)':
3043             if (e.id === '(number)' && left.id === 'arguments') {
3044                 left.warn('use_param');
3045             }
3046             break;
3047         case '(string)':
3048             if (!option.evil &&
3049                     (e.string === 'eval' || e.string === 'execScript')) {
3050                 e.warn('evil');
3051             } else if (!option.sub && ix.test(e.string)) {
3052                 s = syntax[e.string];
3053                 if (!s || !s.reserved) {
3054                     e.warn('subscript');
3055                 }
3056             }
3057             tally_property(e.string);
3058             break;
3059         }
3060         if (left && (left.id === '{' || (left.id === '[' && left.arity === 'prefix'))) {
3061             that.warn('unexpected_a');
3062         }
3063         step_out(']', that);
3064         no_space(prev_token, token);
3065         that.first = left;
3066         that.second = e;
3067         return that;
3068     }, true);
3069 
3070     prefix('[', function (that) {
3071         that.first = [];
3072         step_in('array');
3073         while (next_token.id !== '(end)') {
3074             while (next_token.id === ',') {
3075                 next_token.warn('unexpected_a');
3076                 advance(',');
3077             }
3078             if (next_token.id === ']') {
3079                 break;
3080             }
3081             indent.wrap = false;
3082             edge();
3083             that.first.push(expression(10));
3084             if (next_token.id === ',') {
3085                 comma();
3086                 if (next_token.id === ']') {
3087                     token.warn('unexpected_a');
3088                     break;
3089                 }
3090             } else {
3091                 break;
3092             }
3093         }
3094         step_out(']', that);
3095         return that;
3096     }, 170);
3097 
3098 
3099     function property_name() {
3100         var id = optional_identifier();
3101         if (!id) {
3102             if (next_token.id === '(string)') {
3103                 id = next_token.string;
3104                 advance();
3105             } else if (next_token.id === '(number)') {
3106                 id = next_token.number.toString();
3107                 advance();
3108             }
3109         }
3110         return id;
3111     }
3112 
3113 
3114 
3115     assignop('=');
3116     assignop('+=', '+');
3117     assignop('-=', '-');
3118     assignop('*=', '*');
3119     assignop('/=', '/').nud = function () {
3120         next_token.stop('slash_equal');
3121     };
3122     assignop('%=', '%');
3123     assignop('&=', '&');
3124     assignop('|=', '|');
3125     assignop('^=', '^');
3126     assignop('<<=', '<<');
3127     assignop('>>=', '>>');
3128     assignop('>>>=', '>>>');
3129 
3130     function function_parameters() {
3131         var id, parameters = [], paren = next_token;
3132         advance('(');
3133         token.function = funct;
3134         step_in();
3135         no_space();
3136         if (next_token.id !== ')') {
3137             for (;;) {
3138                 edge();
3139                 id = identifier();
3140                 if (token.reserved) {
3141                     token.warn('expected_identifier_a_reserved');
3142                 }
3143                 define('parameter', token);
3144                 parameters.push(id);
3145                 token.init = true;
3146                 token.writeable = true;
3147                 if (next_token.id !== ',') {
3148                     break;
3149                 }
3150                 comma();
3151             }
3152         }
3153         no_space();
3154         step_out(')', paren);
3155         return parameters;
3156     }
3157 
3158     function do_function(func, name) {
3159         var old_funct = funct,
3160             old_option = option,
3161             old_scope = scope;
3162         scope = Object.create(old_scope);
3163         funct = {
3164             closure: [],
3165             global: [],
3166             level: old_funct.level + 1,
3167             line: next_token.line,
3168             loopage: 0,
3169             name: name || '\'' + (anonname || '').replace(nx, sanitize) + '\'',
3170             outer: [],
3171             scope: scope
3172         };
3173         funct.parameter = function_parameters();
3174         func.function = funct;
3175         option = Object.create(old_option);
3176         functions.push(funct);
3177         if (name) {
3178             func.name = name;
3179             func.string = name;
3180             define('function', func);
3181             func.init = true;
3182             func.used += 1;
3183         }
3184         func.writeable = false;
3185         one_space();
3186         func.block = block('function');
3187         Object.keys(scope).forEach(function (name) {
3188             var master = scope[name];
3189             if (!master.used && master.kind !== 'exception' &&
3190                     ((master.kind === 'var' && !option.unvar)
3191                     || (master.kind === 'parameter' && !option.unparam))) {
3192                 master.warn('unused_a');
3193             } else if (!master.init && (master.kind !== 'var' || !option.unvar)) {
3194                 master.warn('uninitialized_a');
3195             }
3196         });
3197         funct = old_funct;
3198         option = old_option;
3199         scope = old_scope;
3200     }
3201 
3202     prefix('{', function (that) {
3203         var get, i, j, name, set, seen = Object.create(null);
3204         that.first = [];
3205         step_in();
3206         while (next_token.id !== '}') {
3207             indent.wrap = false;
3208 
3209 // JSLint recognizes the ES5 extension for get/set in object literals,
3210 // but requires that they be used in pairs.
3211 
3212             edge();
3213             if (next_token.string === 'get' && peek().id !== ':') {
3214                 get = next_token;
3215                 advance('get');
3216                 one_space_only();
3217                 name = next_token;
3218                 i = property_name();
3219                 if (!i) {
3220                     next_token.stop('missing_property');
3221                 }
3222                 get.string = '';
3223                 do_function(get);
3224                 if (funct.loopage) {
3225                     get.warn('function_loop');
3226                 }
3227                 if (get.function.parameter.length) {
3228                     get.warn('parameter_a_get_b', get.function.parameter[0], i);
3229                 }
3230                 comma();
3231                 set = next_token;
3232                 spaces();
3233                 edge();
3234                 advance('set');
3235                 set.string = '';
3236                 one_space_only();
3237                 j = property_name();
3238                 if (i !== j) {
3239                     token.stop('expected_a_b', i, j || next_token.string);
3240                 }
3241                 do_function(set);
3242                 if (set.block.length === 0) {
3243                     token.warn('missing_a', 'throw');
3244                 }
3245                 if (set.function.parameter.length === 0) {
3246                     set.stop('parameter_set_a', 'value');
3247                 } else if (set.function.parameter[0] !== 'value') {
3248                     set.stop('expected_a_b', 'value',
3249                         set.function.parameter[0]);
3250                 }
3251                 name.first = [get, set];
3252             } else {
3253                 name = next_token;
3254                 i = property_name();
3255                 if (typeof i !== 'string') {
3256                     next_token.stop('missing_property');
3257                 }
3258                 advance(':');
3259                 spaces();
3260                 name.first = expression(10);
3261             }
3262             that.first.push(name);
3263             if (seen[i] === true) {
3264                 next_token.warn('duplicate_a', i);
3265             }
3266             seen[i] = true;
3267             tally_property(i);
3268             if (next_token.id !== ',') {
3269                 break;
3270             }
3271             for (;;) {
3272                 comma();
3273                 if (next_token.id !== ',') {
3274                     break;
3275                 }
3276                 next_token.warn('unexpected_a');
3277             }
3278             if (next_token.id === '}') {
3279                 token.warn('unexpected_a');
3280             }
3281         }
3282         step_out('}', that);
3283         return that;
3284     });
3285 
3286     stmt('{', function () {
3287         next_token.warn('statement_block');
3288         this.arity = 'statement';
3289         this.block = statements();
3290         this.disrupt = this.block.disrupt;
3291         advance('}', this);
3292         return this;
3293     });
3294 
3295     stmt('/*global', directive);
3296     stmt('/*globals', directive);
3297     stmt('/*jslint', directive);
3298     stmt('/*member', directive);
3299     stmt('/*members', directive);
3300     stmt('/*property', directive);
3301     stmt('/*properties', directive);
3302 
3303     stmt('var', function () {
3304 
3305 // JavaScript does not have block scope. It only has function scope. So,
3306 // declaring a variable in a block can have unexpected consequences.
3307 
3308 // var.first will contain an array, the array containing name tokens
3309 // and assignment tokens.
3310 
3311         var assign, id, name;
3312 
3313         if (funct.loopage) {
3314             next_token.warn('var_loop');
3315         } else if (funct.varstatement && !option.vars) {
3316             next_token.warn('combine_var');
3317         }
3318         if (funct !== global_funct) {
3319             funct.varstatement = true;
3320         }
3321         this.arity = 'statement';
3322         this.first = [];
3323         step_in('var');
3324         for (;;) {
3325             name = next_token;
3326             id = identifier(true);
3327             define('var', name);
3328             name.dead = funct;
3329             if (next_token.id === '=') {
3330                 if (funct === global_funct && !name.writeable) {
3331                     name.warn('read_only');
3332                 }
3333                 assign = next_token;
3334                 assign.first = name;
3335                 spaces();
3336                 advance('=');
3337                 spaces();
3338                 if (next_token.id === 'undefined') {
3339                     token.warn('unnecessary_initialize', id);
3340                 }
3341                 if (peek(0).id === '=' && next_token.identifier) {
3342                     next_token.stop('var_a_not');
3343                 }
3344                 assign.second = expression(0);
3345                 assign.arity = 'infix';
3346                 name.init = true;
3347                 this.first.push(assign);
3348             } else {
3349                 this.first.push(name);
3350             }
3351             name.dead = false;
3352             name.writeable = true;
3353             if (next_token.id !== ',') {
3354                 break;
3355             }
3356             comma();
3357             indent.wrap = false;
3358             if (var_mode && next_token.line === token.line &&
3359                     this.first.length === 1) {
3360                 var_mode = null;
3361                 indent.open = false;
3362                 indent.at -= option.indent;
3363             }
3364             spaces();
3365             edge();
3366         }
3367         var_mode = null;
3368         step_out();
3369         return this;
3370     });
3371 
3372     stmt('function', function () {
3373         one_space();
3374         if (in_block) {
3375             token.warn('function_block');
3376         }
3377         var name = next_token,
3378             id = identifier(true);
3379         define('var', name);
3380         if (!name.writeable) {
3381             name.warn('read_only');
3382         }
3383         name.init = true;
3384         name.statement = true;
3385         no_space();
3386         this.arity = 'statement';
3387         do_function(this, id);
3388         if (next_token.id === '(' && next_token.line === token.line) {
3389             next_token.stop('function_statement');
3390         }
3391         return this;
3392     });
3393 
3394     prefix('function', function (that) {
3395         var id = optional_identifier(true), name;
3396         if (id) {
3397             name = token;
3398             no_space();
3399         } else {
3400             id = '';
3401             one_space();
3402         }
3403         do_function(that, id);
3404         if (name) {
3405             name.function = that.function;
3406         }
3407         if (funct.loopage) {
3408             that.warn('function_loop');
3409         }
3410         switch (next_token.id) {
3411         case ';':
3412         case '(':
3413         case ')':
3414         case ',':
3415         case ']':
3416         case '}':
3417         case ':':
3418         case '(end)':
3419             break;
3420         case '.':
3421             if (peek().string !== 'bind' || peek(1).id !== '(') {
3422                 next_token.warn('unexpected_a');
3423             }
3424             break;
3425         default:
3426             next_token.stop('unexpected_a');
3427         }
3428         that.arity = 'function';
3429         return that;
3430     });
3431 
3432     stmt('if', function () {
3433         var paren = next_token;
3434         one_space();
3435         advance('(');
3436         step_in('control');
3437         no_space();
3438         edge();
3439         this.arity = 'statement';
3440         this.first = expected_condition(expected_relation(expression(0)));
3441         no_space();
3442         step_out(')', paren);
3443         one_space();
3444         this.block = block('if');
3445         if (next_token.id === 'else') {
3446             if (this.block.disrupt) {
3447                 next_token.warn(this.elif ? 'use_nested_if' : 'unnecessary_else');
3448             }
3449             one_space();
3450             advance('else');
3451             one_space();
3452             if (next_token.id === 'if') {
3453                 next_token.elif = true;
3454                 this.else = statement(true);
3455             } else {
3456                 this.else = block('else');
3457             }
3458             if (this.else.disrupt && this.block.disrupt) {
3459                 this.disrupt = true;
3460             }
3461         }
3462         return this;
3463     });
3464 
3465     stmt('try', function () {
3466 
3467 // try.first    The catch variable
3468 // try.second   The catch clause
3469 // try.third    The finally clause
3470 // try.block    The try block
3471 
3472         var exception_variable, paren;
3473         one_space();
3474         this.arity = 'statement';
3475         this.block = block('try');
3476         if (next_token.id === 'catch') {
3477             one_space();
3478             advance('catch');
3479             one_space();
3480             paren = next_token;
3481             advance('(');
3482             step_in('control');
3483             no_space();
3484             edge();
3485             exception_variable = next_token;
3486             this.first = identifier();
3487             define('exception', exception_variable);
3488             exception_variable.init = true;
3489             no_space();
3490             step_out(')', paren);
3491             one_space();
3492             this.second = block('catch');
3493             if (this.second.length) {
3494                 if (this.first === 'ignore') {
3495                     exception_variable.warn('unexpected_a');
3496                 }
3497             } else {
3498                 if (this.first !== 'ignore') {
3499                     exception_variable.warn('expected_a_b', 'ignore',
3500                         exception_variable.string);
3501                 }
3502             }
3503             exception_variable.dead = true;
3504         }
3505         if (next_token.id === 'finally') {
3506             one_space();
3507             advance('finally');
3508             one_space();
3509             this.third = block('finally');
3510         } else if (!this.second) {
3511             next_token.stop('expected_a_b', 'catch', artifact());
3512         }
3513         return this;
3514     });
3515 
3516     labeled_stmt('while', function () {
3517         one_space();
3518         var paren = next_token;
3519         funct.loopage += 1;
3520         advance('(');
3521         step_in('control');
3522         no_space();
3523         edge();
3524         this.arity = 'statement';
3525         this.first = expected_relation(expression(0));
3526         if (this.first.id !== 'true') {
3527             expected_condition(this.first, 'unexpected_a');
3528         }
3529         no_space();
3530         step_out(')', paren);
3531         one_space();
3532         this.block = block('while');
3533         if (this.block.disrupt) {
3534             prev_token.warn('strange_loop');
3535         }
3536         funct.loopage -= 1;
3537         return this;
3538     });
3539 
3540     reserve('with');
3541 
3542     labeled_stmt('switch', function () {
3543 
3544 // switch.first         the switch expression
3545 // switch.second        the array of cases. A case is 'case' or 'default' token:
3546 //    case.first        the array of case expressions
3547 //    case.second       the array of statements
3548 // If all of the arrays of statements are disrupt, then the switch is disrupt.
3549 
3550         var cases = [],
3551             old_in_block = in_block,
3552             particular,
3553             that = token,
3554             the_case = next_token;
3555 
3556         function find_duplicate_case(value) {
3557             if (are_similar(particular, value)) {
3558                 value.warn('duplicate_a');
3559             }
3560         }
3561 
3562         one_space();
3563         advance('(');
3564         no_space();
3565         step_in();
3566         this.arity = 'statement';
3567         this.first = expected_condition(expected_relation(expression(0)));
3568         no_space();
3569         step_out(')', the_case);
3570         one_space();
3571         advance('{');
3572         step_in();
3573         in_block = true;
3574         this.second = [];
3575         if (that.from !== next_token.from && !option.white) {
3576             next_token.warn('expected_a_at_b_c', next_token.string, that.from, next_token.from);
3577         }
3578         while (next_token.id === 'case') {
3579             the_case = next_token;
3580             the_case.first = [];
3581             the_case.arity = 'case';
3582             for (;;) {
3583                 spaces();
3584                 edge('case');
3585                 advance('case');
3586                 one_space();
3587                 particular = expression(0);
3588                 cases.forEach(find_duplicate_case);
3589                 cases.push(particular);
3590                 the_case.first.push(particular);
3591                 if (particular.id === 'NaN') {
3592                     particular.warn('unexpected_a');
3593                 }
3594                 no_space_only();
3595                 advance(':');
3596                 if (next_token.id !== 'case') {
3597                     break;
3598                 }
3599             }
3600             spaces();
3601             the_case.second = statements();
3602             if (the_case.second && the_case.second.length > 0) {
3603                 if (!the_case.second[the_case.second.length - 1].disrupt) {
3604                     next_token.warn('missing_a_after_b', 'break', 'case');
3605                 }
3606             } else {
3607                 next_token.warn('empty_case');
3608             }
3609             this.second.push(the_case);
3610         }
3611         if (this.second.length === 0) {
3612             next_token.warn('missing_a', 'case');
3613         }
3614         if (next_token.id === 'default') {
3615             spaces();
3616             the_case = next_token;
3617             the_case.arity = 'case';
3618             edge('case');
3619             advance('default');
3620             no_space_only();
3621             advance(':');
3622             spaces();
3623             the_case.second = statements();
3624             if (the_case.second && the_case.second.length > 0) {
3625                 this.disrupt = the_case.second[the_case.second.length - 1].disrupt;
3626             } else {
3627                 the_case.warn('empty_case');
3628             }
3629             this.second.push(the_case);
3630         }
3631         if (this.break) {
3632             this.disrupt = false;
3633         }
3634         spaces();
3635         step_out('}', this);
3636         in_block = old_in_block;
3637         return this;
3638     });
3639 
3640     stmt('debugger', function () {
3641         if (!option.debug) {
3642             this.warn('unexpected_a');
3643         }
3644         this.arity = 'statement';
3645         return this;
3646     });
3647 
3648     labeled_stmt('do', function () {
3649         funct.loopage += 1;
3650         one_space();
3651         this.arity = 'statement';
3652         this.block = block('do');
3653         if (this.block.disrupt) {
3654             prev_token.warn('strange_loop');
3655         }
3656         one_space();
3657         advance('while');
3658         var paren = next_token;
3659         one_space();
3660         advance('(');
3661         step_in();
3662         no_space();
3663         edge();
3664         this.first = expected_condition(expected_relation(expression(0)), 'unexpected_a');
3665         no_space();
3666         step_out(')', paren);
3667         funct.loopage -= 1;
3668         return this;
3669     });
3670 
3671     labeled_stmt('for', function () {
3672 
3673         var blok, filter, master, ok = false, paren = next_token, value;
3674         this.arity = 'statement';
3675         funct.loopage += 1;
3676         advance('(');
3677         if (next_token.id === ';') {
3678             no_space();
3679             advance(';');
3680             no_space();
3681             advance(';');
3682             no_space();
3683             advance(')');
3684             blok = block('for');
3685         } else {
3686             step_in('control');
3687             spaces(this, paren);
3688             no_space();
3689             if (next_token.id === 'var') {
3690                 next_token.stop('move_var');
3691             }
3692             edge();
3693             if (peek(0).id === 'in') {
3694                 this.forin = true;
3695                 value = expression(1000);
3696                 master = value.master;
3697                 if (!master) {
3698                     value.stop('bad_in_a');
3699                 }
3700                 if (master.kind !== 'var' || master.function !== funct ||
3701                         !master.writeable || master.dead) {
3702                     value.warn('bad_in_a');
3703                 }
3704                 master.init = true;
3705                 master.used -= 1;
3706                 this.first = value;
3707                 advance('in');
3708                 this.second = expression(20);
3709                 step_out(')', paren);
3710                 blok = block('for');
3711                 if (!option.forin) {
3712                     if (blok.length === 1 && typeof blok[0] === 'object') {
3713                         if (blok[0].id === 'if' && !blok[0].else) {
3714                             filter = blok[0].first;
3715                             while (filter.id === '&&') {
3716                                 filter = filter.first;
3717                             }
3718                             switch (filter.id) {
3719                             case '===':
3720                             case '!==':
3721                                 ok = filter.first.id === '['
3722                                     ? are_similar(filter.first.first, this.second) &&
3723                                         are_similar(filter.first.second, this.first)
3724                                     : filter.first.id === 'typeof' &&
3725                                         filter.first.first.id === '[' &&
3726                                         are_similar(filter.first.first.first, this.second) &&
3727                                         are_similar(filter.first.first.second, this.first);
3728                                 break;
3729                             case '(':
3730                                 ok = filter.first.id === '.' && ((
3731                                     are_similar(filter.first.first, this.second) &&
3732                                     filter.first.second.string === 'hasOwnProperty' &&
3733                                     are_similar(filter.second[0], this.first)
3734                                 ) || (
3735                                     filter.first.first.id === '.' &&
3736                                     filter.first.first.first.first &&
3737                                     filter.first.first.first.first.string === 'Object' &&
3738                                     filter.first.first.first.id === '.' &&
3739                                     filter.first.first.first.second.string === 'prototype' &&
3740                                     filter.first.first.second.string === 'hasOwnProperty' &&
3741                                     filter.first.second.string === 'call' &&
3742                                     are_similar(filter.second[0], this.second) &&
3743                                     are_similar(filter.second[1], this.first)
3744                                 ));
3745                                 break;
3746                             }
3747                         } else if (blok[0].id === 'switch') {
3748                             ok = blok[0].id === 'switch' &&
3749                                 blok[0].first.id === 'typeof' &&
3750                                 blok[0].first.first.id === '[' &&
3751                                 are_similar(blok[0].first.first.first, this.second) &&
3752                                 are_similar(blok[0].first.first.second, this.first);
3753                         }
3754                     }
3755                     if (!ok) {
3756                         this.warn('for_if');
3757                     }
3758                 }
3759             } else {
3760                 edge();
3761                 this.first = [];
3762                 for (;;) {
3763                     this.first.push(expression(0, 'for'));
3764                     if (next_token.id !== ',') {
3765                         break;
3766                     }
3767                     comma();
3768                 }
3769                 semicolon();
3770                 edge();
3771                 this.second = expected_relation(expression(0));
3772                 if (this.second.id !== 'true') {
3773                     expected_condition(this.second, 'unexpected_a');
3774                 }
3775                 semicolon(token);
3776                 if (next_token.id === ';') {
3777                     next_token.stop('expected_a_b', ')', ';');
3778                 }
3779                 this.third = [];
3780                 edge();
3781                 for (;;) {
3782                     this.third.push(expression(0, 'for'));
3783                     if (next_token.id !== ',') {
3784                         break;
3785                     }
3786                     comma();
3787                 }
3788                 no_space();
3789                 step_out(')', paren);
3790                 one_space();
3791                 blok = block('for');
3792             }
3793         }
3794         if (blok.disrupt) {
3795             prev_token.warn('strange_loop');
3796         }
3797         this.block = blok;
3798         funct.loopage -= 1;
3799         return this;
3800     });
3801 
3802     function optional_label(that) {
3803         var label = next_token.string,
3804             master;
3805         that.arity = 'statement';
3806         if (!funct.breakage || (!option.continue && that.id === 'continue')) {
3807             that.warn('unexpected_a');
3808         } else if (next_token.identifier && token.line === next_token.line) {
3809             one_space_only();
3810             master = scope[label];
3811             if (!master || master.kind !== 'label') {
3812                 next_token.warn('not_a_label');
3813             } else if (master.dead || master.function !== funct) {
3814                 next_token.warn('not_a_scope');
3815             } else {
3816                 master.used += 1;
3817                 if (that.id === 'break') {
3818                     master.statement.break = true;
3819                 }
3820                 if (funct.breakage[funct.breakage.length - 1] === master.statement) {
3821                     next_token.warn('unexpected_a');
3822                 }
3823             }
3824             that.first = next_token;
3825             advance();
3826         } else {
3827             if (that.id === 'break') {
3828                 funct.breakage[funct.breakage.length - 1].break = true;
3829             }
3830         }
3831         return that;
3832 
3833     }
3834 
3835     disrupt_stmt('break', function () {
3836         return optional_label(this);
3837     });
3838 
3839     disrupt_stmt('continue', function () {
3840         return optional_label(this);
3841     });
3842 
3843     disrupt_stmt('return', function () {
3844         if (funct === global_funct) {
3845             this.warn('unexpected_a');
3846         }
3847         this.arity = 'statement';
3848         if (next_token.id !== ';' && next_token.line === token.line) {
3849             if (option.closure) {
3850                 spaces();
3851             } else {
3852                 one_space_only();
3853             }
3854             if (next_token.id === '/' || next_token.id === '(regexp)') {
3855                 next_token.warn('wrap_regexp');
3856             }
3857             this.first = expression(0);
3858             if (this.first.assign) {
3859                 this.first.warn('unexpected_a');
3860             }
3861         }
3862         return this;
3863     });
3864 
3865     disrupt_stmt('throw', function () {
3866         this.arity = 'statement';
3867         one_space_only();
3868         this.first = expression(20);
3869         return this;
3870     });
3871 
3872 
3873 //  Superfluous reserved words
3874 
3875     reserve('class');
3876     reserve('const');
3877     reserve('enum');
3878     reserve('export');
3879     reserve('extends');
3880     reserve('import');
3881     reserve('super');
3882 
3883 // Harmony reserved words
3884 
3885     reserve('implements');
3886     reserve('interface');
3887     reserve('let');
3888     reserve('package');
3889     reserve('private');
3890     reserve('protected');
3891     reserve('public');
3892     reserve('static');
3893     reserve('yield');
3894 
3895 
3896 // Parse JSON
3897 
3898     function json_value() {
3899 
3900         function json_object() {
3901             var brace = next_token, object = Object.create(null);
3902             advance('{');
3903             if (next_token.id !== '}') {
3904                 while (next_token.id !== '(end)') {
3905                     while (next_token.id === ',') {
3906                         next_token.warn('unexpected_a');
3907                         advance(',');
3908                     }
3909                     if (next_token.id !== '(string)') {
3910                         next_token.warn('expected_string_a');
3911                     }
3912                     if (object[next_token.string] === true) {
3913                         next_token.warn('duplicate_a');
3914                     } else if (next_token.string === '__proto__') {
3915                         next_token.warn('dangling_a');
3916                     } else {
3917                         object[next_token.string] = true;
3918                     }
3919                     advance();
3920                     advance(':');
3921                     json_value();
3922                     if (next_token.id !== ',') {
3923                         break;
3924                     }
3925                     advance(',');
3926                     if (next_token.id === '}') {
3927                         token.warn('unexpected_a');
3928                         break;
3929                     }
3930                 }
3931             }
3932             advance('}', brace);
3933         }
3934 
3935         function json_array() {
3936             var bracket = next_token;
3937             advance('[');
3938             if (next_token.id !== ']') {
3939                 while (next_token.id !== '(end)') {
3940                     while (next_token.id === ',') {
3941                         next_token.warn('unexpected_a');
3942                         advance(',');
3943                     }
3944                     json_value();
3945                     if (next_token.id !== ',') {
3946                         break;
3947                     }
3948                     advance(',');
3949                     if (next_token.id === ']') {
3950                         token.warn('unexpected_a');
3951                         break;
3952                     }
3953                 }
3954             }
3955             advance(']', bracket);
3956         }
3957 
3958         switch (next_token.id) {
3959         case '{':
3960             json_object();
3961             break;
3962         case '[':
3963             json_array();
3964             break;
3965         case 'true':
3966         case 'false':
3967         case 'null':
3968         case '(number)':
3969         case '(string)':
3970             advance();
3971             break;
3972         case '-':
3973             advance('-');
3974             no_space_only();
3975             advance('(number)');
3976             break;
3977         default:
3978             next_token.stop('unexpected_a');
3979         }
3980     }
3981 
3982 
3983 // The actual JSLINT function itself.
3984 
3985     itself = function JSLint(the_source, the_option) {
3986 
3987         var i, predef, tree;
3988         itself.errors = [];
3989         itself.tree = '';
3990         itself.properties = '';
3991         begin = prev_token = token = next_token =
3992             Object.create(syntax['(begin)']);
3993         tokens = [];
3994         predefined = Object.create(null);
3995         add_to_predefined(standard);
3996         property = Object.create(null);
3997         if (the_option) {
3998             option = Object.create(the_option);
3999             predef = option.predef;
4000             if (predef) {
4001                 if (Array.isArray(predef)) {
4002                     for (i = 0; i < predef.length; i += 1) {
4003                         predefined[predef[i]] = true;
4004                     }
4005                 } else if (typeof predef === 'object') {
4006                     add_to_predefined(predef);
4007                 }
4008             }
4009         } else {
4010             option = Object.create(null);
4011         }
4012         option.indent = +option.indent || 4;
4013         option.maxerr = +option.maxerr || 50;
4014         global_scope = scope = Object.create(null);
4015         global_funct = funct = {
4016             scope: scope,
4017             loopage: 0,
4018             level: 0
4019         };
4020         functions = [funct];
4021         block_var = [];
4022 
4023         comments = [];
4024         comments_off = false;
4025         in_block = false;
4026         indent = null;
4027         json_mode = false;
4028         lookahead = [];
4029         node_js = false;
4030         prereg = true;
4031         strict_mode = false;
4032         var_mode = null;
4033         warnings = 0;
4034         lex.init(the_source);
4035 
4036         assume();
4037 
4038         try {
4039             advance();
4040             if (next_token.id === '(number)') {
4041                 next_token.stop('unexpected_a');
4042             } else {
4043                 switch (next_token.id) {
4044                 case '{':
4045                 case '[':
4046                     comments_off = true;
4047                     json_mode = true;
4048                     json_value();
4049                     break;
4050                 default:
4051 
4052 // If the first token is a semicolon, ignore it. This is sometimes used when
4053 // files are intended to be appended to files that may be sloppy. A sloppy
4054 // file may be depending on semicolon insertion on its last line.
4055 
4056                     step_in(1);
4057                     if (next_token.id === ';' && !node_js) {
4058                         next_token.edge = true;
4059                         advance(';');
4060                     }
4061                     tree = statements();
4062                     begin.first = tree;
4063                     itself.tree = begin;
4064                     if (tree.disrupt) {
4065                         prev_token.warn('weird_program');
4066                     }
4067                 }
4068             }
4069             indent = null;
4070             advance('(end)');
4071             itself.property = property;
4072         } catch (e) {
4073             if (e) {        // ~~
4074                 itself.errors.push({
4075                     reason    : e.message,
4076                     line      : e.line || next_token.line,
4077                     character : e.character || next_token.from
4078                 }, null);
4079             }
4080         }
4081         return itself.errors.length === 0;
4082     };
4083 
4084     function unique(array) {
4085         array = array.sort();
4086         var i, length = 0, previous, value;
4087         for (i = 0; i < array.length; i += 1) {
4088             value = array[i];
4089             if (value !== previous) {
4090                 array[length] = value;
4091                 previous = value;
4092                 length += 1;
4093             }
4094         }
4095         array.length = length;
4096         return array;
4097     }
4098 
4099 // Data summary.
4100 
4101     itself.data = function () {
4102         var data = {functions: []},
4103             function_data,
4104             i,
4105             the_function,
4106             the_scope;
4107         data.errors = itself.errors;
4108         data.json = json_mode;
4109         data.global = unique(Object.keys(global_scope));
4110 
4111         function selects(name) {
4112             var kind = the_scope[name].kind;
4113             switch (kind) {
4114             case 'var':
4115             case 'exception':
4116             case 'label':
4117                 function_data[kind].push(name);
4118                 break;
4119             }
4120         }
4121 
4122         for (i = 1; i < functions.length; i += 1) {
4123             the_function = functions[i];
4124             function_data = {
4125                 name: the_function.name,
4126                 line: the_function.line,
4127                 level: the_function.level,
4128                 parameter: the_function.parameter,
4129                 var: [],
4130                 exception: [],
4131                 closure: unique(the_function.closure),
4132                 outer: unique(the_function.outer),
4133                 global: unique(the_function.global),
4134                 label: []
4135             };
4136             the_scope = the_function.scope;
4137             Object.keys(the_scope).forEach(selects);
4138             function_data.var.sort();
4139             function_data.exception.sort();
4140             function_data.label.sort();
4141             data.functions.push(function_data);
4142         }
4143         data.tokens = tokens;
4144         return data;
4145     };
4146 
4147     itself.error_report = function (data) {
4148         var evidence, i, output = [], warning;
4149         if (data.errors.length) {
4150             if (data.json) {
4151                 output.push('<cite>JSON: bad.</cite><br>');
4152             }
4153             for (i = 0; i < data.errors.length; i += 1) {
4154                 warning = data.errors[i];
4155                 if (warning) {
4156                     evidence = warning.evidence || '';
4157                     output.push('<cite>');
4158                     if (isFinite(warning.line)) {
4159                         output.push('<address>line ' +
4160                             String(warning.line) +
4161                             ' character ' + String(warning.character) +
4162                             '</address>');
4163                     }
4164                     output.push(warning.reason.entityify() + '</cite>');
4165                     if (evidence) {
4166                         output.push('<pre>' + evidence.entityify() + '</pre>');
4167                     }
4168                 }
4169             }
4170         }
4171         return output.join('');
4172     };
4173 
4174 
4175     itself.report = function (data) {
4176         var dl, i, j, names, output = [], the_function;
4177 
4178         function detail(h, array) {
4179             var comma_needed = false;
4180             if (array.length) {
4181                 output.push("<dt>" + h + "</dt><dd>");
4182                 array.forEach(function (item) {
4183                     output.push((comma_needed ? ', ' : '') + item);
4184                     comma_needed = true;
4185                 });
4186                 output.push("</dd>");
4187             }
4188         }
4189 
4190         output.push('<dl class=level0>');
4191         if (data.global.length) {
4192             detail('global', data.global);
4193             dl = true;
4194         } else if (data.json) {
4195             if (!data.errors.length) {
4196                 output.push("<dt>JSON: good.</dt>");
4197             }
4198         } else {
4199             output.push("<dt><i>No new global variables introduced.</i></dt>");
4200         }
4201         if (dl) {
4202             output.push("</dl>");
4203         } else {
4204             output[0] = '';
4205         }
4206 
4207         if (data.functions) {
4208             for (i = 0; i < data.functions.length; i += 1) {
4209                 the_function = data.functions[i];
4210                 names = [];
4211                 if (the_function.params) {
4212                     for (j = 0; j < the_function.params.length; j += 1) {
4213                         names[j] = the_function.params[j].string;
4214                     }
4215                 }
4216                 output.push('<dl class=level' + the_function.level +
4217                     '><address>line ' + String(the_function.line) +
4218                     '</address>' + the_function.name.entityify());
4219                 detail('parameter', the_function.parameter);
4220                 detail('variable', the_function.var);
4221                 detail('exception', the_function.exception);
4222                 detail('closure', the_function.closure);
4223                 detail('outer', the_function.outer);
4224                 detail('global', the_function.global);
4225                 detail('label', the_function.label);
4226                 output.push('</dl>');
4227             }
4228         }
4229         return output.join('');
4230     };
4231 
4232     itself.properties_report = function (property) {
4233         if (!property) {
4234             return '';
4235         }
4236         var i,
4237             key,
4238             keys = Object.keys(property).sort(),
4239             mem = '   ',
4240             name,
4241             not_first = false,
4242             output = ['/*properties'];
4243         for (i = 0; i < keys.length; i += 1) {
4244             key = keys[i];
4245             if (property[key] > 0) {
4246                 if (not_first) {
4247                     mem += ',';
4248                 }
4249                 name = ix.test(key)
4250                     ? key
4251                     : '\'' + key.replace(nx, sanitize) + '\'';
4252                 if (mem.length + name.length >= 80) {
4253                     output.push(mem);
4254                     mem = '    ';
4255                 } else {
4256                     mem += ' ';
4257                 }
4258                 mem += name;
4259                 not_first = true;
4260             }
4261         }
4262         output.push(mem, '*/\n');
4263         return output.join('\n');
4264     };
4265 
4266     itself.color = function (data) {
4267         var from,
4268             i = 1,
4269             level,
4270             line,
4271             result = [],
4272             thru,
4273             data_token = data.tokens[0];
4274         while (data_token && data_token.id !== '(end)') {
4275             from = data_token.from;
4276             line = data_token.line;
4277             thru = data_token.thru;
4278             level = data_token.function.level;
4279             do {
4280                 thru = data_token.thru;
4281                 data_token = data.tokens[i];
4282                 i += 1;
4283             } while (data_token && data_token.line === line &&
4284                     data_token.from - thru < 5 &&
4285                     level === data_token.function.level);
4286             result.push({
4287                 line: line,
4288                 level: level,
4289                 from: from,
4290                 thru: thru
4291             });
4292         }
4293         return result;
4294     };
4295 
4296     itself.jslint = itself;
4297 
4298     itself.edition = '2014-07-08';
4299 
4300     return itself;
4301 }());
4302 core.JSLint = function JSLint() {
4303     "use strict";
4304     this.JSLINT = JSLINT;
4305 };
4306