@@ -265,22 +265,42 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
265265 pass . apply ( null , arguments ) ;
266266 return true ;
267267 }
268+ function inList ( name , list ) {
269+ for ( var v = list ; v ; v = v . next ) if ( v . name == name ) return true
270+ return false ;
271+ }
268272 function register ( varname ) {
269- function inList ( list , block ) {
270- for ( var v = list ; v ; v = v . next )
271- if ( v . name == varname && ( block === undefined || v . block === block ) ) return true ;
272- return false ;
273- }
274273 var state = cx . state ;
275274 cx . marked = "def" ;
276275 if ( state . context ) {
277- var block = ! ( cx . state . lexical . info && cx . state . lexical . info . scope === "var" ) ;
278- if ( inList ( state . localVars , block ) ) return ;
279- state . localVars = { name : varname , block : block , next : state . localVars } ;
276+ if ( state . lexical . info == "var" && state . context && state . context . block ) {
277+ // FIXME function decls are also not block scoped
278+ var newContext = registerVarScoped ( varname , state . context )
279+ if ( newContext != null ) {
280+ state . context = newContext
281+ return
282+ }
283+ } else if ( ! inList ( varname , state . localVars ) ) {
284+ state . localVars = new Var ( varname , state . localVars )
285+ return
286+ }
287+ }
288+ // Fall through means this is global
289+ if ( parserConfig . globalVars && ! inList ( varname , state . globalVars ) )
290+ state . globalVars = new Var ( varname , state . globalVars )
291+ }
292+ function registerVarScoped ( varname , context ) {
293+ if ( ! context ) {
294+ return null
295+ } else if ( context . block ) {
296+ var inner = registerVarScoped ( varname , context . prev )
297+ if ( ! inner ) return null
298+ if ( inner == context . prev ) return context
299+ return new Context ( inner , context . vars , true )
300+ } else if ( inList ( varname , context . vars ) ) {
301+ return context
280302 } else {
281- if ( inList ( state . globalVars ) ) return ;
282- if ( parserConfig . globalVars )
283- state . globalVars = { name : varname , next : state . globalVars } ;
303+ return new Context ( context . prev , new Var ( varname , context . vars ) , false )
284304 }
285305 }
286306
@@ -290,32 +310,23 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
290310
291311 // Combinators
292312
293- var defaultVars = { name : "this" , next : { name : "arguments" } } ;
313+ function Context ( prev , vars , block ) { this . prev = prev ; this . vars = vars ; this . block = block }
314+ function Var ( name , next ) { this . name = name ; this . next = next }
315+
316+ var defaultVars = new Var ( "this" , new Var ( "arguments" , null ) )
294317 function pushcontext ( ) {
295- cx . state . context = { prev : cx . state . context , vars : cx . state . localVars } ;
296- cx . state . localVars = defaultVars ;
318+ cx . state . context = new Context ( cx . state . context , cx . state . localVars , false )
319+ cx . state . localVars = defaultVars
297320 }
298321 function pushblockcontext ( ) {
299- cx . state . context = { prev : cx . state . context , vars : cx . state . localVars , block : true } ;
300- cx . state . localVars = defaultVars ;
322+ cx . state . context = new Context ( cx . state . context , cx . state . localVars , true )
323+ cx . state . localVars = null
301324 }
302325 function popcontext ( ) {
303- if ( cx . state . context . block ) {
304- var newVars = { name : "this" , next : { name : "arguments" } } ;
305- // drop block-scoped variables
306- for ( var v = cx . state . localVars ; v ; v = v . next ) {
307- if ( ! v . block ) newVars = { name : v . name , scope : v . scope , next : newVars } ;
308- }
309- // inherit from previous scope
310- for ( v = cx . state . context . vars ; v ; v = v . next ) {
311- newVars = { name : v . name , scope : v . scope , next : newVars } ;
312- }
313- cx . state . localVars = newVars ;
314- } else {
315- cx . state . localVars = cx . state . context . vars ;
316- }
317- cx . state . context = cx . state . context . prev ;
326+ cx . state . localVars = cx . state . context . vars
327+ cx . state . context = cx . state . context . prev
318328 }
329+ popcontext . lex = true
319330 function pushlex ( type , info ) {
320331 var result = function ( ) {
321332 var state = cx . state , indent = state . indented ;
@@ -347,7 +358,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
347358 }
348359
349360 function statement ( type , value ) {
350- if ( type == "var" ) return cont ( pushlex ( "vardef" , { scope : value , length : value . length } ) , vardef , expect ( ";" ) , poplex ) ;
361+ if ( type == "var" ) return cont ( pushlex ( "vardef" , value ) , vardef , expect ( ";" ) , poplex ) ;
351362 if ( type == "keyword a" ) return cont ( pushlex ( "form" ) , parenExpr , statement , poplex ) ;
352363 if ( type == "keyword b" ) return cont ( pushlex ( "form" ) , statement , poplex ) ;
353364 if ( type == "keyword d" ) return cx . stream . match ( / ^ \s * $ / , false ) ? cont ( ) : cont ( pushlex ( "stat" ) , maybeexpression , expect ( ";" ) , poplex ) ;
@@ -381,7 +392,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
381392 return cont ( pushlex ( "stat" ) , maybelabel ) ;
382393 }
383394 }
384- if ( type == "switch" ) return cont ( pushblockcontext , pushlex ( "form" ) , parenExpr , expect ( "{" ) , pushlex ( "}" , "switch" ) ,
395+ if ( type == "switch" ) return cont ( pushlex ( "form" ) , parenExpr , expect ( "{" ) , pushlex ( "}" , "switch" ) , pushblockcontext ,
385396 block , poplex , poplex , popcontext ) ;
386397 if ( type == "case" ) return cont ( expression , expect ( ":" ) ) ;
387398 if ( type == "default" ) return cont ( expect ( ":" ) ) ;
@@ -803,7 +814,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
803814 cc : [ ] ,
804815 lexical : new JSLexical ( ( basecolumn || 0 ) - indentUnit , 0 , "block" , false ) ,
805816 localVars : parserConfig . localVars ,
806- context : parserConfig . localVars && { vars : parserConfig . localVars } ,
817+ context : parserConfig . localVars && new Context ( null , null , false ) ,
807818 indented : basecolumn || 0
808819 } ;
809820 if ( parserConfig . globalVars && typeof parserConfig . globalVars == "object" )
0 commit comments