OLD | NEW |
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others | 1 // CodeMirror, copyright (c) by Marijn Haverbeke and others |
2 // Distributed under an MIT license: http://codemirror.net/LICENSE | 2 // Distributed under an MIT license: http://codemirror.net/LICENSE |
3 | 3 |
4 // TODO actually recognize syntax of TypeScript constructs | 4 // TODO actually recognize syntax of TypeScript constructs |
5 | 5 |
6 (function(mod) { | 6 (function(mod) { |
7 if (typeof exports == "object" && typeof module == "object") // CommonJS | 7 if (typeof exports == "object" && typeof module == "object") // CommonJS |
8 mod(require("../../lib/codemirror")); | 8 mod(require("../../lib/codemirror")); |
9 else if (typeof define == "function" && define.amd) // AMD | 9 else if (typeof define == "function" && define.amd) // AMD |
10 define(["../../lib/codemirror"], mod); | 10 define(["../../lib/codemirror"], mod); |
11 else // Plain browser env | 11 else // Plain browser env |
12 mod(CodeMirror); | 12 mod(CodeMirror); |
13 })(function(CodeMirror) { | 13 })(function(CodeMirror) { |
14 "use strict"; | 14 "use strict"; |
15 | 15 |
16 CodeMirror.defineMode("javascript", function(config, parserConfig) { | 16 CodeMirror.defineMode("javascript", function(config, parserConfig) { |
17 var indentUnit = config.indentUnit; | 17 var indentUnit = config.indentUnit; |
18 var statementIndent = parserConfig.statementIndent; | 18 var statementIndent = parserConfig.statementIndent; |
19 var jsonldMode = parserConfig.jsonld; | 19 var jsonldMode = parserConfig.jsonld; |
20 var jsonMode = parserConfig.json || jsonldMode; | 20 var jsonMode = parserConfig.json || jsonldMode; |
21 var isTS = parserConfig.typescript; | 21 var isTS = parserConfig.typescript; |
| 22 var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/; |
22 | 23 |
23 // Tokenizer | 24 // Tokenizer |
24 | 25 |
25 var keywords = function(){ | 26 var keywords = function(){ |
26 function kw(type) {return {type: type, style: "keyword"};} | 27 function kw(type) {return {type: type, style: "keyword"};} |
27 var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c"); | 28 var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c"); |
28 var operator = kw("operator"), atom = {type: "atom", style: "atom"}; | 29 var operator = kw("operator"), atom = {type: "atom", style: "atom"}; |
29 | 30 |
30 var jsKeywords = { | 31 var jsKeywords = { |
31 "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "fina
lly": B, | 32 "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "fina
lly": B, |
32 "return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C,
"debugger": C, | 33 "return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C,
"debugger": C, |
33 "var": kw("var"), "const": kw("var"), "let": kw("var"), | 34 "var": kw("var"), "const": kw("var"), "let": kw("var"), |
34 "function": kw("function"), "catch": kw("catch"), | 35 "function": kw("function"), "catch": kw("catch"), |
35 "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": k
w("default"), | 36 "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": k
w("default"), |
36 "in": operator, "typeof": operator, "instanceof": operator, | 37 "in": operator, "typeof": operator, "instanceof": operator, |
37 "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom,
"Infinity": atom, | 38 "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom,
"Infinity": atom, |
38 "this": kw("this"), "module": kw("module"), "class": kw("class"), "super":
kw("atom"), | 39 "this": kw("this"), "class": kw("class"), "super": kw("atom"), |
39 "yield": C, "export": kw("export"), "import": kw("import"), "extends": C | 40 "yield": C, "export": kw("export"), "import": kw("import"), "extends": C |
40 }; | 41 }; |
41 | 42 |
42 // Extend the 'normal' keywords with the TypeScript language extensions | 43 // Extend the 'normal' keywords with the TypeScript language extensions |
43 if (isTS) { | 44 if (isTS) { |
44 var type = {type: "variable", style: "variable-3"}; | 45 var type = {type: "variable", style: "variable-3"}; |
45 var tsKeywords = { | 46 var tsKeywords = { |
46 // object-like things | 47 // object-like things |
47 "interface": kw("interface"), | 48 "interface": kw("interface"), |
48 "extends": kw("extends"), | 49 "extends": kw("extends"), |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
110 } else if (ch == "/") { | 111 } else if (ch == "/") { |
111 if (stream.eat("*")) { | 112 if (stream.eat("*")) { |
112 state.tokenize = tokenComment; | 113 state.tokenize = tokenComment; |
113 return tokenComment(stream, state); | 114 return tokenComment(stream, state); |
114 } else if (stream.eat("/")) { | 115 } else if (stream.eat("/")) { |
115 stream.skipToEnd(); | 116 stream.skipToEnd(); |
116 return ret("comment", "comment"); | 117 return ret("comment", "comment"); |
117 } else if (state.lastType == "operator" || state.lastType == "keyword c" |
| | 118 } else if (state.lastType == "operator" || state.lastType == "keyword c" |
| |
118 state.lastType == "sof" || /^[\[{}\(,;:]$/.test(state.lastType))
{ | 119 state.lastType == "sof" || /^[\[{}\(,;:]$/.test(state.lastType))
{ |
119 readRegexp(stream); | 120 readRegexp(stream); |
120 stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla | 121 stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/); |
121 return ret("regexp", "string-2"); | 122 return ret("regexp", "string-2"); |
122 } else { | 123 } else { |
123 stream.eatWhile(isOperatorChar); | 124 stream.eatWhile(isOperatorChar); |
124 return ret("operator", "operator", stream.current()); | 125 return ret("operator", "operator", stream.current()); |
125 } | 126 } |
126 } else if (ch == "`") { | 127 } else if (ch == "`") { |
127 state.tokenize = tokenQuasi; | 128 state.tokenize = tokenQuasi; |
128 return tokenQuasi(stream, state); | 129 return tokenQuasi(stream, state); |
129 } else if (ch == "#") { | 130 } else if (ch == "#") { |
130 stream.skipToEnd(); | 131 stream.skipToEnd(); |
131 return ret("error", "error"); | 132 return ret("error", "error"); |
132 } else if (isOperatorChar.test(ch)) { | 133 } else if (isOperatorChar.test(ch)) { |
133 stream.eatWhile(isOperatorChar); | 134 stream.eatWhile(isOperatorChar); |
134 return ret("operator", "operator", stream.current()); | 135 return ret("operator", "operator", stream.current()); |
135 } else { | 136 } else if (wordRE.test(ch)) { |
136 stream.eatWhile(/[\w\$_]/); | 137 stream.eatWhile(wordRE); |
137 var word = stream.current(), known = keywords.propertyIsEnumerable(word) &
& keywords[word]; | 138 var word = stream.current(), known = keywords.propertyIsEnumerable(word) &
& keywords[word]; |
138 return (known && state.lastType != ".") ? ret(known.type, known.style, wor
d) : | 139 return (known && state.lastType != ".") ? ret(known.type, known.style, wor
d) : |
139 ret("variable", "variable", word); | 140 ret("variable", "variable", word); |
140 } | 141 } |
141 } | 142 } |
142 | 143 |
143 function tokenString(quote) { | 144 function tokenString(quote) { |
144 return function(stream, state) { | 145 return function(stream, state) { |
145 var escaped = false, next; | 146 var escaped = false, next; |
146 if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){ | 147 if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){ |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
195 | 196 |
196 var depth = 0, sawSomething = false; | 197 var depth = 0, sawSomething = false; |
197 for (var pos = arrow - 1; pos >= 0; --pos) { | 198 for (var pos = arrow - 1; pos >= 0; --pos) { |
198 var ch = stream.string.charAt(pos); | 199 var ch = stream.string.charAt(pos); |
199 var bracket = brackets.indexOf(ch); | 200 var bracket = brackets.indexOf(ch); |
200 if (bracket >= 0 && bracket < 3) { | 201 if (bracket >= 0 && bracket < 3) { |
201 if (!depth) { ++pos; break; } | 202 if (!depth) { ++pos; break; } |
202 if (--depth == 0) break; | 203 if (--depth == 0) break; |
203 } else if (bracket >= 3 && bracket < 6) { | 204 } else if (bracket >= 3 && bracket < 6) { |
204 ++depth; | 205 ++depth; |
205 } else if (/[$\w]/.test(ch)) { | 206 } else if (wordRE.test(ch)) { |
206 sawSomething = true; | 207 sawSomething = true; |
| 208 } else if (/["'\/]/.test(ch)) { |
| 209 return; |
207 } else if (sawSomething && !depth) { | 210 } else if (sawSomething && !depth) { |
208 ++pos; | 211 ++pos; |
209 break; | 212 break; |
210 } | 213 } |
211 } | 214 } |
212 if (sawSomething && !depth) state.fatArrowAt = pos; | 215 if (sawSomething && !depth) state.fatArrowAt = pos; |
213 } | 216 } |
214 | 217 |
215 // Parser | 218 // Parser |
216 | 219 |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
291 cx.state.localVars = defaultVars; | 294 cx.state.localVars = defaultVars; |
292 } | 295 } |
293 function popcontext() { | 296 function popcontext() { |
294 cx.state.localVars = cx.state.context.vars; | 297 cx.state.localVars = cx.state.context.vars; |
295 cx.state.context = cx.state.context.prev; | 298 cx.state.context = cx.state.context.prev; |
296 } | 299 } |
297 function pushlex(type, info) { | 300 function pushlex(type, info) { |
298 var result = function() { | 301 var result = function() { |
299 var state = cx.state, indent = state.indented; | 302 var state = cx.state, indent = state.indented; |
300 if (state.lexical.type == "stat") indent = state.lexical.indented; | 303 if (state.lexical.type == "stat") indent = state.lexical.indented; |
| 304 else for (var outer = state.lexical; outer && outer.type == ")" && outer.a
lign; outer = outer.prev) |
| 305 indent = outer.indented; |
301 state.lexical = new JSLexical(indent, cx.stream.column(), type, null, stat
e.lexical, info); | 306 state.lexical = new JSLexical(indent, cx.stream.column(), type, null, stat
e.lexical, info); |
302 }; | 307 }; |
303 result.lex = true; | 308 result.lex = true; |
304 return result; | 309 return result; |
305 } | 310 } |
306 function poplex() { | 311 function poplex() { |
307 var state = cx.state; | 312 var state = cx.state; |
308 if (state.lexical.prev) { | 313 if (state.lexical.prev) { |
309 if (state.lexical.type == ")") | 314 if (state.lexical.type == ")") |
310 state.indented = state.lexical.indented; | 315 state.indented = state.lexical.indented; |
(...skipping 24 matching lines...) Expand all Loading... |
335 } | 340 } |
336 if (type == "function") return cont(functiondef); | 341 if (type == "function") return cont(functiondef); |
337 if (type == "for") return cont(pushlex("form"), forspec, statement, poplex); | 342 if (type == "for") return cont(pushlex("form"), forspec, statement, poplex); |
338 if (type == "variable") return cont(pushlex("stat"), maybelabel); | 343 if (type == "variable") return cont(pushlex("stat"), maybelabel); |
339 if (type == "switch") return cont(pushlex("form"), expression, pushlex("}",
"switch"), expect("{"), | 344 if (type == "switch") return cont(pushlex("form"), expression, pushlex("}",
"switch"), expect("{"), |
340 block, poplex, poplex); | 345 block, poplex, poplex); |
341 if (type == "case") return cont(expression, expect(":")); | 346 if (type == "case") return cont(expression, expect(":")); |
342 if (type == "default") return cont(expect(":")); | 347 if (type == "default") return cont(expect(":")); |
343 if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("),
funarg, expect(")"), | 348 if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("),
funarg, expect(")"), |
344 statement, poplex, popcontext); | 349 statement, poplex, popcontext); |
345 if (type == "module") return cont(pushlex("form"), pushcontext, afterModule,
popcontext, poplex); | |
346 if (type == "class") return cont(pushlex("form"), className, poplex); | 350 if (type == "class") return cont(pushlex("form"), className, poplex); |
347 if (type == "export") return cont(pushlex("form"), afterExport, poplex); | 351 if (type == "export") return cont(pushlex("form"), afterExport, poplex); |
348 if (type == "import") return cont(pushlex("form"), afterImport, poplex); | 352 if (type == "import") return cont(pushlex("form"), afterImport, poplex); |
349 return pass(pushlex("stat"), expression, expect(";"), poplex); | 353 return pass(pushlex("stat"), expression, expect(";"), poplex); |
350 } | 354 } |
351 function expression(type) { | 355 function expression(type) { |
352 return expressionInner(type, false); | 356 return expressionInner(type, false); |
353 } | 357 } |
354 function expressionNoComma(type) { | 358 function expressionNoComma(type) { |
355 return expressionInner(type, true); | 359 return expressionInner(type, true); |
(...skipping 25 matching lines...) Expand all Loading... |
381 return pass(expressionNoComma); | 385 return pass(expressionNoComma); |
382 } | 386 } |
383 | 387 |
384 function maybeoperatorComma(type, value) { | 388 function maybeoperatorComma(type, value) { |
385 if (type == ",") return cont(expression); | 389 if (type == ",") return cont(expression); |
386 return maybeoperatorNoComma(type, value, false); | 390 return maybeoperatorNoComma(type, value, false); |
387 } | 391 } |
388 function maybeoperatorNoComma(type, value, noComma) { | 392 function maybeoperatorNoComma(type, value, noComma) { |
389 var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma; | 393 var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma; |
390 var expr = noComma == false ? expression : expressionNoComma; | 394 var expr = noComma == false ? expression : expressionNoComma; |
391 if (value == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arr
owBody, popcontext); | 395 if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arro
wBody, popcontext); |
392 if (type == "operator") { | 396 if (type == "operator") { |
393 if (/\+\+|--/.test(value)) return cont(me); | 397 if (/\+\+|--/.test(value)) return cont(me); |
394 if (value == "?") return cont(expression, expect(":"), expr); | 398 if (value == "?") return cont(expression, expect(":"), expr); |
395 return cont(expr); | 399 return cont(expr); |
396 } | 400 } |
397 if (type == "quasi") { return pass(quasi, me); } | 401 if (type == "quasi") { return pass(quasi, me); } |
398 if (type == ";") return; | 402 if (type == ";") return; |
399 if (type == "(") return contCommasep(expressionNoComma, ")", "call", me); | 403 if (type == "(") return contCommasep(expressionNoComma, ")", "call", me); |
400 if (type == ".") return cont(property, me); | 404 if (type == ".") return cont(property, me); |
401 if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), pop
lex, me); | 405 if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), pop
lex, me); |
402 } | 406 } |
403 function quasi(type, value) { | 407 function quasi(type, value) { |
404 if (type != "quasi") return pass(); | 408 if (type != "quasi") return pass(); |
405 if (value.slice(value.length - 2) != "${") return cont(quasi); | 409 if (value.slice(value.length - 2) != "${") return cont(quasi); |
406 return cont(expression, continueQuasi); | 410 return cont(expression, continueQuasi); |
407 } | 411 } |
408 function continueQuasi(type) { | 412 function continueQuasi(type) { |
409 if (type == "}") { | 413 if (type == "}") { |
410 cx.marked = "string-2"; | 414 cx.marked = "string-2"; |
411 cx.state.tokenize = tokenQuasi; | 415 cx.state.tokenize = tokenQuasi; |
412 return cont(quasi); | 416 return cont(quasi); |
413 } | 417 } |
414 } | 418 } |
415 function arrowBody(type) { | 419 function arrowBody(type) { |
416 findFatArrow(cx.stream, cx.state); | 420 findFatArrow(cx.stream, cx.state); |
417 if (type == "{") return pass(statement); | 421 return pass(type == "{" ? statement : expression); |
418 return pass(expression); | |
419 } | 422 } |
420 function arrowBodyNoComma(type) { | 423 function arrowBodyNoComma(type) { |
421 findFatArrow(cx.stream, cx.state); | 424 findFatArrow(cx.stream, cx.state); |
422 if (type == "{") return pass(statement); | 425 return pass(type == "{" ? statement : expressionNoComma); |
423 return pass(expressionNoComma); | |
424 } | 426 } |
425 function maybelabel(type) { | 427 function maybelabel(type) { |
426 if (type == ":") return cont(poplex, statement); | 428 if (type == ":") return cont(poplex, statement); |
427 return pass(maybeoperatorComma, expect(";"), poplex); | 429 return pass(maybeoperatorComma, expect(";"), poplex); |
428 } | 430 } |
429 function property(type) { | 431 function property(type) { |
430 if (type == "variable") {cx.marked = "property"; return cont();} | 432 if (type == "variable") {cx.marked = "property"; return cont();} |
431 } | 433 } |
432 function objprop(type, value) { | 434 function objprop(type, value) { |
433 if (type == "variable" || cx.style == "keyword") { | 435 if (type == "variable" || cx.style == "keyword") { |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
472 cx.cc.push(arguments[i]); | 474 cx.cc.push(arguments[i]); |
473 return cont(pushlex(end, info), commasep(what, end), poplex); | 475 return cont(pushlex(end, info), commasep(what, end), poplex); |
474 } | 476 } |
475 function block(type) { | 477 function block(type) { |
476 if (type == "}") return cont(); | 478 if (type == "}") return cont(); |
477 return pass(statement, block); | 479 return pass(statement, block); |
478 } | 480 } |
479 function maybetype(type) { | 481 function maybetype(type) { |
480 if (isTS && type == ":") return cont(typedef); | 482 if (isTS && type == ":") return cont(typedef); |
481 } | 483 } |
| 484 function maybedefault(_, value) { |
| 485 if (value == "=") return cont(expressionNoComma); |
| 486 } |
482 function typedef(type) { | 487 function typedef(type) { |
483 if (type == "variable"){cx.marked = "variable-3"; return cont();} | 488 if (type == "variable") {cx.marked = "variable-3"; return cont();} |
484 } | 489 } |
485 function vardef() { | 490 function vardef() { |
486 return pass(pattern, maybetype, maybeAssign, vardefCont); | 491 return pass(pattern, maybetype, maybeAssign, vardefCont); |
487 } | 492 } |
488 function pattern(type, value) { | 493 function pattern(type, value) { |
489 if (type == "variable") { register(value); return cont(); } | 494 if (type == "variable") { register(value); return cont(); } |
490 if (type == "[") return contCommasep(pattern, "]"); | 495 if (type == "[") return contCommasep(pattern, "]"); |
491 if (type == "{") return contCommasep(proppattern, "}"); | 496 if (type == "{") return contCommasep(proppattern, "}"); |
492 } | 497 } |
493 function proppattern(type, value) { | 498 function proppattern(type, value) { |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
528 function forspec3(type) { | 533 function forspec3(type) { |
529 if (type != ")") cont(expression); | 534 if (type != ")") cont(expression); |
530 } | 535 } |
531 function functiondef(type, value) { | 536 function functiondef(type, value) { |
532 if (value == "*") {cx.marked = "keyword"; return cont(functiondef);} | 537 if (value == "*") {cx.marked = "keyword"; return cont(functiondef);} |
533 if (type == "variable") {register(value); return cont(functiondef);} | 538 if (type == "variable") {register(value); return cont(functiondef);} |
534 if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"
), poplex, statement, popcontext); | 539 if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"
), poplex, statement, popcontext); |
535 } | 540 } |
536 function funarg(type) { | 541 function funarg(type) { |
537 if (type == "spread") return cont(funarg); | 542 if (type == "spread") return cont(funarg); |
538 return pass(pattern, maybetype); | 543 return pass(pattern, maybetype, maybedefault); |
539 } | 544 } |
540 function className(type, value) { | 545 function className(type, value) { |
541 if (type == "variable") {register(value); return cont(classNameAfter);} | 546 if (type == "variable") {register(value); return cont(classNameAfter);} |
542 } | 547 } |
543 function classNameAfter(type, value) { | 548 function classNameAfter(type, value) { |
544 if (value == "extends") return cont(expression, classNameAfter); | 549 if (value == "extends") return cont(expression, classNameAfter); |
545 if (type == "{") return cont(pushlex("}"), classBody, poplex); | 550 if (type == "{") return cont(pushlex("}"), classBody, poplex); |
546 } | 551 } |
547 function classBody(type, value) { | 552 function classBody(type, value) { |
548 if (type == "variable" || cx.style == "keyword") { | 553 if (type == "variable" || cx.style == "keyword") { |
| 554 if (value == "static") { |
| 555 cx.marked = "keyword"; |
| 556 return cont(classBody); |
| 557 } |
549 cx.marked = "property"; | 558 cx.marked = "property"; |
550 if (value == "get" || value == "set") return cont(classGetterSetter, funct
iondef, classBody); | 559 if (value == "get" || value == "set") return cont(classGetterSetter, funct
iondef, classBody); |
551 return cont(functiondef, classBody); | 560 return cont(functiondef, classBody); |
552 } | 561 } |
553 if (value == "*") { | 562 if (value == "*") { |
554 cx.marked = "keyword"; | 563 cx.marked = "keyword"; |
555 return cont(classBody); | 564 return cont(classBody); |
556 } | 565 } |
557 if (type == ";") return cont(classBody); | 566 if (type == ";") return cont(classBody); |
558 if (type == "}") return cont(); | 567 if (type == "}") return cont(); |
559 } | 568 } |
560 function classGetterSetter(type) { | 569 function classGetterSetter(type) { |
561 if (type != "variable") return pass(); | 570 if (type != "variable") return pass(); |
562 cx.marked = "property"; | 571 cx.marked = "property"; |
563 return cont(); | 572 return cont(); |
564 } | 573 } |
565 function afterModule(type, value) { | |
566 if (type == "string") return cont(statement); | |
567 if (type == "variable") { register(value); return cont(maybeFrom); } | |
568 } | |
569 function afterExport(_type, value) { | 574 function afterExport(_type, value) { |
570 if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";"
)); } | 575 if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";"
)); } |
571 if (value == "default") { cx.marked = "keyword"; return cont(expression, exp
ect(";")); } | 576 if (value == "default") { cx.marked = "keyword"; return cont(expression, exp
ect(";")); } |
572 return pass(statement); | 577 return pass(statement); |
573 } | 578 } |
574 function afterImport(type) { | 579 function afterImport(type) { |
575 if (type == "string") return cont(); | 580 if (type == "string") return cont(); |
576 return pass(importSpec, maybeFrom); | 581 return pass(importSpec, maybeFrom); |
577 } | 582 } |
578 function importSpec(type, value) { | 583 function importSpec(type, value) { |
579 if (type == "{") return contCommasep(importSpec, "}"); | 584 if (type == "{") return contCommasep(importSpec, "}"); |
580 if (type == "variable") register(value); | 585 if (type == "variable") register(value); |
581 return cont(); | 586 if (value == "*") cx.marked = "keyword"; |
| 587 return cont(maybeAs); |
| 588 } |
| 589 function maybeAs(_type, value) { |
| 590 if (value == "as") { cx.marked = "keyword"; return cont(importSpec); } |
582 } | 591 } |
583 function maybeFrom(_type, value) { | 592 function maybeFrom(_type, value) { |
584 if (value == "from") { cx.marked = "keyword"; return cont(expression); } | 593 if (value == "from") { cx.marked = "keyword"; return cont(expression); } |
585 } | 594 } |
586 function arrayLiteral(type) { | 595 function arrayLiteral(type) { |
587 if (type == "]") return cont(); | 596 if (type == "]") return cont(); |
588 return pass(expressionNoComma, maybeArrayComprehension); | 597 return pass(expressionNoComma, maybeArrayComprehension); |
589 } | 598 } |
590 function maybeArrayComprehension(type) { | 599 function maybeArrayComprehension(type) { |
591 if (type == "for") return pass(comprehension, expect("]")); | 600 if (type == "for") return pass(comprehension, expect("]")); |
592 if (type == ",") return cont(commasep(expressionNoComma, "]")); | 601 if (type == ",") return cont(commasep(maybeexpressionNoComma, "]")); |
593 return pass(commasep(expressionNoComma, "]")); | 602 return pass(commasep(expressionNoComma, "]")); |
594 } | 603 } |
595 function comprehension(type) { | 604 function comprehension(type) { |
596 if (type == "for") return cont(forspec, comprehension); | 605 if (type == "for") return cont(forspec, comprehension); |
597 if (type == "if") return cont(expression, comprehension); | 606 if (type == "if") return cont(expression, comprehension); |
598 } | 607 } |
599 | 608 |
| 609 function isContinuedStatement(state, textAfter) { |
| 610 return state.lastType == "operator" || state.lastType == "," || |
| 611 isOperatorChar.test(textAfter.charAt(0)) || |
| 612 /[,.]/.test(textAfter.charAt(0)); |
| 613 } |
| 614 |
600 // Interface | 615 // Interface |
601 | 616 |
602 return { | 617 return { |
603 startState: function(basecolumn) { | 618 startState: function(basecolumn) { |
604 var state = { | 619 var state = { |
605 tokenize: tokenBase, | 620 tokenize: tokenBase, |
606 lastType: "sof", | 621 lastType: "sof", |
607 cc: [], | 622 cc: [], |
608 lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false
), | 623 lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false
), |
609 localVars: parserConfig.localVars, | 624 localVars: parserConfig.localVars, |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
641 } | 656 } |
642 if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev; | 657 if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev; |
643 if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat") | 658 if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat") |
644 lexical = lexical.prev; | 659 lexical = lexical.prev; |
645 var type = lexical.type, closing = firstChar == type; | 660 var type = lexical.type, closing = firstChar == type; |
646 | 661 |
647 if (type == "vardef") return lexical.indented + (state.lastType == "operat
or" || state.lastType == "," ? lexical.info + 1 : 0); | 662 if (type == "vardef") return lexical.indented + (state.lastType == "operat
or" || state.lastType == "," ? lexical.info + 1 : 0); |
648 else if (type == "form" && firstChar == "{") return lexical.indented; | 663 else if (type == "form" && firstChar == "{") return lexical.indented; |
649 else if (type == "form") return lexical.indented + indentUnit; | 664 else if (type == "form") return lexical.indented + indentUnit; |
650 else if (type == "stat") | 665 else if (type == "stat") |
651 return lexical.indented + (state.lastType == "operator" || state.lastTyp
e == "," ? statementIndent || indentUnit : 0); | 666 return lexical.indented + (isContinuedStatement(state, textAfter) ? stat
ementIndent || indentUnit : 0); |
652 else if (lexical.info == "switch" && !closing && parserConfig.doubleIndent
Switch != false) | 667 else if (lexical.info == "switch" && !closing && parserConfig.doubleIndent
Switch != false) |
653 return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? inden
tUnit : 2 * indentUnit); | 668 return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? inden
tUnit : 2 * indentUnit); |
654 else if (lexical.align) return lexical.column + (closing ? 0 : 1); | 669 else if (lexical.align) return lexical.column + (closing ? 0 : 1); |
655 else return lexical.indented + (closing ? 0 : indentUnit); | 670 else return lexical.indented + (closing ? 0 : indentUnit); |
656 }, | 671 }, |
657 | 672 |
658 electricChars: ":{}", | 673 electricInput: /^\s*(?:case .*?:|default:|\{|\})$/, |
659 blockCommentStart: jsonMode ? null : "/*", | 674 blockCommentStart: jsonMode ? null : "/*", |
660 blockCommentEnd: jsonMode ? null : "*/", | 675 blockCommentEnd: jsonMode ? null : "*/", |
661 lineComment: jsonMode ? null : "//", | 676 lineComment: jsonMode ? null : "//", |
662 fold: "brace", | 677 fold: "brace", |
| 678 closeBrackets: "()[]{}''\"\"``", |
663 | 679 |
664 helperType: jsonMode ? "json" : "javascript", | 680 helperType: jsonMode ? "json" : "javascript", |
665 jsonldMode: jsonldMode, | 681 jsonldMode: jsonldMode, |
666 jsonMode: jsonMode | 682 jsonMode: jsonMode |
667 }; | 683 }; |
668 }); | 684 }); |
669 | 685 |
670 CodeMirror.registerHelper("wordChars", "javascript", /[\\w$]/); | 686 CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/); |
671 | 687 |
672 CodeMirror.defineMIME("text/javascript", "javascript"); | 688 CodeMirror.defineMIME("text/javascript", "javascript"); |
673 CodeMirror.defineMIME("text/ecmascript", "javascript"); | 689 CodeMirror.defineMIME("text/ecmascript", "javascript"); |
674 CodeMirror.defineMIME("application/javascript", "javascript"); | 690 CodeMirror.defineMIME("application/javascript", "javascript"); |
675 CodeMirror.defineMIME("application/x-javascript", "javascript"); | 691 CodeMirror.defineMIME("application/x-javascript", "javascript"); |
676 CodeMirror.defineMIME("application/ecmascript", "javascript"); | 692 CodeMirror.defineMIME("application/ecmascript", "javascript"); |
677 CodeMirror.defineMIME("application/json", {name: "javascript", json: true}); | 693 CodeMirror.defineMIME("application/json", {name: "javascript", json: true}); |
678 CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true}); | 694 CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true}); |
679 CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true})
; | 695 CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true})
; |
680 CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true
}); | 696 CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true
}); |
681 CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript
: true }); | 697 CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript
: true }); |
682 | 698 |
683 }); | 699 }); |
OLD | NEW |