Develop and Download Open Source Software

Browse Subversion Repository

Annotation of /js/ejs_fulljslint.js

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4 - (hide annotations) (download) (as text)
Fri Dec 4 12:17:36 2009 UTC (14 years, 5 months ago) by berupon
File MIME type: application/x-javascript
File size: 135344 byte(s)
まだ完成していないけど途中経過の記録というか…backupとしてcommit
1 berupon 4 // jslint.js
2     // 2007-12-10
3     /*
4     Copyright (c) 2002 Douglas Crockford (www.JSLint.com)
5    
6     Permission is hereby granted, free of charge, to any person obtaining a copy of
7     this software and associated documentation files (the "Software"), to deal in
8     the Software without restriction, including without limitation the rights to
9     use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
10     of the Software, and to permit persons to whom the Software is furnished to do
11     so, subject to the following conditions:
12    
13     The above copyright notice and this permission notice shall be included in all
14     copies or substantial portions of the Software.
15    
16     The Software shall be used for Good, not Evil.
17    
18     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21     AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24     SOFTWARE.
25     */
26    
27     /*
28     JSLINT is a global function. It takes two parameters.
29    
30     var myResult = JSLINT(source, option);
31    
32     The first parameter is either a string or an array of strings. If it is a
33     string, it will be split on '\n' or '\r'. If it is an array of strings, it
34     is assumed that each string represents one line. The source can be a
35     JavaScript text, or HTML text, or a Konfabulator text.
36    
37     The second parameter is an optional object of options which control the
38     operation of JSLINT. All of the options are booleans. All are optional and
39     have a default value of false.
40    
41     If it checks out, JSLINT returns true. Otherwise, it returns false.
42    
43     If false, you can inspect JSLINT.errors to find out the problems.
44     JSLINT.errors is an array of objects containing these members:
45    
46     {
47     line : The line (relative to 0) at which the lint was found
48     character : The character (relative to 0) at which the lint was found
49     reason : The problem
50     evidence : The text line in which the problem occurred
51     raw : The raw message before the details were inserted
52     a : The first detail
53     b : The second detail
54     c : The third detail
55     d : The fourth detail
56     }
57    
58     If a fatal error was found, a null will be the last element of the
59     JSLINT.errors array.
60    
61     You can request a Function Report, which shows all of the functions
62     and the parameters and vars that they use. This can be used to find
63     implied global variables and other problems. The report is in HTML and
64     can be inserted in a <body>.
65    
66     var myReport = JSLINT.report(option);
67    
68     If the option is true, then the report will be limited to only errors.
69     */
70    
71     /*jslint evil: true, nomen: false */
72    
73     /*members "\b", "\t", "\n", "\f", "\r", "\"", "(begin)", "(context)",
74     "(end)", "(global)", "(identifier)", "(line)", "(name)", "(params)",
75     "(scope)", "(verb)", ")", "++", "--", "\/", ADSAFE, Array, Boolean, COM,
76     Canvas, CustomAnimation, Date, Debug, Error, EvalError, FadeAnimation,
77     Frame, Function, HotKey, Image, Math, MenuItem, MoveAnimation, Number,
78     Object, Point, RangeError, ReferenceError, RegExp, RotateAnimation,
79     ScrollBar, String, SyntaxError, Text, TextArea, TypeError, URIError,
80     URL, Window, XMLDOM, XMLHttpRequest, "\\", "]", a, abbr, "about-box",
81     "about-image", "about-text", "about-version", acronym, action, address,
82     adsafe, alert, alignment, anchorstyle, animator, appleScript, applet,
83     apply, area, author, autohide, b, background, base, bdo, beep, beget,
84     bgcolor, bgcolour, bgopacity, big, bitwise, block, blockquote, blur,
85     body, br, browser, button, bytesToUIString, c, call, callee, caller,
86     canvas, cap, caption, cases, center, charAt, charCodeAt, character,
87     checked, chooseColor, chooseFile, chooseFolder, cite, clearInterval,
88     clearTimeout, cliprect, clone, close, closeWidget, closed, code, col,
89     colgroup, color, colorize, colour, columns, combine, company, condition,
90     confirm, console, constructor, content, contextmenuitems,
91     convertPathToHFS, convertPathToPlatform, copyright, d, data, dd, debug,
92     decodeURI, decodeURIComponent, defaultStatus, defaulttracking,
93     defaultvalue, defineClass, del, description, deserialize, dfn, dir,
94     directory, div, dl, doAttribute, doBegin, doIt, doTagName, document, dt,
95     dynsrc, editable, em, embed, empty, enabled, encodeURI,
96     encodeURIComponent, entityify, eqeqeq, errors, escape, eval, event,
97     evidence, evil, exec, exps, extension, fieldset, file, filesystem,
98     fillmode, flags, floor, focus, focusWidget, font, fontstyle, forin,
99     form, fragment, frame, frames, frameset, from, fromCharCode, fud,
100     function, gc, getComputedStyle, group, h1, h2, h3, h4, h5, h6, halign,
101     handlelinks, hasOwnProperty, head, height, help, hidden, history,
102     hlinesize, hoffset, hotkey, hr, href, hregistrationpoint, hscrollbar,
103     hsladjustment, hsltinting, html, i, iTunes, icon, id, identifier,
104     iframe, image, img, include, indexOf, init, input, ins, interval,
105     isAlpha, isApplicationRunning, isDigit, isFinite, isNaN, join, kbd, key,
106     kind, konfabulatorVersion, label, labelled, laxbreak, lbp, led, left,
107     legend, length, level, li, line, lines, link, load, loadClass,
108     loadingsrc, location, locked, log, lowsrc, map, match, max, maxlength,
109     menu, menuitem, message, meta, min, minimumversion, minlength,
110     missingsrc, modifier, moveBy, moveTo, name, navigator, new, noframes,
111     nomen, noscript, notsaved, nud, object, ol, on, onblur, onclick,
112     oncontextmenu, ondragdrop, ondragenter, ondragexit, onerror,
113     onfirstdisplay, onfocus, ongainfocus, onimageloaded, onkeydown,
114     onkeypress, onkeyup, onload, onlosefocus, onmousedown, onmousedrag,
115     onmouseenter, onmouseexit, onmousemove, onmouseup, onmousewheel,
116     onmulticlick, onresize, onselect, ontextinput, ontimerfired, onunload,
117     onvaluechanged, opacity, open, openURL, opener, opera, optgroup, option,
118     optionvalue, order, orientation, p, pagesize, param, parent, parseFloat,
119     parseInt, passfail, play, plusplus, pop, popupMenu, pre, preference,
120     preferenceGroups, preferencegroup, preferences, print, prompt,
121     prototype, push, q, quit, random, raw, reach, readFile, readUrl, reason,
122     reloadWidget, remoteasync, replace, report, requiredplatform, reserved,
123     resizeBy, resizeTo, resolvePath, resumeUpdates, rhino, right, root,
124     rotation, runCommand, runCommandInBg, samp, saveAs, savePreferences,
125     screen, script, scroll, scrollBy, scrollTo, scrollbar, scrolling,
126     scrollx, scrolly, seal, search, secure, select, self, serialize,
127     setInterval, setTimeout, setting, settings, shadow, shift,
128     showWidgetPreferences, size, skip, sleep, slice, small, sort, source,
129     span, spawn, speak, special, spellcheck, split, src, srcheight,
130     srcwidth, status, strong, style, sub, substr, subviews, sup, superview,
131     supplant, suppressUpdates, sync, system, table, tag, tbody, td,
132     tellWidget, test, text, textarea, tfoot, th, thead, this, thumbcolor,
133     ticking, ticklabel, ticks, tileorigin, timer, title, toLowerCase,
134     toSource, toString, toint32, token, tooltip, top, tr, tracking, trigger,
135     truncation, tt, type, u, ul, undef, unescape, unwatch, updateNow, url,
136     usefileicon, valign, value, valueOf, var, version, visible, vlinesize,
137     voffset, vregistrationpoint, vscrollbar, watch, white, widget, width,
138     window, wrap, yahooCheckLogin, yahooLogin, yahooLogout, zorder
139     */
140    
141     // We build the application inside a function so that we produce only a single
142     // global variable. The function will be invoked, its return value is the JSLINT
143     // function itself.
144    
145     var JSLINT;
146     JSLINT = function () {
147    
148     // These are words that should not be permitted in third party ads.
149    
150     var adsafe = {
151     apply : true,
152     call : true,
153     callee : true,
154     caller : true,
155     clone : true,
156     constructor : true,
157     'eval' : true,
158     'new' : true,
159     prototype : true,
160     source : true,
161     'this' : true,
162     toSource : true,
163     toString : true,
164     unwatch : true,
165     valueOf : true,
166     watch : true
167     },
168    
169     // These are all of the JSLint options.
170    
171     allOptions = {
172     adsafe : true, // if use of some browser features should be restricted
173     bitwise : true, // if bitwise operators should not be allowed
174     browser : true, // if the standard browser globals should be predefined
175     cap : true, // if upper case HTML should be allowed
176     debug : true, // if debugger statements should be allowed
177     eqeqeq : true, // if === should be required
178     evil : true, // if eval should be allowed
179     forin : true, // if for in statements must filter
180     fragment : true, // if HTML fragments should be allowed
181     laxbreak : true, // if line breaks should not be checked
182     nomen : true, // if names should be checked
183     on : true, // if HTML event handlers should be allowed
184     passfail : true, // if the scan should stop on first error
185     plusplus : true, // if increment/decrement should not be allowed
186     rhino : true, // if the Rhino environment globals should be predefined
187     undef : true, // if variables should be declared before used
188     white : true, // if strict whitespace rules apply
189     widget : true // if the Yahoo Widgets globals should be predefined
190     },
191    
192     anonname, // The guessed name for anonymous functions.
193    
194     // browser contains a set of global names which are commonly provided by a
195     // web browser environment.
196    
197     browser = {
198     alert : true,
199     blur : true,
200     clearInterval : true,
201     clearTimeout : true,
202     close : true,
203     closed : true,
204     confirm : true,
205     console : true,
206     Debug : true,
207     defaultStatus : true,
208     document : true,
209     event : true,
210     focus : true,
211     frames : true,
212     getComputedStyle: true,
213     history : true,
214     Image : true,
215     length : true,
216     location : true,
217     moveBy : true,
218     moveTo : true,
219     name : true,
220     navigator : true,
221     onblur : true,
222     onerror : true,
223     onfocus : true,
224     onload : true,
225     onresize : true,
226     onunload : true,
227     open : true,
228     opener : true,
229     opera : true,
230     parent : true,
231     print : true,
232     prompt : true,
233     resizeBy : true,
234     resizeTo : true,
235     screen : true,
236     scroll : true,
237     scrollBy : true,
238     scrollTo : true,
239     self : true,
240     setInterval : true,
241     setTimeout : true,
242     status : true,
243     top : true,
244     window : true,
245     XMLHttpRequest : true
246     },
247    
248     escapes = {
249     '\b': '\\b',
250     '\t': '\\t',
251     '\n': '\\n',
252     '\f': '\\f',
253     '\r': '\\r',
254     '"' : '\\"',
255     '/' : '\\/',
256     '\\': '\\\\'
257     },
258    
259     funct, // The current function
260     functions, // All of the functions
261    
262     href = {
263     background : true,
264     content : true,
265     data : true,
266     dynsrc : true,
267     href : true,
268     lowsrc : true,
269     value : true,
270     src : true,
271     style : true
272     },
273    
274     global, // The global object
275     globals, // The current globals
276     implied, // Implied globals
277     inblock,
278     indent,
279     jsonmode,
280     lines,
281     lookahead,
282     member,
283     membersOnly,
284     nexttoken,
285     noreach,
286     option,
287     prereg,
288     prevtoken,
289    
290     rhino = {
291     defineClass : true,
292     deserialize : true,
293     gc : true,
294     help : true,
295     load : true,
296     loadClass : true,
297     print : true,
298     quit : true,
299     readFile : true,
300     readUrl : true,
301     runCommand : true,
302     seal : true,
303     serialize : true,
304     spawn : true,
305     sync : true,
306     toint32 : true,
307     version : true
308     },
309    
310     scope, // The current scope
311     src,
312     stack,
313    
314     // standard contains the global names that are provided by the
315     // ECMAScript standard.
316    
317     standard = {
318     Array : true,
319     Boolean : true,
320     Date : true,
321     decodeURI : true,
322     decodeURIComponent : true,
323     encodeURI : true,
324     encodeURIComponent : true,
325     Error : true,
326     escape : true,
327     'eval' : true,
328     EvalError : true,
329     Function : true,
330     isFinite : true,
331     isNaN : true,
332     Math : true,
333     Number : true,
334     Object : true,
335     parseInt : true,
336     parseFloat : true,
337     RangeError : true,
338     ReferenceError : true,
339     RegExp : true,
340     String : true,
341     SyntaxError : true,
342     TypeError : true,
343     unescape : true,
344     URIError : true
345     },
346    
347     syntax = {},
348     token,
349     warnings,
350    
351     // widget contains the global names which are provided to a Yahoo
352     // (fna Konfabulator) widget.
353    
354     widget = {
355     alert : true,
356     appleScript : true,
357     animator : true,
358     appleScript : true,
359     beep : true,
360     bytesToUIString : true,
361     Canvas : true,
362     chooseColor : true,
363     chooseFile : true,
364     chooseFolder : true,
365     convertPathToHFS : true,
366     convertPathToPlatform : true,
367     closeWidget : true,
368     COM : true,
369     CustomAnimation : true,
370     escape : true,
371     FadeAnimation : true,
372     filesystem : true,
373     focusWidget : true,
374     form : true,
375     Frame : true,
376     HotKey : true,
377     Image : true,
378     include : true,
379     isApplicationRunning : true,
380     iTunes : true,
381     konfabulatorVersion : true,
382     log : true,
383     MenuItem : true,
384     MoveAnimation : true,
385     openURL : true,
386     play : true,
387     Point : true,
388     popupMenu : true,
389     preferenceGroups : true,
390     preferences : true,
391     print : true,
392     prompt : true,
393     random : true,
394     reloadWidget : true,
395     resolvePath : true,
396     resumeUpdates : true,
397     RotateAnimation : true,
398     runCommand : true,
399     runCommandInBg : true,
400     saveAs : true,
401     savePreferences : true,
402     screen : true,
403     ScrollBar : true,
404     showWidgetPreferences : true,
405     sleep : true,
406     speak : true,
407     suppressUpdates : true,
408     system : true,
409     tellWidget : true,
410     Text : true,
411     TextArea : true,
412     unescape : true,
413     updateNow : true,
414     URL : true,
415     widget : true,
416     Window : true,
417     XMLDOM : true,
418     XMLHttpRequest : true,
419     yahooCheckLogin : true,
420     yahooLogin : true,
421     yahooLogout : true
422     },
423    
424     // xmode is used to adapt to the exceptions in XML parsing.
425     // It can have these states:
426     // false .js script file
427     // " A " attribute
428     // ' A ' attribute
429     // content The content of a script tag
430     // CDATA A CDATA block
431    
432     xmode,
433    
434     // xtype identifies the type of document being analyzed.
435     // It can have these states:
436     // false .js script file
437     // html .html file
438     // widget .kon Konfabulator file
439    
440     xtype,
441    
442     // unsafe comment
443     ax = /@cc|<\/?script|\]\]|&/i,
444     // unsafe character
445     cx = /[\u0000-\u0008\u000a-\u001f\u007f-\u009f\u2028\u2029\ufff0-\uffff]/,
446     // token
447     tx = /^\s*([(){}\[.,:;'"~]|\](\]>)?|\?>?|==?=?|\/(\*(global|extern|jslint|member|members)?|=|\/)?|\*[\/=]?|\+[+=]?|-[\-=]?|%[=>]?|&[&=]?|\|[|=]?|>>?>?=?|<([\/=%\?]|\!(\[|--)?|<=?)?|\^=?|\!=?=?|[a-zA-Z_$][a-zA-Z0-9_$]*|[0-9]+([xX][0-9a-fA-F]+|\.[0-9]*)?([eE][+\-]?[0-9]+)?)/,
448     // star slash
449     lx = /\*\/|\/\*/,
450     // identifier
451     ix = /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/,
452     // javascript url
453     jx = /(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i,
454     // url badness
455     ux = /&|\+|\u00AD|\.\.|\/\*|%[^;]|base64|url|expression|data|mailto/i;
456    
457     function object(o) {
458     function F() {}
459     F.prototype = o;
460     return new F();
461     }
462    
463     object_combine = function (object, o) {
464     var n;
465     for (n in o) if (o.hasOwnProperty(n)) {
466     object[n] = o[n];
467     }
468     };
469    
470     String.prototype.entityify = function () {
471     return this.
472     replace(/&/g, '&amp;').
473     replace(/</g, '&lt;').
474     replace(/>/g, '&gt;');
475     };
476    
477     String.prototype.isAlpha = function () {
478     return (this >= 'a' && this <= 'z\uffff') ||
479     (this >= 'A' && this <= 'Z\uffff');
480     };
481    
482    
483     String.prototype.isDigit = function () {
484     return (this >= '0' && this <= '9');
485     };
486    
487    
488     String.prototype.supplant = function (o) {
489     return this.replace(/\{([^{}]*)\}/g, function (a, b) {
490     var r = o[b];
491     return typeof r === 'string' || typeof r === 'number' ? r : a;
492     });
493     };
494    
495     String.prototype.name = function () {
496    
497     // If the string looks like an identifier, then we can return it as is.
498     // If the string contains no control characters, no quote characters, and no
499     // backslash characters, then we can simply slap some quotes around it.
500     // Otherwise we must also replace the offending characters with safe
501     // sequences.
502    
503    
504     if (ix.test(this)) {
505     return this;
506     }
507     if (/[&<"\/\\\x00-\x1f]/.test(this)) {
508     return '"' + this.replace(/[&<"\/\\\x00-\x1f]/g, function (a) {
509     var c = escapes[a];
510     if (c) {
511     return c;
512     }
513     c = a.charCodeAt();
514     return '\\u00' +
515     Math.floor(c / 16).toString(16) +
516     (c % 16).toString(16);
517     }) + '"';
518     }
519     return '"' + this + '"';
520     };
521    
522    
523     function populateGlobals() {
524     if (option.adsafe) {
525     object_combine(globals, {ADSAFE: true});
526     } else {
527     if (option.rhino) {
528     object_combine(globals, rhino);
529     }
530     if (option.browser) {
531     object_combine(globals, browser);
532     }
533     if (option.widget) {
534     object_combine(globals, widget);
535     }
536     }
537     }
538    
539    
540     // Produce an error warning.
541    
542     function quit(m, l, ch) {
543     throw {
544     name: 'JSLintError',
545     line: l,
546     character: ch,
547     message: m + " (" + Math.floor((l / lines.length) * 100) +
548     "% scanned)."
549     };
550     }
551    
552     function warning(m, t, a, b, c, d) {
553     var ch, l, w;
554     t = t || nexttoken;
555     if (t.id === '(end)') {
556     t = token;
557     }
558     l = t.line || 0;
559     ch = t.from || 0;
560     w = {
561     id: '(error)',
562     raw: m,
563     evidence: lines[l] || '',
564     line: l,
565     character: ch,
566     a: a,
567     b: b,
568     c: c,
569     d: d
570     };
571     w.reason = m.supplant(w);
572     JSLINT.errors.push(w);
573     if (option.passfail) {
574     quit('Stopping. ', l, ch);
575     }
576     warnings += 1;
577     if (warnings === 50) {
578     quit("Too many errors.", l, ch);
579     }
580     return w;
581     }
582    
583     function warningAt(m, l, ch, a, b, c, d) {
584     return warning(m, {
585     line: l,
586     from: ch
587     }, a, b, c, d);
588     }
589    
590     function error(m, t, a, b, c, d) {
591     var w = warning(m, t, a, b, c, d);
592     quit("Stopping, unable to continue.", w.line, w.character);
593     }
594    
595     function errorAt(m, l, ch, a, b, c, d) {
596     return error(m, {
597     line: l,
598     from: ch
599     }, a, b, c, d);
600     }
601    
602    
603    
604     // lexical analysis
605    
606     var lex = function () {
607     var character, from, line, s;
608    
609     // Private lex methods
610    
611     function nextLine() {
612     var at;
613     line += 1;
614     if (line >= lines.length) {
615     return false;
616     }
617     character = 0;
618     s = lines[line];
619     at = s.search(cx);
620     if (at >= 0) {
621     warningAt("Unsafe character.", line, at);
622     }
623     return true;
624     }
625    
626     // Produce a token object. The token inherits from a syntax symbol.
627    
628     function it(type, value) {
629     var i, t;
630     if (type === '(punctuator)' ||
631     (type === '(identifier)' && syntax.hasOwnProperty(value))) {
632     t = syntax[value];
633    
634     // Mozilla bug workaround.
635    
636     if (!t.id) {
637     t = syntax[type];
638     }
639     } else {
640     t = syntax[type];
641     }
642     t = object(t);
643     if (type === '(string)') {
644     if (jx.test(value)) {
645     warningAt("Script URL.", line, from);
646     }
647     } else if (type === '(identifier)') {
648     if (option.nomen && value.charAt(0) === '_') {
649     warningAt("Unexpected '_' in '{a}'.", line, from, value);
650     } else if (option.adsafe &&
651     (adsafe[value] === true || value.slice(-2) === '__')) {
652     warning("ADsafe restricted word '{a}'.",
653     {line: line, from: character}, value);
654     }
655     }
656     t.value = value;
657     t.line = line;
658     t.character = character;
659     t.from = from;
660     i = t.id;
661     if (i !== '(endline)') {
662     prereg = i &&
663     (('(,=:[!&|?{};'.indexOf(i.charAt(i.length - 1)) >= 0) ||
664     i === 'return');
665     }
666     return t;
667     }
668    
669     // Public lex methods
670    
671     return {
672     init: function (source) {
673     if (typeof source === 'string') {
674     lines = source.
675     replace(/\r\n/g, '\n').
676     replace(/\r/g, '\n').
677     split('\n');
678     } else {
679     lines = source;
680     }
681     line = -1;
682     nextLine();
683     from = 0;
684     },
685    
686     // token -- this is called by advance to get the next token.
687    
688     token: function () {
689     var b, c, captures, d, depth, high, i, l, low, q, t;
690    
691     function match(x) {
692     var r = x.exec(s), r1;
693     if (r) {
694     l = r[0].length;
695     r1 = r[1];
696     c = r1.charAt(0);
697     s = s.substr(l);
698     character += l;
699     from = character - r1.length;
700     return r1;
701     }
702     }
703    
704     function string(x) {
705     var c, j, r = '';
706    
707     if (jsonmode && x !== '"') {
708     warningAt("Strings must use doublequote.",
709     line, character);
710     }
711    
712     if (xmode === x || xmode === 'string') {
713     return it('(punctuator)', x);
714     }
715    
716     function esc(n) {
717     var i = parseInt(s.substr(j + 1, n), 16);
718     j += n;
719     if (i >= 32 && i <= 127 &&
720     i !== 34 && i !== 92 && i !== 39) {
721     warningAt("Unnecessary escapement.", line, character);
722     }
723     character += n;
724     c = String.fromCharCode(i);
725     }
726     j = 0;
727     for (;;) {
728     while (j >= s.length) {
729     j = 0;
730     if (xmode !== 'xml' || !nextLine()) {
731     errorAt("Unclosed string.", line, from);
732     }
733     }
734     c = s.charAt(j);
735     if (c === x) {
736     character += 1;
737     s = s.substr(j + 1);
738     return it('(string)', r, x);
739     }
740     if (c < ' ') {
741     if (c === '\n' || c === '\r') {
742     break;
743     }
744     warningAt("Control character in string: {a}.",
745     line, character + j, s.slice(0, j));
746     } else if (c === '<') {
747     if (option.adsafe && xmode === 'xml') {
748     warningAt("ADsafe string violation.",
749     line, character + j);
750     } else if (s.charAt(j + 1) === '/' && ((xmode && xmode !== 'CDATA') || option.adsafe)) {
751     warningAt("Expected '<\\/' and instead saw '</'.", line, character);
752     }
753     } else if (c === '\\') {
754     if (option.adsafe && xmode === 'xml') {
755     warningAt("ADsafe string violation.",
756     line, character + j);
757     }
758     j += 1;
759     character += 1;
760     c = s.charAt(j);
761     switch (c) {
762     case '\\':
763     case '\'':
764     case '"':
765     case '/':
766     break;
767     case 'b':
768     c = '\b';
769     break;
770     case 'f':
771     c = '\f';
772     break;
773     case 'n':
774     c = '\n';
775     break;
776     case 'r':
777     c = '\r';
778     break;
779     case 't':
780     c = '\t';
781     break;
782     case 'u':
783     esc(4);
784     break;
785     case 'v':
786     c = '\v';
787     break;
788     case 'x':
789     if (jsonmode) {
790     warningAt("Avoid \\x-.", line, character);
791     }
792     esc(2);
793     break;
794     default:
795     warningAt("Bad escapement.", line, character);
796     }
797     }
798     r += c;
799     character += 1;
800     j += 1;
801     }
802     }
803    
804     for (;;) {
805     if (!s) {
806     return it(nextLine() ? '(endline)' : '(end)', '');
807     }
808     t = match(tx);
809     if (!t) {
810     t = '';
811     c = '';
812     while (s && s < '!') {
813     s = s.substr(1);
814     }
815     if (s) {
816     errorAt("Unexpected '{a}'.",
817     line, character, s.substr(0, 1));
818     }
819     }
820    
821     // identifier
822    
823     if (c.isAlpha() || c === '_' || c === '$') {
824     return it('(identifier)', t);
825     }
826    
827     // number
828    
829     if (c.isDigit()) {
830     if (!isFinite(Number(t))) {
831     warningAt("Bad number '{a}'.",
832     line, character, t);
833     }
834     if (s.substr(0, 1).isAlpha()) {
835     warningAt("Missing space after '{a}'.",
836     line, character, t);
837     }
838     if (c === '0') {
839     d = t.substr(1, 1);
840     if (d.isDigit()) {
841     warningAt("Don't use extra leading zeros '{a}'.",
842     line, character, t);
843     } else if (jsonmode && (d === 'x' || d === 'X')) {
844     warningAt("Avoid 0x-. '{a}'.",
845     line, character, t);
846     }
847     }
848     if (t.substr(t.length - 1) === '.') {
849     warningAt(
850     "A trailing decimal point can be confused with a dot '{a}'.",
851     line, character, t);
852     }
853     return it('(number)', t);
854     }
855    
856     // string
857    
858     switch (t) {
859     case '"':
860     case "'":
861     return string(t);
862    
863     // // comment
864    
865     case '//':
866     if (src || (xmode && !(xmode === 'script' || xmode === 'CDATA'))) {
867     warningAt("Unexpected comment.", line, character);
868     }
869     if (option.adsafe && ax.test(s)) {
870     warningAt("ADsafe comment violation.", line, character);
871     }
872     s = '';
873     break;
874    
875     // /* comment
876    
877     case '/*':
878     if (src || (xmode && !(xmode === 'script' || xmode === 'CDATA'))) {
879     warningAt("Unexpected comment.", line, character);
880     }
881     if (option.adsafe && ax.test(s)) {
882     warningAt("ADsafe comment violation.", line, character);
883     }
884     for (;;) {
885     i = s.search(lx);
886     if (i >= 0) {
887     break;
888     }
889     if (!nextLine()) {
890     errorAt("Unclosed comment.", line, character);
891     } else {
892     if (option.adsafe && ax.test(s)) {
893     warningAt("ADsafe comment violation.", line, character);
894     }
895     }
896     }
897     character += i + 2;
898     if (s.substr(i, 1) === '/') {
899     errorAt("Nested comment.", line, character);
900     }
901     s = s.substr(i + 2);
902     break;
903    
904     // /*global /*extern /*members /*jslint */
905    
906     case '/*global':
907     case '/*extern':
908     case '/*members':
909     case '/*member':
910     case '/*jslint':
911     case '*/':
912     return {
913     value: t,
914     type: 'special',
915     line: line,
916     character: character,
917     from: from
918     };
919    
920     case '':
921     break;
922     // /
923     case '/':
924     if (prereg) {
925     depth = 0;
926     captures = 0;
927     l = 0;
928     for (;;) {
929     b = true;
930     c = s.charAt(l);
931     l += 1;
932     switch (c) {
933     case '':
934     errorAt("Unclosed regular expression.", line, from);
935     return;
936     case '/':
937     if (depth > 0) {
938     warningAt("Unescaped '{a}'.", line, from + l, '/');
939     }
940     c = s.substr(0, l - 1);
941     if (s.charAt(l) === 'g') {
942     l += 1;
943     }
944     if (s.charAt(l) === 'i') {
945     l += 1;
946     }
947     if (s.charAt(l) === 'm') {
948     l += 1;
949     }
950     character += l;
951     s = s.substr(l);
952     return it('(regex)', c);
953     case '\\':
954     l += 1;
955     break;
956     case '(':
957     depth += 1;
958     b = false;
959     if (s.charAt(l) === '?') {
960     l += 1;
961     switch (s.charAt(l)) {
962     case ':':
963     case '=':
964     case '!':
965     l += 1;
966     break;
967     default:
968     warningAt("Expected '{a}' and instead saw '{b}'.", line, from + l, ':', s.charAt(l));
969     }
970     } else {
971     captures += 1;
972     }
973     break;
974     case ')':
975     if (depth === 0) {
976     warningAt("Unescaped '{a}'.", line, from + l, ')');
977     } else {
978     depth -= 1;
979     }
980     break;
981     case ' ':
982     q = 1;
983     while (s.charAt(l) === ' ') {
984     l += 1;
985     q += 1;
986     }
987     if (q > 1) {
988     warningAt("Spaces are hard to count. Use {{a}}.", line, from + l, q);
989     }
990     break;
991     case '[':
992     if (s.charAt(l) === '^') {
993     l += 1;
994     }
995     q = false;
996     klass: for (;;) {
997     c = s.charAt(l);
998     l += 1;
999     switch (c) {
1000     case '[':
1001     case '^':
1002     warningAt("Unescaped '{a}'.", line, from + l, c);
1003     q = true;
1004     break;
1005     case '-':
1006     if (q) {
1007     q = false;
1008     } else {
1009     warningAt("Unescaped '{a}'.", line, from + l, '-');
1010     q = true;
1011     }
1012     break;
1013     case ']':
1014     if (!q) {
1015     warningAt("Unescaped '{a}'.", line, from + l - 1, '-');
1016     }
1017     break klass;
1018     case '\\':
1019     l += 1;
1020     q = true;
1021     break;
1022     default:
1023     if (c < ' ') {
1024     errorAt(c ? "Control character in a regular expression" :
1025     "Unclosed regular expression.", line, from + l);
1026     }
1027     q = true;
1028     }
1029     }
1030     break;
1031     case ']':
1032     case '?':
1033     case '{':
1034     case '}':
1035     case '+':
1036     case '*':
1037     warningAt("Unescaped '{a}'.", line, from + l, c);
1038     break;
1039     default:
1040     if (c < ' ') {
1041     warningAt("Control character in a regular expression", line, from + l);
1042     }
1043     }
1044     if (b) {
1045     switch (s.charAt(l)) {
1046     case '?':
1047     case '+':
1048     case '*':
1049     l += 1;
1050     if (s.charAt(l) === '?') {
1051     l += 1;
1052     }
1053     break;
1054     case '{':
1055     l += 1;
1056     c = s.charAt(l);
1057     if (c < '0' || c > '9') {
1058     warningAt("Expected a number and instead saw '{a}'.", line, from + l, c);
1059     }
1060     l += 1;
1061     low = +c;
1062     for (;;) {
1063     c = s.charAt(l);
1064     if (c < '0' || c > '9') {
1065     break;
1066     }
1067     l += 1;
1068     low = +c + (low * 10);
1069     }
1070     high = low;
1071     if (c === ',') {
1072     l += 1;
1073     high = Infinity;
1074     c = s.charAt(l);
1075     if (c >= '0' && c <= '9') {
1076     l += 1;
1077     high = +c;
1078     for (;;) {
1079     c = s.charAt(l);
1080     if (c < '0' || c > '9') {
1081     break;
1082     }
1083     l += 1;
1084     high = +c + (high * 10);
1085     }
1086     }
1087     }
1088     if (s.charAt(l) !== '}') {
1089     warningAt("Expected '{a}' and instead saw '{b}'.", line, from + l, '}', c);
1090     } else {
1091     l += 1;
1092     }
1093     if (s.charAt(l) === '?') {
1094     l += 1;
1095     }
1096     if (low > high) {
1097     warningAt("'{a}' should not be greater than '{b}'.", line, from + l, low, high);
1098     }
1099     }
1100     }
1101     }
1102     c = s.substr(0, l - 1);
1103     character += l;
1104     s = s.substr(l);
1105     return it('(regex)', c);
1106     }
1107     return it('(punctuator)', t);
1108    
1109     // punctuator
1110    
1111     default:
1112     return it('(punctuator)', t);
1113     }
1114     }
1115     },
1116    
1117     // skip -- skip past the next occurrence of a particular string.
1118     // If the argument is empty, skip to just before the next '<' character.
1119     // This is used to ignore HTML content. Return false if it isn't found.
1120    
1121     skip: function (p) {
1122     var i, t = p;
1123     if (nexttoken.id) {
1124     if (!t) {
1125     t = '';
1126     if (nexttoken.id.substr(0, 1) === '<') {
1127     lookahead.push(nexttoken);
1128     return true;
1129     }
1130     } else if (nexttoken.id.indexOf(t) >= 0) {
1131     return true;
1132     }
1133     }
1134     token = nexttoken;
1135     nexttoken = syntax['(end)'];
1136     for (;;) {
1137     i = s.indexOf(t || '<');
1138     if (i >= 0) {
1139     character += i + t.length;
1140     s = s.substr(i + t.length);
1141     return true;
1142     }
1143     if (!nextLine()) {
1144     break;
1145     }
1146     }
1147     return false;
1148     }
1149     };
1150     }();
1151    
1152    
1153     function addlabel(t, type) {
1154    
1155     if (t === 'hasOwnProperty') {
1156     error("'hasOwnProperty' is a really bad name.");
1157     }
1158     if (option.adsafe && scope === global) {
1159     warning('ADsafe global: ' + t + '.', token);
1160     }
1161    
1162     // Define t in the current function in the current scope.
1163    
1164     if (funct.hasOwnProperty(t)) {
1165     warning(funct[t] === true ?
1166     "'{a}' was used before it was defined." :
1167     "'{a}' is already defined.",
1168     nexttoken, t);
1169     }
1170     scope[t] = funct;
1171     funct[t] = type;
1172     if (funct['(global)'] && implied.hasOwnProperty(t)) {
1173     warning("'{a}' was used before it was defined.",
1174     nexttoken, t);
1175     delete implied[t];
1176     }
1177     }
1178    
1179    
1180     function doOption() {
1181     var b, obj, filter, o = nexttoken.value, t, v;
1182     switch (o) {
1183     case '*/':
1184     error("Unbegun comment.");
1185     break;
1186     case '/*global':
1187     case '/*extern':
1188     if (option.adsafe) {
1189     warning("ADsafe restriction.");
1190     }
1191     obj = globals;
1192     break;
1193     case '/*members':
1194     case '/*member':
1195     o = '/*members';
1196     if (!membersOnly) {
1197     membersOnly = {};
1198     }
1199     obj = membersOnly;
1200     break;
1201     case '/*jslint':
1202     if (option.adsafe) {
1203     warning("ADsafe restriction.");
1204     }
1205     obj = option;
1206     filter = allOptions;
1207     }
1208     for (;;) {
1209     t = lex.token();
1210     if (t.id === ',') {
1211     t = lex.token();
1212     }
1213     while (t.id === '(endline)') {
1214     t = lex.token();
1215     }
1216     if (t.type === 'special' && t.value === '*/') {
1217     break;
1218     }
1219     if (t.type !== '(string)' && t.type !== '(identifier)' &&
1220     o !== '/*members') {
1221     error("Bad option.", t);
1222     }
1223     if (filter) {
1224     if (filter[t.value] !== true) {
1225     error("Bad option.", t);
1226     }
1227     v = lex.token();
1228     if (v.id !== ':') {
1229     error("Expected '{a}' and instead saw '{b}'.",
1230     t, ':', t.value);
1231     }
1232     v = lex.token();
1233     if (v.value === 'true') {
1234     b = true;
1235     } else if (v.value === 'false') {
1236     b = false;
1237     } else {
1238     error("Expected '{a}' and instead saw '{b}'.",
1239     t, 'true', t.value);
1240     }
1241     } else {
1242     b = true;
1243     }
1244     obj[t.value] = b;
1245     }
1246     if (filter) {
1247     populateGlobals();
1248     }
1249     }
1250    
1251    
1252     // We need a peek function. If it has an argument, it peeks that much farther
1253     // ahead. It is used to distinguish
1254     // for ( var i in ...
1255     // from
1256     // for ( var i = ...
1257    
1258     function peek(p) {
1259     var i = p || 0, j = 0, t;
1260    
1261     while (j <= i) {
1262     t = lookahead[j];
1263     if (!t) {
1264     t = lookahead[j] = lex.token();
1265     }
1266     j += 1;
1267     }
1268     return t;
1269     }
1270    
1271    
1272     var badbreak = {
1273     ')': true,
1274     ']': true,
1275     '++': true,
1276     '--': true
1277     };
1278    
1279     // Produce the next token. It looks for programming errors.
1280    
1281     function advance(id, t) {
1282     var l;
1283     switch (token.id) {
1284     case '(number)':
1285     if (nexttoken.id === '.') {
1286     warning(
1287     "A dot following a number can be confused with a decimal point.", token);
1288     }
1289     break;
1290     case '-':
1291     if (nexttoken.id === '-' || nexttoken.id === '--') {
1292     warning("Confusing minusses.");
1293     }
1294     break;
1295     case '+':
1296     if (nexttoken.id === '+' || nexttoken.id === '++') {
1297     warning("Confusing plusses.");
1298     }
1299     break;
1300     }
1301     if (token.type === '(string)' || token.identifier) {
1302     anonname = token.value;
1303     }
1304    
1305     if (id && nexttoken.id !== id) {
1306     if (t) {
1307     if (nexttoken.id === '(end)') {
1308     warning("Unmatched '{a}'.", t, t.id);
1309     } else {
1310     warning("Expected '{a}' to match '{b}' from line {c} and instead saw '{d}'.",
1311     nexttoken, id, t.id, t.line + 1, nexttoken.value);
1312     }
1313     } else {
1314     warning("Expected '{a}' and instead saw '{b}'.",
1315     nexttoken, id, nexttoken.value);
1316     }
1317     }
1318     prevtoken = token;
1319     token = nexttoken;
1320     for (;;) {
1321     nexttoken = lookahead.shift() || lex.token();
1322     if (nexttoken.type === 'special') {
1323     doOption();
1324     } else {
1325     if (nexttoken.id === '<![') {
1326     if (option.adsafe) {
1327     error("ADsafe violation.", nexttoken);
1328     }
1329     if (xtype === 'html') {
1330     error("Unexpected '{a}'.", nexttoken, '<![');
1331     }
1332     if (xmode === 'script') {
1333     nexttoken = lex.token();
1334     if (nexttoken.value !== 'CDATA') {
1335     error("Missing '{a}'.", nexttoken, 'CDATA');
1336     }
1337     nexttoken = lex.token();
1338     if (nexttoken.id !== '[') {
1339     error("Missing '{a}'.", nexttoken, '[');
1340     }
1341     xmode = 'CDATA';
1342     } else if (xmode === 'xml') {
1343     lex.skip(']]>');
1344     } else {
1345     error("Unexpected '{a}'.", nexttoken, '<![');
1346     }
1347     } else if (nexttoken.id === ']]>') {
1348     if (xmode === 'CDATA') {
1349     xmode = 'script';
1350     } else {
1351     error("Unexpected '{a}'.", nexttoken, ']]>');
1352     }
1353     } else if (nexttoken.id !== '(endline)') {
1354     break;
1355     }
1356     if (xmode === '"' || xmode === "'") {
1357     error("Missing '{a}'.", token, xmode);
1358     }
1359     l = !xmode && !option.laxbreak &&
1360     (token.type === '(string)' || token.type === '(number)' ||
1361     token.type === '(identifier)' || badbreak[token.id]);
1362     }
1363     }
1364     if (l) {
1365     switch (nexttoken.id) {
1366     case '{':
1367     case '}':
1368     case ']':
1369     break;
1370     case ')':
1371     switch (token.id) {
1372     case ')':
1373     case '}':
1374     case ']':
1375     break;
1376     default:
1377     warning("Line breaking error '{a}'.", token, ')');
1378     }
1379     break;
1380     default:
1381     warning("Line breaking error '{a}'.",
1382     token, token.value);
1383     }
1384     }
1385     if (xtype === 'widget' && xmode === 'script' && nexttoken.id) {
1386     l = nexttoken.id.charAt(0);
1387     if (l === '<' || l === '&') {
1388     nexttoken.nud = nexttoken.led = null;
1389     nexttoken.lbp = 0;
1390     nexttoken.reach = true;
1391     }
1392     }
1393     }
1394    
1395    
1396     // This is the heart of JSLINT, the Pratt parser. In addition to parsing, it
1397     // is looking for ad hoc lint patterns. We add to Pratt's model .fud, which is
1398     // like nud except that it is only used on the first token of a statement.
1399     // Having .fud makes it much easier to define JavaScript. I retained Pratt's
1400     // nomenclature.
1401    
1402     // .nud Null denotation
1403     // .fud First null denotation
1404     // .led Left denotation
1405     // lbp Left binding power
1406     // rbp Right binding power
1407    
1408     // They are key to the parsing method called Top Down Operator Precedence.
1409    
1410     function parse(rbp, initial) {
1411     var left;
1412     var o;
1413     if (nexttoken.id === '(end)') {
1414     error("Unexpected early end of program.", token);
1415     }
1416     advance();
1417     if (option.adsafe && token.value === 'ADSAFE') {
1418     if (nexttoken.id !== '.' || !(peek(0).identifier) ||
1419     peek(1).id !== '(') {
1420     warning('ADsafe violation.', token);
1421     }
1422     }
1423     if (initial) {
1424     anonname = 'anonymous';
1425     funct['(verb)'] = token.value;
1426     }
1427     if (initial && token.fud) {
1428     left = token.fud();
1429     } else {
1430     if (token.nud) {
1431     o = token.exps;
1432     left = token.nud();
1433     } else {
1434     if (nexttoken.type === '(number)' && token.id === '.') {
1435     warning(
1436     "A leading decimal point can be confused with a dot: '.{a}'.",
1437     token, nexttoken.value);
1438     advance();
1439     return token;
1440     } else {
1441     error("Expected an identifier and instead saw '{a}'.",
1442     token, token.id);
1443     }
1444     }
1445     while (rbp < nexttoken.lbp) {
1446     o = nexttoken.exps;
1447     advance();
1448     if (token.led) {
1449     left = token.led(left);
1450     } else {
1451     error("Expected an operator and instead saw '{a}'.",
1452     token, token.id);
1453     }
1454     }
1455     if (initial && !o) {
1456     warning(
1457     "Expected an assignment or function call and instead saw an expression.",
1458     token);
1459     }
1460     }
1461     if (!option.evil && left && left.value === 'eval') {
1462     warning("eval is evil.", left);
1463     }
1464     return left;
1465     }
1466    
1467    
1468     // Functions for conformance of style.
1469    
1470     function adjacent(left, right) {
1471     left = left || token;
1472     right = right || nexttoken;
1473     if (option.white) {
1474     if (left.character !== right.from) {
1475     warning("Unexpected space after '{a}'.",
1476     nexttoken, left.value);
1477     }
1478     }
1479     }
1480    
1481    
1482     function nospace(left, right) {
1483     left = left || token;
1484     right = right || nexttoken;
1485     if (option.white) {
1486     if (left.line === right.line) {
1487     adjacent(left, right);
1488     }
1489     }
1490     }
1491    
1492    
1493     function nonadjacent(left, right) {
1494     left = left || token;
1495     right = right || nexttoken;
1496     if (option.white) {
1497     if (left.character === right.from) {
1498     warning("Missing space after '{a}'.",
1499     nexttoken, left.value);
1500     }
1501     }
1502     }
1503    
1504     function indentation(bias) {
1505     var i;
1506     if (option.white && nexttoken.id !== '(end)') {
1507     i = indent + (bias || 0);
1508     if (nexttoken.from !== i) {
1509     warning("Expected '{a}' to have an indentation of {b} instead of {c}.",
1510     nexttoken, nexttoken.value, i, nexttoken.from);
1511     }
1512     }
1513     }
1514    
1515     function nolinebreak(t) {
1516     if (t.line !== nexttoken.line) {
1517     warning("Line breaking error '{a}'.", t, t.id);
1518     }
1519     }
1520    
1521    
1522     // Parasitic constructors for making the symbols that will be inherited by
1523     // tokens.
1524    
1525     function symbol(s, p) {
1526     var x = syntax[s];
1527     if (!x || typeof x !== 'object') {
1528     syntax[s] = x = {
1529     id: s,
1530     lbp: p,
1531     value: s
1532     };
1533     }
1534     return x;
1535     }
1536    
1537    
1538     function delim(s) {
1539     return symbol(s, 0);
1540     }
1541    
1542    
1543     function stmt(s, f) {
1544     var x = delim(s);
1545     x.identifier = x.reserved = true;
1546     x.fud = f;
1547     return x;
1548     }
1549    
1550    
1551     function blockstmt(s, f) {
1552     var x = stmt(s, f);
1553     x.block = true;
1554     return x;
1555     }
1556    
1557    
1558     function reserveName(x) {
1559     var c = x.id.charAt(0);
1560     if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
1561     x.identifier = x.reserved = true;
1562     }
1563     return x;
1564     }
1565    
1566    
1567     function prefix(s, f) {
1568     var x = symbol(s, 150);
1569     reserveName(x);
1570     x.nud = (typeof f === 'function') ? f : function () {
1571     if (option.plusplus && (this.id === '++' || this.id === '--')) {
1572     warning("Unexpected use of '{a}'.", this, this.id);
1573     }
1574     parse(150);
1575     return this;
1576     };
1577     return x;
1578     }
1579    
1580    
1581     function type(s, f) {
1582     var x = delim(s);
1583     x.type = s;
1584     x.nud = f;
1585     return x;
1586     }
1587    
1588    
1589     function reserve(s, f) {
1590     var x = type(s, f);
1591     x.identifier = x.reserved = true;
1592     return x;
1593     }
1594    
1595    
1596     function reservevar(s) {
1597     return reserve(s, function () {
1598     return this;
1599     });
1600     }
1601    
1602    
1603     function infix(s, f, p) {
1604     var x = symbol(s, p);
1605     reserveName(x);
1606     x.led = (typeof f === 'function') ? f : function (left) {
1607     nonadjacent(prevtoken, token);
1608     nonadjacent(token, nexttoken);
1609     return [this.id, left, parse(p)];
1610     };
1611     return x;
1612     }
1613    
1614    
1615     function relation(s, f) {
1616     var x = symbol(s, 100);
1617     x.led = function (left) {
1618     nonadjacent(prevtoken, token);
1619     nonadjacent(token, nexttoken);
1620     var right = parse(100);
1621     if ((left && left.id === 'NaN') || (right && right.id === 'NaN')) {
1622     warning("Use the isNaN function to compare with NaN.", this);
1623     } else if (f) {
1624     f.apply(this, [left, right]);
1625     }
1626     return [this.id, left, right];
1627     };
1628     return x;
1629     }
1630    
1631    
1632     function isPoorRelation(node) {
1633     return (node.type === '(number)' && !+node.value) ||
1634     (node.type === '(string)' && !node.value) ||
1635     node.type === 'true' ||
1636     node.type === 'false' ||
1637     node.type === 'undefined' ||
1638     node.type === 'null';
1639     }
1640    
1641    
1642     function assignop(s, f) {
1643     symbol(s, 20).exps = true;
1644     return infix(s, function (left) {
1645     var l;
1646     nonadjacent(prevtoken, token);
1647     nonadjacent(token, nexttoken);
1648     if (adsafe) {
1649     l = left;
1650     do {
1651     if (l.value === 'ADSAFE') {
1652     warning('ADsafe violation.', l);
1653     }
1654     l = l.left;
1655     } while (l);
1656     }
1657     if (left) {
1658     if (left.id === '.' || left.id === '[' ||
1659     (left.identifier && !left.reserved)) {
1660     parse(19);
1661     return left;
1662     }
1663     if (left === syntax['function']) {
1664     warning(
1665     "Expected an identifier in an assignment and instead saw a function invocation.",
1666     token);
1667     }
1668     }
1669     error("Bad assignment.", this);
1670     }, 20);
1671     }
1672    
1673     function bitwise(s, f, p) {
1674     var x = symbol(s, p);
1675     reserveName(x);
1676     x.led = (typeof f === 'function') ? f : function (left) {
1677     if (option.bitwise) {
1678     warning("Unexpected use of '{a}'.", this, this.id);
1679     }
1680     nonadjacent(prevtoken, token);
1681     nonadjacent(token, nexttoken);
1682     return [this.id, left, parse(p)];
1683     };
1684     return x;
1685     }
1686    
1687     function bitwiseassignop(s) {
1688     symbol(s, 20).exps = true;
1689     return infix(s, function (left) {
1690     if (option.bitwise) {
1691     warning("Unexpected use of '{a}'.", this, this.id);
1692     }
1693     nonadjacent(prevtoken, token);
1694     nonadjacent(token, nexttoken);
1695     if (left) {
1696     if (left.id === '.' || left.id === '[' ||
1697     (left.identifier && !left.reserved)) {
1698     parse(19);
1699     return left;
1700     }
1701     if (left === syntax['function']) {
1702     warning(
1703     "Expected an identifier in an assignment, and instead saw a function invocation.",
1704     token);
1705     }
1706     }
1707     error("Bad assignment.", this);
1708     }, 20);
1709     }
1710    
1711    
1712     function suffix(s, f) {
1713     var x = symbol(s, 150);
1714     x.led = function (left) {
1715     if (option.plusplus) {
1716     warning("Unexpected use of '{a}'.", this, this.id);
1717     }
1718     return [f, left];
1719     };
1720     return x;
1721     }
1722    
1723    
1724     function optionalidentifier() {
1725     if (nexttoken.reserved) {
1726     warning("Expected an identifier and instead saw '{a}' (a reserved word).",
1727     nexttoken, nexttoken.id);
1728     }
1729     if (nexttoken.identifier) {
1730     advance();
1731     return token.value;
1732     }
1733     }
1734    
1735    
1736     function identifier() {
1737     var i = optionalidentifier();
1738     if (i) {
1739     return i;
1740     }
1741     if (token.id === 'function' && nexttoken.id === '(') {
1742     warning("Missing name in function statement.");
1743     } else {
1744     error("Expected an identifier and instead saw '{a}'.",
1745     nexttoken, nexttoken.value);
1746     }
1747     }
1748    
1749     function reachable(s) {
1750     var i = 0, t;
1751     if (nexttoken.id !== ';' || noreach) {
1752     return;
1753     }
1754     for (;;) {
1755     t = peek(i);
1756     if (t.reach) {
1757     return;
1758     }
1759     if (t.id !== '(endline)') {
1760     if (t.id === 'function') {
1761     warning(
1762     "Inner functions should be listed at the top of the outer function.", t);
1763     break;
1764     }
1765     warning("Unreachable '{a}' after '{b}'.", t, t.value, s);
1766     break;
1767     }
1768     i += 1;
1769     }
1770     }
1771    
1772    
1773     function statement(noindent) {
1774     var i = indent, r, s = scope, t = nexttoken;
1775    
1776     // We don't like the empty statement.
1777    
1778     if (t.id === ';') {
1779     warning("Unnecessary semicolon.", t);
1780     advance(';');
1781     return;
1782     }
1783    
1784     // Is this a labelled statement?
1785    
1786     if (t.identifier && !t.reserved && peek().id === ':') {
1787     advance();
1788     advance(':');
1789     scope = object(s);
1790     addlabel(t.value, 'label');
1791     if (!nexttoken.labelled) {
1792     warning("Label '{a}' on {b} statement.",
1793     nexttoken, t.value, nexttoken.value);
1794     }
1795     if (jx.test(t.value + ':')) {
1796     warning("Label '{a}' looks like a javascript url.",
1797     t, t.value);
1798     }
1799     nexttoken.label = t.value;
1800     t = nexttoken;
1801     }
1802    
1803     // Parse the statement.
1804    
1805     if (!noindent) {
1806     indentation();
1807     }
1808     r = parse(0, true);
1809    
1810     // Look for the final semicolon.
1811    
1812     if (!t.block) {
1813     if (nexttoken.id !== ';') {
1814     warningAt("Missing semicolon.", token.line,
1815     token.from + token.value.length);
1816     } else {
1817     adjacent(token, nexttoken);
1818     advance(';');
1819     nonadjacent(token, nexttoken);
1820     }
1821     }
1822    
1823     // Restore the indentation.
1824    
1825     indent = i;
1826     scope = s;
1827     return r;
1828     }
1829    
1830    
1831     function statements() {
1832     var a = [];
1833     while (!nexttoken.reach && nexttoken.id !== '(end)') {
1834     if (nexttoken.id === ';') {
1835     warning("Unnecessary semicolon.");
1836     advance(';');
1837     } else {
1838     a.push(statement());
1839     }
1840     }
1841     return a;
1842     }
1843    
1844    
1845     function block(f) {
1846     var a, b = inblock, s = scope;
1847     inblock = f;
1848     if (f) {
1849     scope = object(scope);
1850     }
1851     nonadjacent(token, nexttoken);
1852     var t = nexttoken;
1853     if (nexttoken.id === '{') {
1854     advance('{');
1855     if (nexttoken.id !== '}' || token.line !== nexttoken.line) {
1856     indent += 4;
1857     if (!f && nexttoken.from === indent + 4) {
1858     indent += 4;
1859     }
1860     a = statements();
1861     indent -= 4;
1862     indentation();
1863     }
1864     advance('}', t);
1865     } else {
1866     warning("Expected '{a}' and instead saw '{b}'.",
1867     nexttoken, '{', nexttoken.value);
1868     noreach = true;
1869     a = [statement()];
1870     noreach = false;
1871     }
1872     funct['(verb)'] = null;
1873     scope = s;
1874     inblock = b;
1875     return a;
1876     }
1877    
1878    
1879     // An identity function, used by string and number tokens.
1880    
1881     function idValue() {
1882     return this;
1883     }
1884    
1885    
1886     function countMember(m) {
1887     if (membersOnly && membersOnly[m] !== true) {
1888     warning("Unexpected /*member '{a}'.", nexttoken, m);
1889     }
1890     if (typeof member[m] === 'number') {
1891     member[m] += 1;
1892     } else {
1893     member[m] = 1;
1894     }
1895     }
1896    
1897     function note_implied(token) {
1898     var name = token.value, line = token.line + 1, a = implied[name];
1899     if (!a) {
1900     a = [line];
1901     implied[name] = a;
1902     } else if (a[a.length - 1] !== line) {
1903     a.push(line);
1904     }
1905     }
1906    
1907    
1908     // XML types. Currently we support html and widget.
1909    
1910     var xmltype = {
1911     html: {
1912     doBegin: function (n) {
1913     xtype = 'html';
1914     option.browser = true;
1915     populateGlobals();
1916     },
1917     doTagName: function (n, p) {
1918     var i, t = xmltype.html.tag[n], x;
1919     src = false;
1920     if (!t) {
1921     error("Unrecognized tag '<{a}>'.",
1922     nexttoken,
1923     n === n.toLowerCase() ? n :
1924     n + ' (capitalization error)');
1925     }
1926     x = t.parent;
1927     if (!option.fragment || stack.length !== 1 || !stack[0].fragment) {
1928     if (x) {
1929     if (x.indexOf(' ' + p + ' ') < 0) {
1930     error("A '<{a}>' must be within '<{b}>'.",
1931     token, n, x);
1932     }
1933     } else {
1934     i = stack.length;
1935     do {
1936     if (i <= 0) {
1937     error("A '<{a}>' must be within '<{b}>'.",
1938     token, n, 'body');
1939     }
1940     i -= 1;
1941     } while (stack[i].name !== 'body');
1942     }
1943     }
1944     return t.empty;
1945     },
1946     doAttribute: function (n, a) {
1947     if (!a) {
1948     warning("Missing attribute name.", token);
1949     }
1950     a = a.toLowerCase();
1951     if (n === 'script') {
1952     if (a === 'src') {
1953     src = true;
1954     return 'href';
1955     } else if (a === 'language') {
1956     warning("The 'language' attribute is deprecated.",
1957     token);
1958     return false;
1959     }
1960     } else if (n === 'style') {
1961     if (a === 'type' && option.adsafe) {
1962     warning("Don't bother with 'type'.", token);
1963     }
1964     }
1965     if (href[a] === true) {
1966     return 'href';
1967     }
1968     if (a.slice(0, 2) === 'on') {
1969     if (!option.on) {
1970     warning("Avoid HTML event handlers.");
1971     }
1972     return 'script';
1973     } else {
1974     return 'value';
1975     }
1976     },
1977     doIt: function (n) {
1978     return n === 'script' ? 'script' : n !== 'html' &&
1979     xmltype.html.tag[n].special && 'special';
1980     },
1981     tag: {
1982     a: {},
1983     abbr: {},
1984     acronym: {},
1985     address: {},
1986     applet: {},
1987     area: {empty: true, parent: ' map '},
1988     b: {},
1989     base: {empty: true, parent: ' head '},
1990     bdo: {},
1991     big: {},
1992     blockquote: {},
1993     body: {parent: ' html noframes '},
1994     br: {empty: true},
1995     button: {},
1996     canvas: {parent: ' body p div th td '},
1997     caption: {parent: ' table '},
1998     center: {},
1999     cite: {},
2000     code: {},
2001     col: {empty: true, parent: ' table colgroup '},
2002     colgroup: {parent: ' table '},
2003     dd: {parent: ' dl '},
2004     del: {},
2005     dfn: {},
2006     dir: {},
2007     div: {},
2008     dl: {},
2009     dt: {parent: ' dl '},
2010     em: {},
2011     embed: {},
2012     fieldset: {},
2013     font: {},
2014     form: {},
2015     frame: {empty: true, parent: ' frameset '},
2016     frameset: {parent: ' html frameset '},
2017     h1: {},
2018     h2: {},
2019     h3: {},
2020     h4: {},
2021     h5: {},
2022     h6: {},
2023     head: {parent: ' html '},
2024     html: {},
2025     hr: {empty: true},
2026     i: {},
2027     iframe: {},
2028     img: {empty: true},
2029     input: {empty: true},
2030     ins: {},
2031     kbd: {},
2032     label: {},
2033     legend: {parent: ' fieldset '},
2034     li: {parent: ' dir menu ol ul '},
2035     link: {empty: true, parent: ' head '},
2036     map: {},
2037     menu: {},
2038     meta: {empty: true, parent: ' head noframes noscript '},
2039     noframes: {parent: ' html body '},
2040     noscript: {parent: ' head html noframes '},
2041     object: {},
2042     ol: {},
2043     optgroup: {parent: ' select '},
2044     option: {parent: ' optgroup select '},
2045     p: {},
2046     param: {empty: true, parent: ' applet object '},
2047     pre: {},
2048     q: {},
2049     samp: {},
2050     script: {parent: ' body div frame head iframe p pre span '},
2051     select: {},
2052     small: {},
2053     span: {},
2054     strong: {},
2055     style: {parent: ' head ', special: true},
2056     sub: {},
2057     sup: {},
2058     table: {},
2059     tbody: {parent: ' table '},
2060     td: {parent: ' tr '},
2061     textarea: {},
2062     tfoot: {parent: ' table '},
2063     th: {parent: ' tr '},
2064     thead: {parent: ' table '},
2065     title: {parent: ' head '},
2066     tr: {parent: ' table tbody thead tfoot '},
2067     tt: {},
2068     u: {},
2069     ul: {},
2070     'var': {}
2071     }
2072     },
2073     widget: {
2074     doBegin: function (n) {
2075     xtype = 'widget';
2076     option.widget = true;
2077     option.cap = true;
2078     populateGlobals();
2079     },
2080     doTagName: function (n, p) {
2081     var t = xmltype.widget.tag[n];
2082     if (!t) {
2083     error("Unrecognized tag '<{a}>'.", nexttoken, n);
2084     }
2085     var x = t.parent;
2086     if (x.indexOf(' ' + p + ' ') < 0) {
2087     error("A '<{a}>' must be within '<{b}>'.",
2088     token, n, x);
2089     }
2090     },
2091     doAttribute: function (n, a) {
2092     var t = xmltype.widget.tag[a];
2093     if (!t) {
2094     error("Unrecognized attribute '<{a} {b}>'.", nexttoken, n, a);
2095     }
2096     var x = t.parent;
2097     if (x.indexOf(' ' + n + ' ') < 0) {
2098     error("Attribute '{a}' does not belong in '<{b}>'.", nexttoken, a, n);
2099     }
2100     return t.script ?
2101     'script' :
2102     a === 'name' && n !== 'setting' ?
2103     'define' : 'string';
2104     },
2105     doIt: function (n) {
2106     var x = xmltype.widget.tag[n];
2107     return x && x.script && 'script';
2108     },
2109     tag: {
2110     "about-box": {parent: ' widget '},
2111     "about-image": {parent: ' about-box '},
2112     "about-text": {parent: ' about-box '},
2113     "about-version": {parent: ' about-box '},
2114     action: {parent: ' widget ', script: true},
2115     alignment: {parent: ' canvas frame image scrollbar text textarea window '},
2116     anchorstyle: {parent: ' text '},
2117     author: {parent: ' widget '},
2118     autohide: {parent: ' scrollbar '},
2119     beget: {parent: ' canvas frame image scrollbar text window '},
2120     bgcolor: {parent: ' text textarea '},
2121     bgcolour: {parent: ' text textarea '},
2122     bgopacity: {parent: ' text textarea '},
2123     canvas: {parent: ' frame window '},
2124     charset: {parent: ' script '},
2125     checked: {parent: ' image menuitem '},
2126     cliprect: {parent: ' image '},
2127     color: {parent: ' about-text about-version shadow text textarea '},
2128     colorize: {parent: ' image '},
2129     colour: {parent: ' about-text about-version shadow text textarea '},
2130     columns: {parent: ' textarea '},
2131     company: {parent: ' widget '},
2132     contextmenuitems: {parent: ' canvas frame image scrollbar text textarea window '},
2133     copyright: {parent: ' widget '},
2134     data: {parent: ' about-text about-version text textarea '},
2135     debug: {parent: ' widget '},
2136     defaultvalue: {parent: ' preference '},
2137     defaulttracking: {parent: ' widget '},
2138     description: {parent: ' preference '},
2139     directory: {parent: ' preference '},
2140     editable: {parent: ' textarea '},
2141     enabled: {parent: ' menuitem '},
2142     extension: {parent: ' preference '},
2143     file: {parent: ' action preference '},
2144     fillmode: {parent: ' image '},
2145     font: {parent: ' about-text about-version text textarea '},
2146     fontstyle: {parent: ' textarea '},
2147     frame: {parent: ' frame window '},
2148     group: {parent: ' preference '},
2149     halign: {parent: ' canvas frame image scrollbar text textarea '},
2150     handlelinks: {parent: ' textarea '},
2151     height: {parent: ' canvas frame image scrollbar text textarea window '},
2152     hidden: {parent: ' preference '},
2153     hlinesize: {parent: ' frame '},
2154     hoffset: {parent: ' about-text about-version canvas frame image scrollbar shadow text textarea window '},
2155     hotkey: {parent: ' widget '},
2156     hregistrationpoint: {parent: ' canvas frame image scrollbar text '},
2157     hscrollbar: {parent: ' frame '},
2158     hsladjustment: {parent: ' image '},
2159     hsltinting: {parent: ' image '},
2160     icon: {parent: ' preferencegroup '},
2161     id: {parent: ' canvas frame hotkey image preference text textarea timer scrollbar widget window '},
2162     image: {parent: ' about-box frame window widget '},
2163     interval: {parent: ' action timer '},
2164     key: {parent: ' hotkey '},
2165     kind: {parent: ' preference '},
2166     level: {parent: ' window '},
2167     lines: {parent: ' textarea '},
2168     loadingsrc: {parent: ' image '},
2169     locked: {parent: ' window '},
2170     max: {parent: ' scrollbar '},
2171     maxlength: {parent: ' preference '},
2172     menuitem: {parent: ' contextmenuitems '},
2173     min: {parent: ' scrollbar '},
2174     minimumversion: {parent: ' widget '},
2175     minlength: {parent: ' preference '},
2176     missingsrc: {parent: ' image '},
2177     modifier: {parent: ' hotkey '},
2178     name: {parent: ' canvas frame hotkey image preference preferencegroup scrollbar setting text textarea timer widget window '},
2179     notsaved: {parent: ' preference '},
2180     onclick: {parent: ' canvas frame image scrollbar text textarea ', script: true},
2181     oncontextmenu: {parent: ' canvas frame image scrollbar text textarea window ', script: true},
2182     ondragdrop: {parent: ' canvas frame image scrollbar text textarea ', script: true},
2183     ondragenter: {parent: ' canvas frame image scrollbar text textarea ', script: true},
2184     ondragexit: {parent: ' canvas frame image scrollbar text textarea ', script: true},
2185     onfirstdisplay: {parent: ' window ', script: true},
2186     ongainfocus: {parent: ' textarea window ', script: true},
2187     onkeydown: {parent: ' hotkey text textarea window ', script: true},
2188     onkeypress: {parent: ' textarea window ', script: true},
2189     onkeyup: {parent: ' hotkey text textarea window ', script: true},
2190     onimageloaded: {parent: ' image ', script: true},
2191     onlosefocus: {parent: ' textarea window ', script: true},
2192     onmousedown: {parent: ' canvas frame image scrollbar text textarea window ', script: true},
2193     onmousedrag: {parent: ' canvas frame image scrollbar text textarea window ', script: true},
2194     onmouseenter: {parent: ' canvas frame image scrollbar text textarea window ', script: true},
2195     onmouseexit: {parent: ' canvas frame image scrollbar text textarea window ', script: true},
2196     onmousemove: {parent: ' canvas frame image scrollbar text textarea window ', script: true},
2197     onmouseup: {parent: ' canvas frame image scrollbar text textarea window ', script: true},
2198     onmousewheel: {parent: ' frame ', script: true},
2199     onmulticlick: {parent: ' canvas frame image scrollbar text textarea window ', script: true},
2200     onselect: {parent: ' menuitem ', script: true},
2201     ontextinput: {parent: ' window ', script: true},
2202     ontimerfired: {parent: ' timer ', script: true},
2203     onvaluechanged: {parent: ' scrollbar ', script: true},
2204     opacity: {parent: ' canvas frame image scrollbar shadow text textarea window '},
2205     option: {parent: ' preference widget '},
2206     optionvalue: {parent: ' preference '},
2207     order: {parent: ' preferencegroup '},
2208     orientation: {parent: ' scrollbar '},
2209     pagesize: {parent: ' scrollbar '},
2210     preference: {parent: ' widget '},
2211     preferencegroup: {parent: ' widget '},
2212     remoteasync: {parent: ' image '},
2213     requiredplatform: {parent: ' widget '},
2214     root: {parent: ' window '},
2215     rotation: {parent: ' canvas frame image scrollbar text '},
2216     script: {parent: ' widget ', script: true},
2217     scrollbar: {parent: ' frame text textarea window '},
2218     scrolling: {parent: ' text '},
2219     scrollx: {parent: ' frame '},
2220     scrolly: {parent: ' frame '},
2221     secure: {parent: ' preference textarea '},
2222     setting: {parent: ' settings '},
2223     settings: {parent: ' widget '},
2224     shadow: {parent: ' about-text about-version text window '},
2225     size: {parent: ' about-text about-version text textarea '},
2226     spellcheck: {parent: ' textarea '},
2227     src: {parent: ' image script '},
2228     srcheight: {parent: ' image '},
2229     srcwidth: {parent: ' image '},
2230     style: {parent: ' about-text about-version canvas frame image preference scrollbar text textarea window '},
2231     subviews: {parent: ' frame '},
2232     superview: {parent: ' canvas frame image scrollbar text textarea '},
2233     text: {parent: ' frame text textarea window '},
2234     textarea: {parent: ' frame window '},
2235     timer: {parent: ' widget '},
2236     thumbcolor: {parent: ' scrollbar textarea '},
2237     ticking: {parent: ' timer '},
2238     ticks: {parent: ' preference '},
2239     ticklabel: {parent: ' preference '},
2240     tileorigin: {parent: ' image '},
2241     title: {parent: ' menuitem preference preferencegroup window '},
2242     tooltip: {parent: ' frame image text textarea '},
2243     tracking: {parent: ' canvas image '},
2244     trigger: {parent: ' action '},
2245     truncation: {parent: ' text '},
2246     type: {parent: ' preference '},
2247     url: {parent: ' about-box about-text about-version '},
2248     usefileicon: {parent: ' image '},
2249     valign: {parent: ' canvas frame image scrollbar text textarea '},
2250     value: {parent: ' preference scrollbar setting '},
2251     version: {parent: ' widget '},
2252     visible: {parent: ' canvas frame image scrollbar text textarea window '},
2253     vlinesize: {parent: ' frame '},
2254     voffset: {parent: ' about-text about-version canvas frame image scrollbar shadow text textarea window '},
2255     vregistrationpoint: {parent: ' canvas frame image scrollbar text '},
2256     vscrollbar: {parent: ' frame '},
2257     width: {parent: ' canvas frame image scrollbar text textarea window '},
2258     window: {parent: ' canvas frame image scrollbar text textarea widget '},
2259     wrap: {parent: ' text '},
2260     zorder: {parent: ' canvas frame image scrollbar text textarea window '}
2261     }
2262     }
2263     };
2264    
2265     function xmlword(tag) {
2266     var w = nexttoken.value;
2267     if (!nexttoken.identifier) {
2268     if (nexttoken.id === '<') {
2269     if (tag) {
2270     error("Expected '{a}' and instead saw '{b}'.",
2271     token, '&lt;', '<');
2272     } else {
2273     error("Missing '{a}'.", token, '>');
2274     }
2275     } else if (nexttoken.id === '(end)') {
2276     error("Bad structure.");
2277     } else {
2278     warning("Missing quote.", token);
2279     }
2280     }
2281     advance();
2282     while (nexttoken.id === '-' || nexttoken.id === ':') {
2283     w += nexttoken.id;
2284     advance();
2285     if (!nexttoken.identifier) {
2286     error("Bad name '{a}'.", nexttoken, w + nexttoken.value);
2287     }
2288     w += nexttoken.value;
2289     advance();
2290     }
2291     if (option.cap) {
2292     w = w.toLowerCase();
2293     }
2294     return w;
2295     }
2296    
2297     function closetag(n) {
2298     return '</' + n + '>';
2299     }
2300    
2301     function xml() {
2302     var a, e, n, q, t, wmode;
2303     xmode = 'xml';
2304     stack = null;
2305     for (;;) {
2306     switch (nexttoken.value) {
2307     case '<':
2308     if (!stack) {
2309     stack = [];
2310     }
2311     advance('<');
2312     t = nexttoken;
2313     n = xmlword(true);
2314     t.name = n;
2315     if (!xtype) {
2316     if (option.fragment && option.adsafe &&
2317     n !== 'div' && n !== 'iframe') {
2318     error("ADsafe HTML fragment violation.", token);
2319     }
2320     if (xmltype[n]) {
2321     xmltype[n].doBegin();
2322     n = xtype;
2323     e = false;
2324     } else {
2325     if (option.fragment) {
2326     xmltype.html.doBegin();
2327     } else {
2328     error("Unrecognized tag '<{a}>'.", nexttoken, n);
2329     }
2330     }
2331     } else {
2332     if (stack.length === 0) {
2333     error("What the hell is this?");
2334     }
2335     e = xmltype[xtype].doTagName(n,
2336     stack[stack.length - 1].name);
2337     }
2338     t.type = n;
2339     for (;;) {
2340     if (nexttoken.id === '/') {
2341     advance('/');
2342     if (nexttoken.id !== '>') {
2343     warning("Expected '{a}' and instead saw '{b}'.",
2344     nexttoken, '>', nexttoken.value);
2345     }
2346     e = true;
2347     break;
2348     }
2349     if (nexttoken.id && nexttoken.id.substr(0, 1) === '>') {
2350     break;
2351     }
2352     a = xmlword();
2353     switch (xmltype[xtype].doAttribute(n, a)) {
2354     case 'script':
2355     xmode = 'string';
2356     advance('=');
2357     q = nexttoken.id;
2358     if (q !== '"' && q !== "'") {
2359     error("Missing quote.");
2360     }
2361     xmode = q;
2362     wmode = option.white;
2363     option.white = false;
2364     advance(q);
2365     statements();
2366     option.white = wmode;
2367     if (nexttoken.id !== q) {
2368     error("Missing close quote on script attribute.");
2369     }
2370     xmode = 'xml';
2371     advance(q);
2372     break;
2373     case 'value':
2374     advance('=');
2375     if (!nexttoken.identifier &&
2376     nexttoken.type !== '(string)' &&
2377     nexttoken.type !== '(number)') {
2378     error("Bad value '{a}'.",
2379     nexttoken, nexttoken.value);
2380     }
2381     advance();
2382     break;
2383     case 'string':
2384     advance('=');
2385     if (nexttoken.type !== '(string)') {
2386     error("Bad value '{a}'.",
2387     nexttoken, nexttoken.value);
2388     }
2389     advance();
2390     break;
2391     case 'href':
2392     advance('=');
2393     if (nexttoken.type !== '(string)') {
2394     error("Bad value '{a}'.",
2395     nexttoken, nexttoken.value);
2396     }
2397     if (option.adsafe && ux.test(nexttoken.value)) {
2398     error("ADsafe URL violation.");
2399     }
2400     advance();
2401     break;
2402     case 'define':
2403     advance('=');
2404     if (nexttoken.type !== '(string)') {
2405     error("Bad value '{a}'.",
2406     nexttoken, nexttoken.value);
2407     }
2408     addlabel(nexttoken.value, 'var');
2409     advance();
2410     break;
2411     default:
2412     if (nexttoken.id === '=') {
2413     advance('=');
2414     if (!nexttoken.identifier &&
2415     nexttoken.type !== '(string)' &&
2416     nexttoken.type !== '(number)') {
2417     error("Bad value '{a}'.",
2418     nexttoken, nexttoken.value);
2419     }
2420     advance();
2421     }
2422     }
2423     }
2424     switch (xmltype[xtype].doIt(n)) {
2425     case 'script':
2426     xmode = 'script';
2427     advance('>');
2428     indent = nexttoken.from;
2429     if (src) {
2430     if (option.fragment && option.adsafe) {
2431     warning("ADsafe script violation.", token);
2432     }
2433     } else {
2434     statements();
2435     }
2436     if (nexttoken.id !== '</' && nexttoken.id !== '(end)') {
2437     warning("Expected '{a}' and instead saw '{b}'.",
2438     nexttoken, '<\/script>', nexttoken.value);
2439     }
2440     xmode = 'xml';
2441     break;
2442     case 'special':
2443     e = true;
2444     n = closetag(t.name);
2445     if (!lex.skip(n)) {
2446     error("Missing '{a}'.", t, n);
2447     }
2448     break;
2449     default:
2450     lex.skip('>');
2451     }
2452     if (!e) {
2453     stack.push(t);
2454     }
2455     break;
2456     case '</':
2457     advance('</');
2458     n = xmlword(true);
2459     t = stack.pop();
2460     if (!t) {
2461     error("Unexpected '{a}'.", nexttoken, closetag(n));
2462     }
2463     if (t.name !== n) {
2464     error("Expected '{a}' and instead saw '{b}'.",
2465     nexttoken, closetag(t.name), closetag(n));
2466     }
2467     if (nexttoken.id !== '>') {
2468     error("Missing '{a}'.", nexttoken, '>');
2469     }
2470     if (stack.length > 0) {
2471     lex.skip('>');
2472     } else {
2473     advance('>');
2474     }
2475     break;
2476     case '<!':
2477     if (option.adsafe) {
2478     error("ADsafe HTML violation.");
2479     }
2480     for (;;) {
2481     advance();
2482     if (nexttoken.id === '>') {
2483     break;
2484     }
2485     if (nexttoken.id === '<' || nexttoken.id === '(end)') {
2486     error("Missing '{a}'.", token, '>');
2487     }
2488     }
2489     lex.skip('>');
2490     break;
2491     case '<!--':
2492     if (option.adsafe) {
2493     error("ADsafe comment violation.");
2494     }
2495     lex.skip('-->');
2496     break;
2497     case '<%':
2498     if (option.adsafe) {
2499     error(