Ticket #2571: syntaxDiff.txt

File syntaxDiff.txt, 102.1 kB (added by guest, 21 months ago)

2007-4-12 revision of syntax checker.

Line 
1Index: syntax.js
2===================================================================
3--- syntax.js   (revision 0)
4+++ syntax.js   (revision 1277)
5@@ -0,0 +1,3 @@
6+dojo.provide("dojo.syntax");
7+dojo.require('dojo.syntax.*');
8+
9
10Property changes on: syntax.js
11___________________________________________________________________
12Name: svn:eol-style
13   + native
14
15Index: syntax/LICENSE
16===================================================================
17--- syntax/LICENSE      (revision 0)
18+++ syntax/LICENSE      (revision 1277)
19@@ -0,0 +1,28 @@
20+License Disclaimer:
21+       
22+       All contents of this directory are Copyright (c) the Dojo Foundation, with the
23+       following exceptions:
24+       -------------------------------------------------------------------------------
25+       
26+       jslint.js:
27+               * Copyright (c) 2002 Douglas Crockford  (www.JSLint.com)
28+               * Distributed under a BSD like license:
29+                       Permission is hereby granted, free of charge, to any person obtaining a copy of
30+                       this software and associated documentation files (the "Software"), to deal in
31+                       the Software without restriction, including without limitation the rights to
32+                       use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
33+                       of the Software, and to permit persons to whom the Software is furnished to do
34+                       so, subject to the following conditions:
35+
36+                       The above copyright notice and this permission notice shall be included in all
37+                       copies or substantial portions of the Software.
38+
39+                       The Software shall be used for Good, not Evil.
40+
41+                       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42+                       IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
43+                       FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
44+                       AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
45+                       LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
46+                       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
47+                       SOFTWARE.
48\ No newline at end of file
49
50Property changes on: syntax/LICENSE
51___________________________________________________________________
52Name: svn:eol-style
53   + native
54
55Index: syntax/__package__.js
56===================================================================
57--- syntax/__package__.js       (revision 0)
58+++ syntax/__package__.js       (revision 1277)
59@@ -0,0 +1,8 @@
60+dojo.kwCompoundRequire({
61+       common: [
62+               "dojo.syntax",
63+               "dojo.syntax.common",
64+               "dojo.syntax.jslint"
65+       ]
66+});
67+dojo.provide("dojo.syntax.*");
68\ No newline at end of file
69
70Property changes on: syntax/__package__.js
71___________________________________________________________________
72Name: svn:eol-style
73   + native
74
75Index: syntax/common.js
76===================================================================
77--- syntax/common.js    (revision 0)
78+++ syntax/common.js    (revision 1277)
79@@ -0,0 +1,188 @@
80+dojo.provide('dojo.syntax.common');
81+dojo.require('dojo.syntax.jslint');
82+dojo.require('dojo.lang.*');
83+// The override happens at the very end...
84+
85+
86+dojo.syntax.check = function(/* string */ code, /* string */name,/* string */checker){
87+       //summary: check code against checker.
88+       //              code is the actual JS code to check.
89+       //              name is the uri generally.
90+       //              checker is which checker to use.  currently only 'jslint' is supported.
91+       //
92+       //      in djConfig: syntaxWarn is a boolean.
93+       //              if true, it will continue running on error.. otherwise it will stop
94+       //      in djConfig: syntaxOptions:
95+       //              {
96+    //    browser    : true if the standard browser globals should be predefined
97+    //    cap        : true if upper case HTML should be allowed
98+    //    debug      : true if debugger statements should be allowed
99+    //    eqeqeq     : true if === should be required
100+    //    evil       : true if eval should be allowed
101+    //    jscript    : true if jscript deviations should be allowed
102+    //    laxLineEnd : true if line breaks should not be checked
103+    //    passfail   : true if the scan should stop on first error
104+    //    plusplus   : true if increment/decrement should not be allowed
105+    //    redef      : true if var redefinition should be allowed
106+    //    rhino      : true if the Rhino environment globals should be predefined
107+    //    undef      : true if undefined variables are errors
108+    //    white      : true if strict whitespace rules apply
109+    //    widget     : true if the Yahoo Widgets globals should be predefined
110+       //    skipDojo   : true if skipping dojo sources should be done.
111+       //        strict         : true if we should be VERY strict about syntax.
112+       //        warn           : true if we should only warn, and keep loading despite errors.
113+    //}
114+       //      returns false on error.
115+       if (checker == 'jslint'){
116+               options = djConfig.syntaxOptions;
117+               //dojo.debug('syntax options:',options);
118+               if (!options) {
119+                       options = {
120+                               widget:false,
121+                               undef:true,
122+                               browser:true,
123+                               skipDojo:true,
124+                               strict:false
125+                       };
126+               }
127+               if (!options.strict){
128+                       //NOT strict mode
129+                       options.jscript = true;
130+                       options.skipDojo = true;
131+               }
132+               else{
133+                       //Strict mode.
134+                       options.jscript = false;
135+                       options.skipDojo = false;
136+               }
137+               if ((options.skipDojo)&&(name.indexOf('dojo/src') != -1)) {
138+                       //dojo.debug('skipping:',name);
139+                       return true;
140+               }
141+               //Time to actually check.
142+               var err = dojo.syntax.jslint(code,options);
143+               if (!err) {
144+                       //dojo.debug('error');
145+                       //var errs = dojo.syntax.jslint.errors;
146+                       dojo.syntax.prettyPrint(dojo.syntax.jslint.errors,name);
147+                       if (options.warn){
148+                               //return a fake clean..
149+                               return true;
150+                       }
151+                       return false;
152+               } else {
153+                       //no error happened.
154+                       return true;
155+               }
156+       } else {
157+               dojo.debug('ERROR, jslint is the only checker supported right now');
158+       }
159+};
160+
161+dojo.syntax.moduleExists = function(name){
162+       for (var module in dojo.hostenv.modulePrefixes_) {
163+               if (module == name){
164+                       return true;
165+               }
166+               else if (module.indexOf('.')){
167+                       var arr = [];
168+                       arr = module.split('.');
169+                       if (arr[0] == name){
170+                               return true;
171+                       }
172+                       }
173+               else {
174+                       return false;
175+               }
176+               }       
177+};
178+
179+dojo.syntax.prettyPrint = function(errs,name){
180+       //summary: pretty print the errors.
181+       //      errs is a [] of {}'s that have these elements:
182+       //{
183+    //    line      : The line (relative to 0) at which the lint was found
184+    //    character : The character (relative to 0) at which the lint was found
185+    //    reason    : The problem
186+    //    evidence  : The text line in which the problem occurred
187+    //}
188+       var node = document.createElement('div');
189+       var p = document.createElement('h1');
190+       p.innerHTML = 'error in:'+name;
191+       node.appendChild(p);
192+       var t = dojo.syntax.makeTable(errs);
193+       node.appendChild(t);
194+       //we may not have a document.body element to append to, if not, then we well do evil stuff.
195+       if (document.body){
196+               document.body.appendChild(node);
197+       }
198+       else {
199+               // I am EVIL, but I am a worst case.
200+               document.write(node.innerHTML);
201+       }
202+};
203+
204+dojo.syntax.makeTableHeader = function(obj){
205+       var th = document.createElement('TR');
206+       for (var i in obj) {
207+               var newelt = document.createElement('TD');
208+               newelt.innerHTML=i;
209+               th.appendChild(newelt);
210+               }
211+       return th;
212+};
213+dojo.syntax.makeTable = function(list,opts){
214+       //if opts.edit, then I need:
215+       // opts.id  which item(by number) is the cp_id for this row.
216+       var table = document.createElement('TABLE');
217+       table.border=1;
218+       var nums=0;
219+       for (var obj in list) {
220+               obj = list[obj];
221+               if (nums === 0) {table.appendChild(dojo.syntax.makeTableHeader(obj))};
222+               var newRow = document.createElement('TR');
223+               for (var i in obj) {
224+                       //dojo.debug('new td %s:%s',i,obj[i]);
225+                       var newelt = document.createElement('TD');
226+                       newelt.innerHTML=obj[i];
227+                       newRow.appendChild(newelt);
228+               }
229+               nums += 1;
230+               table.appendChild(newRow);
231+       }
232+return table;
233+};
234+
235+dojo.syntax._realGetText = dojo.hostenv.getText;
236+dojo.syntax.getText = function(uri, async_cb, fail_ok){
237+       //dojo.debug('syntax getText called:',uri,async_cb,fail_ok);
238+    var contents = dojo.syntax._realGetText.apply(dojo.hostenv, arguments);
239+       //dojo.debug('contents gotten',contents);
240+       if(contents){
241+               if (dojo.lang.isString(uri)){
242+                       uri = uri.toLowerCase();
243+               }
244+               else {
245+                       //assume it's a dojo.uri.Uri object.
246+                       uri = uri.toString();
247+               }
248+               if (uri.indexOf('.js') != -1){
249+                       dojo.debug('syntax checking:',uri);
250+                       if (dojo.syntax.check(contents,uri,'jslint') == false){
251+                               //check failed.
252+                               if (!fail_ok){
253+                                       var err = Error("Unable to load "+uri+" because of a syntax error");
254+                                       throw err;
255+                               }
256+                               //we return null, unless we are not supposed to.
257+                               //dojo.debug('returning badness');
258+                               return null;
259+                       }
260+               }
261+    }
262+//dojo.debug('syntax: all done');
263+return contents;
264+
265+};
266+
267+dojo.hostenv.getText = dojo.syntax.getText;
268\ No newline at end of file
269
270Property changes on: syntax/common.js
271___________________________________________________________________
272Name: svn:eol-style
273   + native
274
275Index: syntax/TODO
276===================================================================
277--- syntax/TODO (revision 0)
278+++ syntax/TODO (revision 1277)
279@@ -0,0 +1,47 @@
280+http://trac.dojotoolkit.org/ticket/2571
281+jamestag (jburke on trac) is my contact
282+
283+slightlyoff: birlcathy: and bug jamestag early next week for status on what hooks will be available
284+
285+Hi all!
286+
287+I started work on a new feature, that I want to help me with JS syntax(since I never can remember it..)  I hack into dojo.hostenv.loadUri and put a syntax checker in before an eval() is called. 
288+
289+Anyways, I never expected to find all sorts of errors in dojo itself!
290+  http://www.yuma.ca/tech/js/baddojo.html
291+
292+is a list of most of the packages, and the problems.. It's not pretty.. so I made:
293+http://www.yuma.ca/tech/js/testsyntax.html
294+
295+Which will let you test a particular module. (you will prolly want to refresh the page before trying another one or check the bottom!).
296+
297+anyways, there is lot's of errors.  It doesn't do formatting errors, only syntax.  It's totally hacked into dojo right now, but dojo.syntax.* is the module.
298+
299+
300+
301+Syntax feature
302+
303+Alter dojo.require() so that when code is pulled in from sources, we verify it against a syntax checker.. the beauty is then, your code STAYS clean because everytime you run it, it will get mad.  This is only true on debug versions(djConfig.isDebug:true).  Uses jslint.com's syntax checker currently. Other checkers could be used, but no others are supported currently.
304+
305+features:
306+  allow stopping on error, or just warning on error.  djConfig.syntaxWarn ?
307+  Follow dojo JS guidelines as much as possible.
308+  allow it to skip dojo srcs, and only get upset with stuff in your custom namespace? 
309+
310+
311+
312+current implementation at: http://www.yuma.ca/tech/js/dojo/src/syntax/
313+demo/testcase: http://www.yuma.ca/tech/js/testsyntax.html
314+
315+
316+
317+QUESTIONS (for non strict mode):
318+  allow variable declaration in block?  (JS is not block-scoped)
319+                       if (blah){
320+                       var tito = blah;
321+                       }
322+  using == to compare (type coercion bad?)
323+               if (blah == 0)
324+  unnecessary semicolons:
325+       try { this.domNode.focus(); } catch(e2) {};
326+
327Index: syntax/jslint.js
328===================================================================
329--- syntax/jslint.js    (revision 0)
330+++ syntax/jslint.js    (revision 1277)
331@@ -0,0 +1,2745 @@
332+dojo.provide("dojo.syntax.jslint");
333+// jslint.js
334+// 2007-03-05
335+/*
336+Copyright (c) 2002 Douglas Crockford  (www.JSLint.com)
337+
338+Permission is hereby granted, free of charge, to any person obtaining a copy of
339+this software and associated documentation files (the "Software"), to deal in
340+the Software without restriction, including without limitation the rights to
341+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
342+of the Software, and to permit persons to whom the Software is furnished to do
343+so, subject to the following conditions:
344+
345+The above copyright notice and this permission notice shall be included in all
346+copies or substantial portions of the Software.
347+
348+The Software shall be used for Good, not Evil.
349+
350+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
351+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
352+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
353+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
354+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
355+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
356+SOFTWARE.
357+*/
358+
359+
360+/*
361+    JSLINT is a global function. It takes two parameters.
362+
363+        var myResult = JSLINT(source, option);
364+
365+    The first parameter is either a string or an array of strings. If it is a
366+    string, it will be split on '\n' or '\r'. If it is an array of strings, it
367+    is assumed that each string represents one line. The source can be a
368+    JavaScript text, or HTML text, or a Konfabulator text.
369+
370+    The second parameter is an optional object of options which control the
371+    operation of JSLINT. All of the options are booleans. All are optional and
372+    have a default value of false.
373+
374+    {
375+        browser    : true if the standard browser globals should be predefined
376+        cap        : true if upper case HTML should be allowed
377+        debug      : true if debugger statements should be allowed
378+        eqeqeq     : true if === should be required
379+        evil       : true if eval should be allowed
380+        jscript    : true if jscript deviations should be allowed
381+        laxLineEnd : true if line breaks should not be checked
382+        passfail   : true if the scan should stop on first error
383+        plusplus   : true if increment/decrement should not be allowed
384+        redef      : true if var redefinition should be allowed
385+        rhino      : true if the Rhino environment globals should be predefined
386+        undef      : true if undefined variables are errors
387+        white      : true if strict whitespace rules apply
388+        widget     : true if the Yahoo Widgets globals should be predefined
389+               strict     : true if we should be normal jslint mode, false and we be very very lax...
390+    }
391+
392+    If it checks out, JSLINT returns true. Otherwise, it returns false.
393+
394+    If false, you can inspect JSLINT.errors to find out the problems.
395+    JSLINT.errors is an array of objects containing these members:
396+
397+    {
398+        line      : The line (relative to 0) at which the lint was found
399+        character : The character (relative to 0) at which the lint was found
400+        reason    : The problem
401+        evidence  : The text line in which the problem occurred
402+    }
403+
404+    If a fatal error was found, a null will be the last element of the
405+    JSLINT.errors array.
406+
407+    You can request a Function Report, which shows all of the functions
408+    and the parameters and vars that they use. This can be used to find
409+    implied global variables and other problems. The report is in HTML and
410+    can be inserted in a <body>.
411+
412+        var myReport = JSLINT.report(option);
413+
414+    If the option is true, then the report will be limited to only errors.
415+*/
416+
417+String.prototype.entityify = function () {
418+    return this.
419+        replace(/&/g, '&amp;').
420+        replace(/</g, '&lt;').
421+        replace(/>/g, '&gt;');
422+};
423+
424+String.prototype.isAlpha = function () {
425+    return (this >= 'a' && this <= 'z\uffff') ||
426+        (this >= 'A' && this <= 'Z\uffff');
427+};
428+
429+
430+String.prototype.isDigit = function () {
431+    return (this >= '0' && this <= '9');
432+};
433+
434+
435+// We build the application inside a function so that we produce only a single
436+// global variable. The function will be invoked, its return value is the JSLINT
437+// function itself.
438+
439+//var dojo.JSLINT;
440+dojo.syntax.jslint = function () {
441+
442+    var anonname,
443+
444+// browser contains a set of global names which are commonly provided by a
445+// web browser environment.
446+
447+        browser = {
448+            alert: true,
449+            blur: true,
450+            clearInterval: true,
451+            clearTimeout: true,
452+            close: true,
453+            closed: true,
454+            confirm: true,
455+            console: true,
456+            Debug: true,
457+            defaultStatus: true,
458+            document: true,
459+            event: true,
460+            focus: true,
461+            frames: true,
462+            history: true,
463+            Image: true,
464+            length: true,
465+            location: true,
466+            moveBy: true,
467+            moveTo: true,
468+            name: true,
469+            navigator: true,
470+            onblur: true,
471+            onerror: true,
472+            onfocus: true,
473+            onload: true,
474+            onresize: true,
475+            onunload: true,
476+            open: true,
477+            opener: true,
478+            opera: true,
479+            parent: true,
480+            print: true,
481+            prompt: true,
482+            resizeBy: true,
483+            resizeTo: true,
484+            screen: true,
485+            scroll: true,
486+            scrollBy: true,
487+            scrollTo: true,
488+            self: true,
489+            setInterval: true,
490+            setTimeout: true,
491+            status: true,
492+            top: true,
493+            window: true,
494+            XMLHttpRequest: true,
495+                       dojo: true,
496+                       dj_undef: true,
497+                       djConfig: true
498+        },
499+        funlab, funstack, functions, globals,
500+
501+// konfab contains the global names which are provided to a Yahoo
502+// (fna Konfabulator) widget.
503+
504+        konfab = {
505+            alert: true,
506+            animator: true,
507+            appleScript: true,
508+            beep: true,
509+            bytesToUIString: true,
510+            chooseColor: true,
511+            chooseFile: true,
512+            chooseFolder: true,
513+            convertPathToHFS: true,
514+            convertPathToPlatform: true,
515+            closeWidget: true,
516+            CustomAnimation: true,
517+            escape: true,
518+            FadeAnimation: true,
519+            focusWidget: true,
520+            form: true,
521+            include: true,
522+            isApplicationRunning: true,
523+            iTunes: true,
524+            konfabulatorVersion: true,
525+            log: true,
526+            MoveAnimation: true,
527+            openURL: true,
528+            play: true,
529+            popupMenu: true,
530+            print: true,
531+            prompt: true,
532+            reloadWidget: true,
533+            resolvePath: true,
534+            resumeUpdates: true,
535+            RotateAnimation: true,
536+            runCommand: true,
537+            runCommandInBg: true,
538+            saveAs: true,
539+            savePreferences: true,
540+            showWidgetPreferences: true,
541+            sleep: true,
542+            speak: true,
543+            suppressUpdates: true,
544+            tellWidget: true,
545+            unescape: true,
546+            updateNow: true,
547+            yahooCheckLogin: true,
548+            yahooLogin: true,
549+            yahooLogout: true,
550+            COM: true,
551+            filesystem: true,
552+            preferenceGroups: true,
553+            preferences: true,
554+            screen: true,
555+            system: true,
556+            URL: true,
557+            XMLDOM: true,
558+            XMLHttpRequest: true
559+        },
560+        lines, lookahead, member, nexttoken, noreach, option, quit,
561+        rhino = {
562+            defineClass: true,
563+            deserialize: true,
564+            gc: true,
565+            help: true,
566+            load: true,
567+            loadClass: true,
568+            print: true,
569+            quit: true,
570+            readFile: true,
571+            readUrl: true,
572+            runCommand: true,
573+            seal: true,
574+            serialize: true,
575+            spawn: true,
576+            sync: true,
577+            toint32: true,
578+            version: true
579+        },
580+        stack,
581+
582+// standard contains the global names that are provided by standard JavaScript.
583+
584+        standard = {
585+            Array: true,
586+            Boolean: true,
587+            Date: true,
588+            decodeURI: true,
589+            decodeURIComponent: true,
590+            encodeURI: true,
591+            encodeURIComponent: true,
592+            Error: true,
593+            escape: true,
594+            'eval': true,
595+            EvalError: true,
596+            Function: true,
597+            isFinite: true,
598+            isNaN: true,
599+            Math: true,
600+            Number: true,
601+            Object: true,
602+            parseInt: true,
603+            parseFloat: true,
604+            RangeError: true,
605+            ReferenceError: true,
606+            RegExp: true,
607+            String: true,
608+            SyntaxError: true,
609+            TypeError: true,
610+            unescape: true,
611+            URIError: true
612+        },
613+        syntax = {}, token, verb, warnings,
614+
615+//  xmode is used to adapt to the exceptions in XML parsing.
616+//  It can have these states:
617+//      false   .js script file
618+//      "       A " attribute
619+//      '       A ' attribute
620+//      content The content of a script tag
621+//      CDATA   A CDATA block
622+
623+        xmode,
624+
625+//  xtype identifies the type of document being analyzed.
626+//  It can have these states:
627+//      false   .js script file
628+//      html    .html file
629+//      widget  .kon Konfabulator file
630+
631+        xtype,
632+// token
633+        tx = /^([(){}[.,:;'"~]|\](\]>)?|\?>?|==?=?|\/(\*(global|extern)*|=|)|\*[\/=]?|\+[+=]?|-[-=]?|%[=>]?|&[&=]?|\|[|=]?|>>?>?=?|<([\/=%\?]|\!(\[|--)?|<=?)?|\^=?|\!=?=?|[a-zA-Z_$][a-zA-Z0-9_$]*|[0-9]+([xX][0-9a-fA-F]+|\.[0-9]*)?([eE][+-]?[0-9]+)?)/,
634+// string ending in single quote
635+        sx = /^((\\[^\x00-\x1f]|[^\x00-\x1f'\\])*)'/,
636+        sxx = /^(([^\x00-\x1f'])*)'/,
637+// string ending in double quote
638+        qx = /^((\\[^\x00-\x1f]|[^\x00-\x1f"\\])*)"/,
639+        qxx = /^(([^\x00-\x1f"])*)"/,
640+// regular expression
641+        rx = /^(\\[^\x00-\x1f]|\[(\\[^\x00-\x1f]|[^\x00-\x1f\\\/])*\]|[^\x00-\x1f\\\/\[])+\/[gim]*/,
642+// star slash
643+        lx = /\*\/|\/\*/,
644+// global identifier
645+        gx = /^([a-zA-Z_$][a-zA-Z0-9_$]*)/,
646+// identifier
647+        ix = /^([a-zA-Z_$][a-zA-Z0-9_$]*$)/,
648+// global separators
649+        hx = /^[\x00-\x20,]*(\*\/)?/,
650+// whitespace
651+        wx = /^\s*(\/\/.*\r*$)?/;
652+
653+// Make a new object that inherits from an existing object.
654+
655+    function object(o) {
656+        function F() {}
657+        F.prototype = o;
658+        return new F();
659+    }
660+
661+// Produce an error warning.
662+
663+
664+    function warning(m, x, y) {
665+        var l, c, t = typeof x === 'object' ? x : nexttoken, w;
666+        if (typeof x === 'number') {
667+            l = x;
668+            c = y || 0;
669+        } else {
670+            if (t.id === '(end)') {
671+                t = token;
672+            }
673+            l = t.line || 0;
674+            c = t.from || 0;
675+        }
676+        w = {
677+            id: '(error)',
678+            reason: m,
679+            evidence: lines[l] || '',
680+            line: l,
681+            character: c
682+        };
683+        dojo.syntax.jslint.errors.push(w);
684+        if (option.passfail) {
685+            quit('Stopping. ', l, c);
686+        }
687+        warnings += 1;
688+        if (warnings === 50) {
689+            quit("Too many errors.", l, c);
690+        }
691+        return w;
692+    }
693+
694+    function error(m, x, y) {
695+        var w = warning(m, x, y);
696+        quit("Stopping, unable to continue.", w.line, w.character);
697+    }
698+
699+    quit = function quit(m, l, c) {
700+        warning(m + ' (' + Math.floor((l / lines.length) * 100) + '% scanned)', l, c);
701+        dojo.syntax.jslint.errors.push(null);
702+        throw null;
703+    };
704+
705+
706+
707+// lexical analysis
708+
709+    var lex = function () {
710+        var character, from, line, s;
711+
712+// Private lex methods
713+
714+        function nextLine() {
715+            line += 1;
716+            if (line >= lines.length) {
717+                return false;
718+            }
719+            character = 0;
720+            s = lines[line];
721+            return true;
722+        }
723+
724+// Produce a token object.  The token inherits from a syntax symbol.
725+
726+        function it(type, value) {
727+            var t;
728+            if (type === '(punctuator)') {
729+                t = syntax[value];
730+            } else if (type === '(identifier)') {
731+                t = syntax[value];
732+                if (!t || typeof t !== 'object') {
733+                    t = syntax[type];
734+                }
735+            } else {
736+                t = syntax[type];
737+            }
738+            if (!t || typeof t !== 'object') {
739+                error("Unrecognized symbol: '" + value + "' " + type);
740+            }
741+            t = object(t);
742+            if (value || type === '(string)') {
743+                if (value.charAt(10) === ':' &&
744+                        value.substring(0, 10).toLowerCase() === 'javascript') {
745+                    warning("JavaScript URL.");
746+                }
747+                t.value = value;
748+            }
749+            t.line = line;
750+            t.character = character;
751+            t.from = from;
752+            return t;
753+        }
754+
755+// Public lex methods
756+
757+        return {
758+            init: function (source) {
759+                if (typeof source === 'string') {
760+                    lines = source.split('\n');
761+                    if (lines.length === 1) {
762+                        lines = lines[0].split('\r');
763+                    }
764+                } else {
765+                    lines = source;
766+                }
767+                line = 0;
768+                character = 0;
769+                from = 0;
770+                s = lines[0];
771+            },
772+
773+// token -- this is called by advance to get the next token.
774+
775+            token: function () {
776+                var c, i, l, r, t;
777+
778+                function string(x) {
779+                    var a, j;
780+                    r = x.exec(s);
781+                    if (r) {
782+                        t = r[1];
783+                        l = r[0].length;
784+                        s = s.substr(l);
785+                        character += l;
786+                        if (xmode === 'script') {
787+                            if (t.indexOf('<\/') >= 0) {
788+                                warning(
789+    'Expected "...<\\/..." and instead saw "...<\/...".', nexttoken);
790+                            }
791+                        }
792+                        return it('(string)', r[1]);
793+                    } else {
794+                        for (j = 0; j < s.length; j += 1) {
795+                            a = s.charAt(j);
796+                            if (a < ' ') {
797+                                if (a === '\n' || a === '\r') {
798+                                    break;
799+                                }
800+                                warning("Control character in string: " +
801+                                        s.substring(0, j), line, character + j);
802+                            }
803+                        }
804+                        error("Unclosed string: " + s, line, character);
805+                    }
806+                }
807+
808+                for (;;) {
809+                    if (!s) {
810+                        return it(nextLine() ? '(endline)' : '(end)', '');
811+                    }
812+                    r = wx.exec(s);
813+                    if (!r || !r[0]) {
814+                        break;
815+                    }
816+                    l = r[0].length;
817+                    s = s.substr(l);
818+                    character += l;
819+                    if (s) {
820+                        break;
821+                    }
822+                }
823+                from = character;
824+                r = tx.exec(s);
825+                if (r) {
826+                    t = r[0];
827+                    l = t.length;
828+                    s = s.substr(l);
829+                    character += l;
830+                    c = t.substr(0, 1);
831+
832+//      identifier
833+
834+                    if (c.isAlpha() || c === '_' || c === '$') {
835+                        return it('(identifier)', t);
836+                    }
837+
838+//      number
839+
840+                    if (c.isDigit()) {
841+                        if (nexttoken.id === '.') {
842+                            warning(
843+            "A decimal fraction should have a zero before the decimal point.",
844+                                nexttoken);
845+                        }
846+                        if (!isFinite(Number(t))) {
847+                            warning("Bad number: '" + t + "'.",
848+                                line, character);
849+                        }
850+                        if (s.substr(0, 1).isAlpha()) {
851+                            warning("Space is required after a number: '" +
852+                                    t + "'.", line, character);
853+                        }
854+                        if (c === '0' && t.substr(1,1).isDigit()) {
855+                            warning("Don't use extra leading zeros: '" +
856+                                    t + "'.", line, character);
857+                        }
858+                        if (t.substr(t.length - 1) === '.') {
859+                            warning(
860+    "A trailing decimal point can be confused with a dot: '" + t + "'.",
861+                                    line, character);
862+                        }
863+                        return it('(number)', t);
864+                    }
865+
866+//      string
867+
868+                    if (t === '"') {
869+                        return (xmode === '"' ||  xmode === 'string') ?
870+                            it('(punctuator)', t) :
871+                            string(xmode === 'xml' ? qxx : qx);
872+                    }
873+                    if (t === "'") {
874+                        return (xmode === "'" ||  xmode === 'string') ?
875+                            it('(punctuator)', t) :
876+                            string(xmode === 'xml' ? sxx : sx);
877+                    }
878+
879+//      unbegun comment
880+
881+                    if (t === '/*') {
882+                        for (;;) {
883+                            i = s.search(lx);
884+                            if (i >= 0) {
885+                                break;
886+                            }
887+                            if (!nextLine()) {
888+                                error("Unclosed comment.", nexttoken);
889+                            }
890+                        }
891+                        character += i + 2;
892+                        if (s.substr(i, 1) === '/') {
893+                            error("Nested comment.");
894+                        }
895+                        s = s.substr(i + 2);
896+                        return this.token();
897+                    }
898+
899+//      /*extern
900+
901+                    if (t === '/*extern' || t === '/*global') {
902+                        for (;;) {
903+                            r = hx.exec(s);
904+                            if (r) {
905+                                l = r[0].length;
906+                                s = s.substr(l);
907+                                character += l;
908+                                if (r[1] === '*/') {
909+                                    return this.token();
910+                                }
911+                            }
912+                            if (s) {
913+                                r = gx.exec(s);
914+                                if (r) {
915+                                    l = r[0].length;
916+                                    s = s.substr(l);
917+                                    character += l;
918+                                    globals[r[1]] = true;
919+                                } else {
920+                                    error("Bad extern identifier: '" +
921+                                        s + "'.", line, character);
922+                                }
923+                             } else if (!nextLine()) {
924+                                error("Unclosed comment.");
925+                            }
926+                        }
927+                    }
928+
929+//      punctuator
930+
931+                    return it('(punctuator)', t);
932+                }
933+                error("Unexpected token: " + (t || s.substr(0, 1)),
934+                    line, character);
935+            },
936+
937+// skip -- skip past the next occurrence of a particular string.
938+// If the argument is empty, skip to just before the next '<' character.
939+// This is used to ignore HTML content. Return false if it isn't found.
940+
941+            skip: function (t) {
942+                if (nexttoken.id) {
943+                    if (!t) {
944+                        t = '';
945+                        if (nexttoken.id.substr(0, 1) === '<') {
946+                            lookahead.push(nexttoken);
947+                            return true;
948+                        }
949+                    } else if (nexttoken.id.indexOf(t) >= 0) {
950+                        return true;
951+                    }
952+                }
953+                token = nexttoken;
954+                nexttoken = syntax['(error)'];
955+                for (;;) {
956+                    var i = s.indexOf(t || '<');
957+                    if (i >= 0) {
958+                        character += i + t.length;
959+                        s = s.substr(i + t.length);
960+                        return true;
961+                    }
962+                    if (!nextLine()) {
963+                        break;
964+                    }
965+                }
966+                return false;
967+            },
968+
969+// regex -- this is called by parse when it sees '/' being used as a prefix.
970+
971+            regex: function () {
972+                var l, r = rx.exec(s), x;
973+                if (r) {
974+                    l = r[0].length;
975+                    character += l;
976+                    s = s.substr(l);
977+                    x = r[1];
978+                    return it('(regex)', x);
979+                }
980+                error("Bad regular expression: " + s);
981+            }
982+        };
983+    }();
984+
985+    function builtin(name) {
986+        var ret =  standard[name] === true ||
987+               globals[name] === true ||
988+              (option.rhino && rhino[name] === true) ||
989+             ((xtype === 'widget' || option.widget) && konfab[name] === true) ||
990+             ((xtype === 'html' || option.browser) && browser[name] === true);
991+               if (dojo.syntax.moduleExists(name)){
992+                       return true;
993+               }
994+               return ret;
995+    }
996+
997+    function addlabel(t, type) {
998+        if (t) {
999+            if (typeof funlab[t] === 'string') {
1000+                switch (funlab[t]) {
1001+                case 'var':
1002+                case 'var*':
1003+                    if (type === 'global') {
1004+                        funlab[t] = 'var*';
1005+                        return;
1006+                    }
1007+                    break;
1008+                case 'global':
1009+                    if (type === 'var') {
1010+                        warning('Var ' + t +
1011+                            ' was used before it was declared.', token);
1012+                        return;
1013+                    }
1014+                    if (type === 'var*' || type === 'global') {
1015+                        return;
1016+                    }
1017+                    break;
1018+                case 'function':
1019+                case 'parameter':
1020+                    if (type === 'global') {
1021+                        return;
1022+                    }
1023+                    break;
1024+                }
1025+                warning("Identifier '" + t + "' already declared as " +
1026+                        funlab[t], token);
1027+            }
1028+            funlab[t] = type;
1029+        }
1030+    }
1031+
1032+
1033+// We need a peek function. If it has an argument, it peeks that much farther
1034+// ahead. It is used to distinguish
1035+//     for ( var i in ...
1036+// from
1037+//     for ( var i = ...
1038+
1039+    function peek(i) {
1040+        var j = 0, t;
1041+        if (nexttoken === syntax['(error)']) {
1042+            return nexttoken;
1043+        }
1044+        if (typeof i === 'undefined') {
1045+            i = 0;
1046+        }
1047+        while (j <= i) {
1048+            t = lookahead[j];
1049+            if (!t) {
1050+                t = lookahead[j] = lex.token();
1051+            }
1052+            j += 1;
1053+        }
1054+        return t;
1055+    }
1056+
1057+
1058+    var badbreak = {')': true, ']': true, '++': true, '--': true};
1059+
1060+// Produce the next token. It looks for programming errors.
1061+
1062+    function advance(id, t) {
1063+        var l;
1064+        switch (token.id) {
1065+        case '(number)':
1066+            if (nexttoken.id === '.') {
1067+                warning(
1068+"A dot following a number can be confused with a decimal point.", token);
1069+            }
1070+            break;
1071+        case '-':
1072+            if (nexttoken.id === '-' || nexttoken.id === '--') {
1073+                warning("Confusing minusses.");
1074+            }
1075+            break;
1076+        case '+':
1077+            if (nexttoken.id === '+' || nexttoken.id === '++') {
1078+                warning("Confusing plusses.");
1079+            }
1080+            break;
1081+        }
1082+        if (token.type === '(string)' || token.identifier) {
1083+            anonname = token.value;
1084+        }
1085+
1086+        if (id && nexttoken.value !== id) {
1087+            if (t) {
1088+                if (nexttoken.id === '(end)') {
1089+                    warning("Unmatched '" + t.id + "'.", t);
1090+                } else {
1091+                    warning("Expected '" + id + "' to match '" +
1092+                            t.id + "' from line " + (t.line + 1) +
1093+                            " and instead saw '" + nexttoken.value + "'.");
1094+                }
1095+            } else {
1096+                warning("Expected '" + id + "' and instead saw '" +
1097+                        nexttoken.value + "'.");
1098+            }
1099+        }
1100+        token = nexttoken;
1101+        for (;;) {
1102+            nexttoken = lookahead.shift() || lex.token();
1103+            if (nexttoken.id === '<![') {
1104+                if (xtype === 'html') {
1105+                    error("Unexpected token '<!['");
1106+                }
1107+                if (xmode === 'script') {
1108+                    nexttoken = lex.token();
1109+                    if (nexttoken.value !== 'CDATA') {
1110+                        error("Expected 'CDATA'");
1111+                    }
1112+                    nexttoken = lex.token();
1113+                    if (nexttoken.id !== '[') {
1114+                        error("Expected '['");
1115+                    }
1116+                    xmode = 'CDATA';
1117+                } else if (xmode === 'xml') {
1118+                    lex.skip(']]>');
1119+                } else {
1120+                    error("Unexpected token '<!['");
1121+                }
1122+            } else if (nexttoken.id === ']]>') {
1123+                if (xmode === 'CDATA') {
1124+                    xmode = 'script';
1125+                } else {
1126+                    error("Unexpected token ']]>");
1127+                }
1128+            } else if (nexttoken.id !== '(endline)') {
1129+                break;
1130+            }
1131+            if (xmode === '"' || xmode === "'") {
1132+                error("Missing '" + xmode + "'.", token);
1133+            }
1134+            l = !xmode && !option.laxLineEnd &&
1135+                (token.type === '(string)' || token.type === '(number)' ||
1136+                token.type === '(identifier)' || badbreak[token.id]);
1137+        }
1138+        if (l) {
1139+            switch (nexttoken.id) {
1140+            case '{':
1141+            case '}':
1142+            case ']':
1143+                break;
1144+            case ')':
1145+                switch (token.id) {
1146+                case ')':
1147+                case '}':
1148+                case ']':
1149+                    break;
1150+                default:
1151+                    warning("Line breaking error: ')'.", token);
1152+                }
1153+                break;
1154+            default:
1155+                warning("Line breaking error: '" + token.value + "'.",
1156+                        token);
1157+            }
1158+        }
1159+        if (xtype === 'widget' && xmode === 'script' && nexttoken.id) {
1160+            l = nexttoken.id.charAt(0);
1161+            if (l === '<' || l === '&') {
1162+                nexttoken.nud = nexttoken.led = null;
1163+                nexttoken.lbp = 0;
1164+                nexttoken.reach = true;
1165+            }
1166+        }
1167+    }
1168+
1169+
1170+    function advanceregex() {
1171+        nexttoken = lex.regex();
1172+    }
1173+
1174+
1175+    function beginfunction(i) {
1176+        var f = {'(name)': i, '(line)': nexttoken.line + 1, '(context)': funlab};
1177+        funstack.push(funlab);
1178+        funlab = f;
1179+        functions.push(funlab);
1180+    }
1181+
1182+
1183+    function endfunction() {
1184+        funlab = funstack.pop();
1185+    }
1186+
1187+
1188+// This is the heart of JSLINT, the Pratt parser. In addition to parsing, it
1189+// is looking for ad hoc lint patterns. We add to Pratt's model .fud, which is
1190+// like nud except that it is only used on the first token of a statement.
1191+// Having .fud makes it much easier to define JavaScript. I retained Pratt's
1192+// nomenclature, even though it isn't very descriptive.
1193+
1194+// .nud     Null denotation
1195+// .fud     First null denotation
1196+// .led     Left denotation
1197+//  lbp     Left binding power
1198+//  rbp     Right binding power
1199+
1200+// They are key to the parsing method called Top Down Operator Precedence.
1201+
1202+    function parse(rbp, initial) {
1203+        var l, left, o;
1204+        if (nexttoken.id && nexttoken.id === '/') {
1205+            if (token.id !== '(' && token.id !== '=' &&
1206+                    token.id !== ':' && token.id !== ',' &&
1207+                    token.id !== '=' && token.id !== '[') {
1208+                warning(
1209+"Expected to see a '(' or '=' or ':' or ',' or '[' preceding a regular expression literal, and instead saw '" +
1210+                        token.value + "'.", token);
1211+            }
1212+            advanceregex();
1213+        }
1214+        if (nexttoken.id === '(end)') {
1215+            warning("Unexpected early end of program", token);
1216+        }
1217+        advance();
1218+        if (initial) {
1219+            anonname = 'anonymous';
1220+            verb = token.value;
1221+        }
1222+        if (initial && token.fud) {
1223+            token.fud();
1224+        } else {
1225+            if (token.nud) {
1226+                o = token.exps;
1227+                left = token.nud();
1228+            } else {
1229+                if (nexttoken.type === '(number)' && token.id === '.') {
1230+                    warning(
1231+"A leading decimal point can be confused with a dot: ." + nexttoken.value,
1232+                            token);
1233+                }
1234+                error("Expected an identifier and instead saw '" +
1235+                        token.id + "'.", token);
1236+            }
1237+            while (rbp < nexttoken.lbp) {
1238+                o = nexttoken.exps;
1239+                advance();
1240+                if (token.led) {
1241+                    left = token.led(left);
1242+                } else {
1243+                    error("Expected an operator and instead saw '" +
1244+                        token.id + "'.");
1245+                }
1246+            }
1247+            if (initial && !o) {
1248+                warning(
1249+"Expected an assignment or function call and instead saw an expression.",
1250+                        token);
1251+            }
1252+        }
1253+        if (l) {
1254+            funlab[l] = 'label';