| OLD | NEW |
| 1 /* Parse function for JavaScript. Makes use of the tokenizer from | 1 /* Parse function for JavaScript. Makes use of the tokenizer from |
| 2 * tokenizejavascript.js. Note that your parsers do not have to be | 2 * tokenizejavascript.js. Note that your parsers do not have to be |
| 3 * this complicated -- if you don't want to recognize local variables, | 3 * this complicated -- if you don't want to recognize local variables, |
| 4 * in many languages it is enough to just look for braces, semicolons, | 4 * in many languages it is enough to just look for braces, semicolons, |
| 5 * parentheses, etc, and know when you are inside a string or comment. | 5 * parentheses, etc, and know when you are inside a string or comment. |
| 6 * | 6 * |
| 7 * See manual.html for more info about the parser interface. | 7 * See manual.html for more info about the parser interface. |
| 8 */ | 8 */ |
| 9 | 9 |
| 10 var JSParser = Editor.Parser = (function() { | 10 var JSParser = Editor.Parser = (function() { |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 61 // The lexical scope, used mostly for indentation. | 61 // The lexical scope, used mostly for indentation. |
| 62 var lexical = new JSLexical((basecolumn || 0) - 2, 0, "block", false); | 62 var lexical = new JSLexical((basecolumn || 0) - 2, 0, "block", false); |
| 63 // Current column, and the indentation at the start of the current | 63 // Current column, and the indentation at the start of the current |
| 64 // line. Used to create lexical scope objects. | 64 // line. Used to create lexical scope objects. |
| 65 var column = 0; | 65 var column = 0; |
| 66 var indented = 0; | 66 var indented = 0; |
| 67 // Variables which are used by the mark, cont, and pass functions | 67 // Variables which are used by the mark, cont, and pass functions |
| 68 // below to communicate with the driver loop in the 'next' | 68 // below to communicate with the driver loop in the 'next' |
| 69 // function. | 69 // function. |
| 70 var consume, marked; | 70 var consume, marked; |
| 71 | 71 |
| 72 // The iterator object. | 72 // The iterator object. |
| 73 var parser = {next: next, copy: copy}; | 73 var parser = {next: next, copy: copy}; |
| 74 | 74 |
| 75 function next(){ | 75 function next(){ |
| 76 // Start by performing any 'lexical' actions (adjusting the | 76 // Start by performing any 'lexical' actions (adjusting the |
| 77 // lexical variable), or the operations below will be working | 77 // lexical variable), or the operations below will be working |
| 78 // with the wrong lexical state. | 78 // with the wrong lexical state. |
| 79 while(cc[cc.length - 1].lex) | 79 while(cc[cc.length - 1].lex) |
| 80 cc.pop()(); | 80 cc.pop()(); |
| 81 | 81 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 98 } | 98 } |
| 99 // No more processing for meaningless tokens. | 99 // No more processing for meaningless tokens. |
| 100 if (token.type == "whitespace" || token.type == "comment") | 100 if (token.type == "whitespace" || token.type == "comment") |
| 101 return token; | 101 return token; |
| 102 // When a meaningful token is found and the lexical scope's | 102 // When a meaningful token is found and the lexical scope's |
| 103 // align is undefined, it is an aligned scope. | 103 // align is undefined, it is an aligned scope. |
| 104 if (!("align" in lexical)) | 104 if (!("align" in lexical)) |
| 105 lexical.align = true; | 105 lexical.align = true; |
| 106 | 106 |
| 107 // Execute actions until one 'consumes' the token and we can | 107 // Execute actions until one 'consumes' the token and we can |
| 108 // return it. Marked is used to | 108 // return it. Marked is used to |
| 109 while(true){ | 109 while(true){ |
| 110 consume = marked = false; | 110 consume = marked = false; |
| 111 // Take and execute the topmost action. | 111 // Take and execute the topmost action. |
| 112 cc.pop()(token.type, token.content); | 112 cc.pop()(token.type, token.content); |
| 113 if (consume){ | 113 if (consume){ |
| 114 // Marked is used to change the style of the current token. | 114 // Marked is used to change the style of the current token. |
| 115 if (marked) | 115 if (marked) |
| 116 token.style = marked; | 116 token.style = marked; |
| 117 // Here we differentiate between local and global variables. | 117 // Here we differentiate between local and global variables. |
| 118 else if (token.type == "variable" && inScope(token.content)) | 118 else if (token.type == "variable" && inScope(token.content)) |
| 119 token.style = "js-localvariable"; | 119 token.style = "js-localvariable"; |
| 120 return token; | 120 return token; |
| 121 } | 121 } |
| 122 } | 122 } |
| 123 } | 123 } |
| 124 | 124 |
| 125 // This makes a copy of the parser state. It stores all the | 125 // This makes a copy of the parser state. It stores all the |
| 126 // stateful variables in a closure, and returns a function that | 126 // stateful variables in a closure, and returns a function that |
| 127 // will restore them when called with a new input stream. Note | 127 // will restore them when called with a new input stream. Note |
| 128 // that the cc array has to be copied, because it is contantly | 128 // that the cc array has to be copied, because it is contantly |
| 129 // being modified. Lexical objects are not mutated, and context | 129 // being modified. Lexical objects are not mutated, and context |
| 130 // objects are not mutated in a harmful way, so they can be shared | 130 // objects are not mutated in a harmful way, so they can be shared |
| 131 // between runs of the parser. | 131 // between runs of the parser. |
| 132 function copy(){ | 132 function copy(){ |
| 133 var _context = context, _lexical = lexical, _cc = cc.concat([]), _tokenSta
te = tokens.state; | 133 var _context = context, _lexical = lexical, _cc = cc.concat([]), _tokenSta
te = tokens.state; |
| 134 | 134 |
| 135 return function(input){ | 135 return function(input){ |
| 136 context = _context; | 136 context = _context; |
| 137 lexical = _lexical; | 137 lexical = _lexical; |
| 138 cc = _cc.concat([]); // copies the array | 138 cc = _cc.concat([]); // copies the array |
| 139 column = indented = 0; | 139 column = indented = 0; |
| 140 tokens = tokenizeJavaScript(input, _tokenState); | 140 tokens = tokenizeJavaScript(input, _tokenState); |
| 141 return parser; | 141 return parser; |
| 142 }; | 142 }; |
| 143 } | 143 } |
| 144 | 144 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 183 // Check whether a variable is defined in the current scope. | 183 // Check whether a variable is defined in the current scope. |
| 184 function inScope(varname){ | 184 function inScope(varname){ |
| 185 var cursor = context; | 185 var cursor = context; |
| 186 while (cursor) { | 186 while (cursor) { |
| 187 if (cursor.vars[varname]) | 187 if (cursor.vars[varname]) |
| 188 return true; | 188 return true; |
| 189 cursor = cursor.prev; | 189 cursor = cursor.prev; |
| 190 } | 190 } |
| 191 return false; | 191 return false; |
| 192 } | 192 } |
| 193 | 193 |
| 194 // Push a new lexical context of the given type. | 194 // Push a new lexical context of the given type. |
| 195 function pushlex(type){ | 195 function pushlex(type){ |
| 196 var result = function(){ | 196 var result = function(){ |
| 197 lexical = new JSLexical(indented, column, type, null, lexical) | 197 lexical = new JSLexical(indented, column, type, null, lexical) |
| 198 }; | 198 }; |
| 199 result.lex = true; | 199 result.lex = true; |
| 200 return result; | 200 return result; |
| 201 } | 201 } |
| 202 // Pop off the current lexical context. | 202 // Pop off the current lexical context. |
| 203 function poplex(){ | 203 function poplex(){ |
| 204 lexical = lexical.prev; | 204 lexical = lexical.prev; |
| 205 } | 205 } |
| 206 poplex.lex = true; | 206 poplex.lex = true; |
| 207 // The 'lex' flag on these actions is used by the 'next' function | 207 // The 'lex' flag on these actions is used by the 'next' function |
| 208 // to know they can (and have to) be ran before moving on to the | 208 // to know they can (and have to) be ran before moving on to the |
| 209 // next token. | 209 // next token. |
| 210 | 210 |
| 211 // Creates an action that discards tokens until it finds one of | 211 // Creates an action that discards tokens until it finds one of |
| 212 // the given type. | 212 // the given type. |
| 213 function expect(wanted){ | 213 function expect(wanted){ |
| 214 return function(type){ | 214 return function(type){ |
| 215 if (type == wanted) cont(); | 215 if (type == wanted) cont(); |
| 216 else cont(arguments.callee); | 216 else cont(arguments.callee); |
| 217 }; | 217 }; |
| 218 } | 218 } |
| 219 | 219 |
| 220 // Looks for a statement, and then calls itself. | 220 // Looks for a statement, and then calls itself. |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 307 } | 307 } |
| 308 // A function definition creates a new context, and the variables | 308 // A function definition creates a new context, and the variables |
| 309 // in its argument list have to be added to this context. | 309 // in its argument list have to be added to this context. |
| 310 function functiondef(type, value){ | 310 function functiondef(type, value){ |
| 311 if (type == "variable"){register(value); cont(functiondef);} | 311 if (type == "variable"){register(value); cont(functiondef);} |
| 312 else if (type == "(") cont(pushcontext, commasep(funarg), expect(")"), sta
tement, popcontext); | 312 else if (type == "(") cont(pushcontext, commasep(funarg), expect(")"), sta
tement, popcontext); |
| 313 } | 313 } |
| 314 function funarg(type, value){ | 314 function funarg(type, value){ |
| 315 if (type == "variable"){register(value); cont();} | 315 if (type == "variable"){register(value); cont();} |
| 316 } | 316 } |
| 317 | 317 |
| 318 return parser; | 318 return parser; |
| 319 } | 319 } |
| 320 | 320 |
| 321 return {make: parseJS, electricChars: "{}"}; | 321 return {make: parseJS, electricChars: "{}"}; |
| 322 })(); | 322 })(); |
| OLD | NEW |