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