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