OLD | NEW |
| 1 // CodeMirror, copyright (c) by Marijn Haverbeke and others |
| 2 // Distributed under an MIT license: http://codemirror.net/LICENSE |
| 3 |
1 // TODO actually recognize syntax of TypeScript constructs | 4 // TODO actually recognize syntax of TypeScript constructs |
2 | 5 |
| 6 (function(mod) { |
| 7 if (typeof exports == "object" && typeof module == "object") // CommonJS |
| 8 mod(require("../../lib/codemirror")); |
| 9 else if (typeof define == "function" && define.amd) // AMD |
| 10 define(["../../lib/codemirror"], mod); |
| 11 else // Plain browser env |
| 12 mod(CodeMirror); |
| 13 })(function(CodeMirror) { |
| 14 "use strict"; |
| 15 |
3 CodeMirror.defineMode("javascript", function(config, parserConfig) { | 16 CodeMirror.defineMode("javascript", function(config, parserConfig) { |
4 var indentUnit = config.indentUnit; | 17 var indentUnit = config.indentUnit; |
5 var statementIndent = parserConfig.statementIndent; | 18 var statementIndent = parserConfig.statementIndent; |
6 var jsonMode = parserConfig.json; | 19 var jsonldMode = parserConfig.jsonld; |
| 20 var jsonMode = parserConfig.json || jsonldMode; |
7 var isTS = parserConfig.typescript; | 21 var isTS = parserConfig.typescript; |
8 | 22 |
9 // Tokenizer | 23 // Tokenizer |
10 | 24 |
11 var keywords = function(){ | 25 var keywords = function(){ |
12 function kw(type) {return {type: type, style: "keyword"};} | 26 function kw(type) {return {type: type, style: "keyword"};} |
13 var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c"); | 27 var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c"); |
14 var operator = kw("operator"), atom = {type: "atom", style: "atom"}; | 28 var operator = kw("operator"), atom = {type: "atom", style: "atom"}; |
15 | 29 |
16 var jsKeywords = { | 30 var jsKeywords = { |
17 "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "fina
lly": B, | 31 "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "fina
lly": B, |
18 "return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C, | 32 "return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C,
"debugger": C, |
19 "var": kw("var"), "const": kw("var"), "let": kw("var"), | 33 "var": kw("var"), "const": kw("var"), "let": kw("var"), |
20 "function": kw("function"), "catch": kw("catch"), | 34 "function": kw("function"), "catch": kw("catch"), |
21 "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": k
w("default"), | 35 "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": k
w("default"), |
22 "in": operator, "typeof": operator, "instanceof": operator, | 36 "in": operator, "typeof": operator, "instanceof": operator, |
23 "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom,
"Infinity": atom, | 37 "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom,
"Infinity": atom, |
24 "this": kw("this"), "module": kw("module"), "class": kw("class"), "super":
kw("atom"), | 38 "this": kw("this"), "module": kw("module"), "class": kw("class"), "super":
kw("atom"), |
25 "yield": C, "export": kw("export"), "import": kw("import"), "extends": C | 39 "yield": C, "export": kw("export"), "import": kw("import"), "extends": C |
26 }; | 40 }; |
27 | 41 |
28 // Extend the 'normal' keywords with the TypeScript language extensions | 42 // Extend the 'normal' keywords with the TypeScript language extensions |
(...skipping 17 matching lines...) Expand all Loading... |
46 | 60 |
47 for (var attr in tsKeywords) { | 61 for (var attr in tsKeywords) { |
48 jsKeywords[attr] = tsKeywords[attr]; | 62 jsKeywords[attr] = tsKeywords[attr]; |
49 } | 63 } |
50 } | 64 } |
51 | 65 |
52 return jsKeywords; | 66 return jsKeywords; |
53 }(); | 67 }(); |
54 | 68 |
55 var isOperatorChar = /[+\-*&%=<>!?|~^]/; | 69 var isOperatorChar = /[+\-*&%=<>!?|~^]/; |
| 70 var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|re
verse|index|base|vocab|graph)"/; |
56 | 71 |
57 function nextUntilUnescaped(stream, end) { | 72 function readRegexp(stream) { |
58 var escaped = false, next; | 73 var escaped = false, next, inSet = false; |
59 while ((next = stream.next()) != null) { | 74 while ((next = stream.next()) != null) { |
60 if (next == end && !escaped) | 75 if (!escaped) { |
61 return false; | 76 if (next == "/" && !inSet) return; |
| 77 if (next == "[") inSet = true; |
| 78 else if (inSet && next == "]") inSet = false; |
| 79 } |
62 escaped = !escaped && next == "\\"; | 80 escaped = !escaped && next == "\\"; |
63 } | 81 } |
64 return escaped; | |
65 } | 82 } |
66 | 83 |
67 // Used as scratch variables to communicate multiple values without | 84 // Used as scratch variables to communicate multiple values without |
68 // consing up tons of objects. | 85 // consing up tons of objects. |
69 var type, content; | 86 var type, content; |
70 function ret(tp, style, cont) { | 87 function ret(tp, style, cont) { |
71 type = tp; content = cont; | 88 type = tp; content = cont; |
72 return style; | 89 return style; |
73 } | 90 } |
74 function tokenBase(stream, state) { | 91 function tokenBase(stream, state) { |
75 var ch = stream.next(); | 92 var ch = stream.next(); |
76 if (ch == '"' || ch == "'") { | 93 if (ch == '"' || ch == "'") { |
77 state.tokenize = tokenString(ch); | 94 state.tokenize = tokenString(ch); |
78 return state.tokenize(stream, state); | 95 return state.tokenize(stream, state); |
79 } else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) { | 96 } else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) { |
80 return ret("number", "number"); | 97 return ret("number", "number"); |
81 } else if (ch == "." && stream.match("..")) { | 98 } else if (ch == "." && stream.match("..")) { |
82 return ret("spread", "meta"); | 99 return ret("spread", "meta"); |
83 } else if (/[\[\]{}\(\),;\:\.]/.test(ch)) { | 100 } else if (/[\[\]{}\(\),;\:\.]/.test(ch)) { |
84 return ret(ch); | 101 return ret(ch); |
85 } else if (ch == "=" && stream.eat(">")) { | 102 } else if (ch == "=" && stream.eat(">")) { |
86 return ret("=>"); | 103 return ret("=>", "operator"); |
87 } else if (ch == "0" && stream.eat(/x/i)) { | 104 } else if (ch == "0" && stream.eat(/x/i)) { |
88 stream.eatWhile(/[\da-f]/i); | 105 stream.eatWhile(/[\da-f]/i); |
89 return ret("number", "number"); | 106 return ret("number", "number"); |
90 } else if (/\d/.test(ch)) { | 107 } else if (/\d/.test(ch)) { |
91 stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/); | 108 stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/); |
92 return ret("number", "number"); | 109 return ret("number", "number"); |
93 } else if (ch == "/") { | 110 } else if (ch == "/") { |
94 if (stream.eat("*")) { | 111 if (stream.eat("*")) { |
95 state.tokenize = tokenComment; | 112 state.tokenize = tokenComment; |
96 return tokenComment(stream, state); | 113 return tokenComment(stream, state); |
97 } else if (stream.eat("/")) { | 114 } else if (stream.eat("/")) { |
98 stream.skipToEnd(); | 115 stream.skipToEnd(); |
99 return ret("comment", "comment"); | 116 return ret("comment", "comment"); |
100 } else if (state.lastType == "operator" || state.lastType == "keyword c" |
| | 117 } else if (state.lastType == "operator" || state.lastType == "keyword c" |
| |
101 state.lastType == "sof" || /^[\[{}\(,;:]$/.test(state.lastType))
{ | 118 state.lastType == "sof" || /^[\[{}\(,;:]$/.test(state.lastType))
{ |
102 nextUntilUnescaped(stream, "/"); | 119 readRegexp(stream); |
103 stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla | 120 stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla |
104 return ret("regexp", "string-2"); | 121 return ret("regexp", "string-2"); |
105 } else { | 122 } else { |
106 stream.eatWhile(isOperatorChar); | 123 stream.eatWhile(isOperatorChar); |
107 return ret("operator", null, stream.current()); | 124 return ret("operator", "operator", stream.current()); |
108 } | 125 } |
109 } else if (ch == "`") { | 126 } else if (ch == "`") { |
110 state.tokenize = tokenQuasi; | 127 state.tokenize = tokenQuasi; |
111 return tokenQuasi(stream, state); | 128 return tokenQuasi(stream, state); |
112 } else if (ch == "#") { | 129 } else if (ch == "#") { |
113 stream.skipToEnd(); | 130 stream.skipToEnd(); |
114 return ret("error", "error"); | 131 return ret("error", "error"); |
115 } else if (isOperatorChar.test(ch)) { | 132 } else if (isOperatorChar.test(ch)) { |
116 stream.eatWhile(isOperatorChar); | 133 stream.eatWhile(isOperatorChar); |
117 return ret("operator", null, stream.current()); | 134 return ret("operator", "operator", stream.current()); |
118 } else { | 135 } else { |
119 stream.eatWhile(/[\w\$_]/); | 136 stream.eatWhile(/[\w\$_]/); |
120 var word = stream.current(), known = keywords.propertyIsEnumerable(word) &
& keywords[word]; | 137 var word = stream.current(), known = keywords.propertyIsEnumerable(word) &
& keywords[word]; |
121 return (known && state.lastType != ".") ? ret(known.type, known.style, wor
d) : | 138 return (known && state.lastType != ".") ? ret(known.type, known.style, wor
d) : |
122 ret("variable", "variable", word); | 139 ret("variable", "variable", word); |
123 } | 140 } |
124 } | 141 } |
125 | 142 |
126 function tokenString(quote) { | 143 function tokenString(quote) { |
127 return function(stream, state) { | 144 return function(stream, state) { |
128 if (!nextUntilUnescaped(stream, quote)) | 145 var escaped = false, next; |
| 146 if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){ |
129 state.tokenize = tokenBase; | 147 state.tokenize = tokenBase; |
| 148 return ret("jsonld-keyword", "meta"); |
| 149 } |
| 150 while ((next = stream.next()) != null) { |
| 151 if (next == quote && !escaped) break; |
| 152 escaped = !escaped && next == "\\"; |
| 153 } |
| 154 if (!escaped) state.tokenize = tokenBase; |
130 return ret("string", "string"); | 155 return ret("string", "string"); |
131 }; | 156 }; |
132 } | 157 } |
133 | 158 |
134 function tokenComment(stream, state) { | 159 function tokenComment(stream, state) { |
135 var maybeEnd = false, ch; | 160 var maybeEnd = false, ch; |
136 while (ch = stream.next()) { | 161 while (ch = stream.next()) { |
137 if (ch == "/" && maybeEnd) { | 162 if (ch == "/" && maybeEnd) { |
138 state.tokenize = tokenBase; | 163 state.tokenize = tokenBase; |
139 break; | 164 break; |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
182 } else if (sawSomething && !depth) { | 207 } else if (sawSomething && !depth) { |
183 ++pos; | 208 ++pos; |
184 break; | 209 break; |
185 } | 210 } |
186 } | 211 } |
187 if (sawSomething && !depth) state.fatArrowAt = pos; | 212 if (sawSomething && !depth) state.fatArrowAt = pos; |
188 } | 213 } |
189 | 214 |
190 // Parser | 215 // Parser |
191 | 216 |
192 var atomicTypes = {"atom": true, "number": true, "variable": true, "string": t
rue, "regexp": true, "this": true}; | 217 var atomicTypes = {"atom": true, "number": true, "variable": true, "string": t
rue, "regexp": true, "this": true, "jsonld-keyword": true}; |
193 | 218 |
194 function JSLexical(indented, column, type, align, prev, info) { | 219 function JSLexical(indented, column, type, align, prev, info) { |
195 this.indented = indented; | 220 this.indented = indented; |
196 this.column = column; | 221 this.column = column; |
197 this.type = type; | 222 this.type = type; |
198 this.prev = prev; | 223 this.prev = prev; |
199 this.info = info; | 224 this.info = info; |
200 if (align != null) this.align = align; | 225 if (align != null) this.align = align; |
201 } | 226 } |
202 | 227 |
203 function inScope(state, varname) { | 228 function inScope(state, varname) { |
204 for (var v = state.localVars; v; v = v.next) | 229 for (var v = state.localVars; v; v = v.next) |
205 if (v.name == varname) return true; | 230 if (v.name == varname) return true; |
206 for (var cx = state.context; cx; cx = cx.prev) { | 231 for (var cx = state.context; cx; cx = cx.prev) { |
207 for (var v = cx.vars; v; v = v.next) | 232 for (var v = cx.vars; v; v = v.next) |
208 if (v.name == varname) return true; | 233 if (v.name == varname) return true; |
209 } | 234 } |
210 } | 235 } |
211 | 236 |
212 function parseJS(state, style, type, content, stream) { | 237 function parseJS(state, style, type, content, stream) { |
213 var cc = state.cc; | 238 var cc = state.cc; |
214 // Communicate our context to the combinators. | 239 // Communicate our context to the combinators. |
215 // (Less wasteful than consing up a hundred closures on every call.) | 240 // (Less wasteful than consing up a hundred closures on every call.) |
216 cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; | 241 cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style
= style; |
217 | 242 |
218 if (!state.lexical.hasOwnProperty("align")) | 243 if (!state.lexical.hasOwnProperty("align")) |
219 state.lexical.align = true; | 244 state.lexical.align = true; |
220 | 245 |
221 while(true) { | 246 while(true) { |
222 var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement; | 247 var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement; |
223 if (combinator(type, content)) { | 248 if (combinator(type, content)) { |
224 while(cc.length && cc[cc.length - 1].lex) | 249 while(cc.length && cc[cc.length - 1].lex) |
225 cc.pop()(); | 250 cc.pop()(); |
226 if (cx.marked) return cx.marked; | 251 if (cx.marked) return cx.marked; |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
282 var state = cx.state; | 307 var state = cx.state; |
283 if (state.lexical.prev) { | 308 if (state.lexical.prev) { |
284 if (state.lexical.type == ")") | 309 if (state.lexical.type == ")") |
285 state.indented = state.lexical.indented; | 310 state.indented = state.lexical.indented; |
286 state.lexical = state.lexical.prev; | 311 state.lexical = state.lexical.prev; |
287 } | 312 } |
288 } | 313 } |
289 poplex.lex = true; | 314 poplex.lex = true; |
290 | 315 |
291 function expect(wanted) { | 316 function expect(wanted) { |
292 return function(type) { | 317 function exp(type) { |
293 if (type == wanted) return cont(); | 318 if (type == wanted) return cont(); |
294 else if (wanted == ";") return pass(); | 319 else if (wanted == ";") return pass(); |
295 else return cont(arguments.callee); | 320 else return cont(exp); |
296 }; | 321 }; |
| 322 return exp; |
297 } | 323 } |
298 | 324 |
299 function statement(type, value) { | 325 function statement(type, value) { |
300 if (type == "var") return cont(pushlex("vardef", value.length), vardef, expe
ct(";"), poplex); | 326 if (type == "var") return cont(pushlex("vardef", value.length), vardef, expe
ct(";"), poplex); |
301 if (type == "keyword a") return cont(pushlex("form"), expression, statement,
poplex); | 327 if (type == "keyword a") return cont(pushlex("form"), expression, statement,
poplex); |
302 if (type == "keyword b") return cont(pushlex("form"), statement, poplex); | 328 if (type == "keyword b") return cont(pushlex("form"), statement, poplex); |
303 if (type == "{") return cont(pushlex("}"), block, poplex); | 329 if (type == "{") return cont(pushlex("}"), block, poplex); |
304 if (type == ";") return cont(); | 330 if (type == ";") return cont(); |
305 if (type == "if") return cont(pushlex("form"), expression, statement, poplex
, maybeelse); | 331 if (type == "if") { |
| 332 if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1]
== poplex) |
| 333 cx.state.cc.pop()(); |
| 334 return cont(pushlex("form"), expression, statement, poplex, maybeelse); |
| 335 } |
306 if (type == "function") return cont(functiondef); | 336 if (type == "function") return cont(functiondef); |
307 if (type == "for") return cont(pushlex("form"), forspec, poplex, statement,
poplex); | 337 if (type == "for") return cont(pushlex("form"), forspec, statement, poplex); |
308 if (type == "variable") return cont(pushlex("stat"), maybelabel); | 338 if (type == "variable") return cont(pushlex("stat"), maybelabel); |
309 if (type == "switch") return cont(pushlex("form"), expression, pushlex("}",
"switch"), expect("{"), | 339 if (type == "switch") return cont(pushlex("form"), expression, pushlex("}",
"switch"), expect("{"), |
310 block, poplex, poplex); | 340 block, poplex, poplex); |
311 if (type == "case") return cont(expression, expect(":")); | 341 if (type == "case") return cont(expression, expect(":")); |
312 if (type == "default") return cont(expect(":")); | 342 if (type == "default") return cont(expect(":")); |
313 if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("),
funarg, expect(")"), | 343 if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("),
funarg, expect(")"), |
314 statement, poplex, popcontext); | 344 statement, poplex, popcontext); |
315 if (type == "module") return cont(pushlex("form"), pushcontext, afterModule,
popcontext, poplex); | 345 if (type == "module") return cont(pushlex("form"), pushcontext, afterModule,
popcontext, poplex); |
316 if (type == "class") return cont(pushlex("form"), className, objlit, poplex)
; | 346 if (type == "class") return cont(pushlex("form"), className, poplex); |
317 if (type == "export") return cont(pushlex("form"), afterExport, poplex); | 347 if (type == "export") return cont(pushlex("form"), afterExport, poplex); |
318 if (type == "import") return cont(pushlex("form"), afterImport, poplex); | 348 if (type == "import") return cont(pushlex("form"), afterImport, poplex); |
319 return pass(pushlex("stat"), expression, expect(";"), poplex); | 349 return pass(pushlex("stat"), expression, expect(";"), poplex); |
320 } | 350 } |
321 function expression(type) { | 351 function expression(type) { |
322 return expressionInner(type, false); | 352 return expressionInner(type, false); |
323 } | 353 } |
324 function expressionNoComma(type) { | 354 function expressionNoComma(type) { |
325 return expressionInner(type, true); | 355 return expressionInner(type, true); |
326 } | 356 } |
327 function expressionInner(type, noComma) { | 357 function expressionInner(type, noComma) { |
328 if (cx.state.fatArrowAt == cx.stream.start) { | 358 if (cx.state.fatArrowAt == cx.stream.start) { |
329 var body = noComma ? arrowBodyNoComma : arrowBody; | 359 var body = noComma ? arrowBodyNoComma : arrowBody; |
330 if (type == "(") return cont(pushcontext, commasep(pattern, ")"), expect("
=>"), body, popcontext); | 360 if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern,
")"), poplex, expect("=>"), body, popcontext); |
331 else if (type == "variable") return pass(pushcontext, pattern, expect("=>"
), body, popcontext); | 361 else if (type == "variable") return pass(pushcontext, pattern, expect("=>"
), body, popcontext); |
332 } | 362 } |
333 | 363 |
334 var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma; | 364 var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma; |
335 if (atomicTypes.hasOwnProperty(type)) return cont(maybeop); | 365 if (atomicTypes.hasOwnProperty(type)) return cont(maybeop); |
336 if (type == "function") return cont(functiondef); | 366 if (type == "function") return cont(functiondef, maybeop); |
337 if (type == "keyword c") return cont(noComma ? maybeexpressionNoComma : mayb
eexpression); | 367 if (type == "keyword c") return cont(noComma ? maybeexpressionNoComma : mayb
eexpression); |
338 if (type == "(") return cont(pushlex(")"), maybeexpression, comprehension, e
xpect(")"), poplex, maybeop); | 368 if (type == "(") return cont(pushlex(")"), maybeexpression, comprehension, e
xpect(")"), poplex, maybeop); |
339 if (type == "operator" || type == "spread") return cont(noComma ? expression
NoComma : expression); | 369 if (type == "operator" || type == "spread") return cont(noComma ? expression
NoComma : expression); |
340 if (type == "[") return cont(pushlex("]"), expressionNoComma, maybeArrayComp
rehension, poplex, maybeop); | 370 if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop); |
341 if (type == "{") return cont(commasep(objprop, "}"), maybeop); | 371 if (type == "{") return contCommasep(objprop, "}", null, maybeop); |
| 372 if (type == "quasi") { return pass(quasi, maybeop); } |
342 return cont(); | 373 return cont(); |
343 } | 374 } |
344 function maybeexpression(type) { | 375 function maybeexpression(type) { |
345 if (type.match(/[;\}\)\],]/)) return pass(); | 376 if (type.match(/[;\}\)\],]/)) return pass(); |
346 return pass(expression); | 377 return pass(expression); |
347 } | 378 } |
348 function maybeexpressionNoComma(type) { | 379 function maybeexpressionNoComma(type) { |
349 if (type.match(/[;\}\)\],]/)) return pass(); | 380 if (type.match(/[;\}\)\],]/)) return pass(); |
350 return pass(expressionNoComma); | 381 return pass(expressionNoComma); |
351 } | 382 } |
352 | 383 |
353 function maybeoperatorComma(type, value) { | 384 function maybeoperatorComma(type, value) { |
354 if (type == ",") return cont(expression); | 385 if (type == ",") return cont(expression); |
355 return maybeoperatorNoComma(type, value, false); | 386 return maybeoperatorNoComma(type, value, false); |
356 } | 387 } |
357 function maybeoperatorNoComma(type, value, noComma) { | 388 function maybeoperatorNoComma(type, value, noComma) { |
358 var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma; | 389 var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma; |
359 var expr = noComma == false ? expression : expressionNoComma; | 390 var expr = noComma == false ? expression : expressionNoComma; |
360 if (value == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arr
owBody, popcontext); | 391 if (value == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arr
owBody, popcontext); |
361 if (type == "operator") { | 392 if (type == "operator") { |
362 if (/\+\+|--/.test(value)) return cont(me); | 393 if (/\+\+|--/.test(value)) return cont(me); |
363 if (value == "?") return cont(expression, expect(":"), expr); | 394 if (value == "?") return cont(expression, expect(":"), expr); |
364 return cont(expr); | 395 return cont(expr); |
365 } | 396 } |
366 if (type == "quasi") { cx.cc.push(me); return quasi(value); } | 397 if (type == "quasi") { return pass(quasi, me); } |
367 if (type == ";") return; | 398 if (type == ";") return; |
368 if (type == "(") return cont(commasep(expressionNoComma, ")", "call"), me); | 399 if (type == "(") return contCommasep(expressionNoComma, ")", "call", me); |
369 if (type == ".") return cont(property, me); | 400 if (type == ".") return cont(property, me); |
370 if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), pop
lex, me); | 401 if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), pop
lex, me); |
371 } | 402 } |
372 function quasi(value) { | 403 function quasi(type, value) { |
373 if (!value) debugger; | 404 if (type != "quasi") return pass(); |
374 if (value.slice(value.length - 2) != "${") return cont(); | 405 if (value.slice(value.length - 2) != "${") return cont(quasi); |
375 return cont(expression, continueQuasi); | 406 return cont(expression, continueQuasi); |
376 } | 407 } |
377 function continueQuasi(type) { | 408 function continueQuasi(type) { |
378 if (type == "}") { | 409 if (type == "}") { |
379 cx.marked = "string-2"; | 410 cx.marked = "string-2"; |
380 cx.state.tokenize = tokenQuasi; | 411 cx.state.tokenize = tokenQuasi; |
381 return cont(); | 412 return cont(quasi); |
382 } | 413 } |
383 } | 414 } |
384 function arrowBody(type) { | 415 function arrowBody(type) { |
385 findFatArrow(cx.stream, cx.state); | 416 findFatArrow(cx.stream, cx.state); |
386 if (type == "{") return pass(statement); | 417 if (type == "{") return pass(statement); |
387 return pass(expression); | 418 return pass(expression); |
388 } | 419 } |
389 function arrowBodyNoComma(type) { | 420 function arrowBodyNoComma(type) { |
390 findFatArrow(cx.stream, cx.state); | 421 findFatArrow(cx.stream, cx.state); |
391 if (type == "{") return pass(statement); | 422 if (type == "{") return pass(statement); |
392 return pass(expressionNoComma); | 423 return pass(expressionNoComma); |
393 } | 424 } |
394 function maybelabel(type) { | 425 function maybelabel(type) { |
395 if (type == ":") return cont(poplex, statement); | 426 if (type == ":") return cont(poplex, statement); |
396 return pass(maybeoperatorComma, expect(";"), poplex); | 427 return pass(maybeoperatorComma, expect(";"), poplex); |
397 } | 428 } |
398 function property(type) { | 429 function property(type) { |
399 if (type == "variable") {cx.marked = "property"; return cont();} | 430 if (type == "variable") {cx.marked = "property"; return cont();} |
400 } | 431 } |
401 function objprop(type, value) { | 432 function objprop(type, value) { |
402 if (type == "variable") { | 433 if (type == "variable" || cx.style == "keyword") { |
403 cx.marked = "property"; | 434 cx.marked = "property"; |
404 if (value == "get" || value == "set") return cont(getterSetter); | 435 if (value == "get" || value == "set") return cont(getterSetter); |
| 436 return cont(afterprop); |
405 } else if (type == "number" || type == "string") { | 437 } else if (type == "number" || type == "string") { |
406 cx.marked = type + " property"; | 438 cx.marked = jsonldMode ? "property" : (cx.style + " property"); |
| 439 return cont(afterprop); |
| 440 } else if (type == "jsonld-keyword") { |
| 441 return cont(afterprop); |
407 } else if (type == "[") { | 442 } else if (type == "[") { |
408 return cont(expression, expect("]"), afterprop); | 443 return cont(expression, expect("]"), afterprop); |
409 } | 444 } |
410 if (atomicTypes.hasOwnProperty(type)) return cont(afterprop); | |
411 } | 445 } |
412 function getterSetter(type) { | 446 function getterSetter(type) { |
413 if (type != "variable") return pass(afterprop); | 447 if (type != "variable") return pass(afterprop); |
414 cx.marked = "property"; | 448 cx.marked = "property"; |
415 return cont(functiondef); | 449 return cont(functiondef); |
416 } | 450 } |
417 function afterprop(type) { | 451 function afterprop(type) { |
418 if (type == ":") return cont(expressionNoComma); | 452 if (type == ":") return cont(expressionNoComma); |
419 if (type == "(") return pass(functiondef); | 453 if (type == "(") return pass(functiondef); |
420 } | 454 } |
421 function commasep(what, end, info) { | 455 function commasep(what, end) { |
422 function proceed(type) { | 456 function proceed(type) { |
423 if (type == ",") { | 457 if (type == ",") { |
424 var lex = cx.state.lexical; | 458 var lex = cx.state.lexical; |
425 if (lex.info == "call") lex.pos = (lex.pos || 0) + 1; | 459 if (lex.info == "call") lex.pos = (lex.pos || 0) + 1; |
426 return cont(what, proceed); | 460 return cont(what, proceed); |
427 } | 461 } |
428 if (type == end) return cont(); | 462 if (type == end) return cont(); |
429 return cont(expect(end)); | 463 return cont(expect(end)); |
430 } | 464 } |
431 return function(type) { | 465 return function(type) { |
432 if (type == end) return cont(); | 466 if (type == end) return cont(); |
433 if (info === false) return pass(what, proceed); | 467 return pass(what, proceed); |
434 return pass(pushlex(end, info), what, proceed, poplex); | |
435 }; | 468 }; |
436 } | 469 } |
| 470 function contCommasep(what, end, info) { |
| 471 for (var i = 3; i < arguments.length; i++) |
| 472 cx.cc.push(arguments[i]); |
| 473 return cont(pushlex(end, info), commasep(what, end), poplex); |
| 474 } |
437 function block(type) { | 475 function block(type) { |
438 if (type == "}") return cont(); | 476 if (type == "}") return cont(); |
439 return pass(statement, block); | 477 return pass(statement, block); |
440 } | 478 } |
441 function maybetype(type) { | 479 function maybetype(type) { |
442 if (isTS && type == ":") return cont(typedef); | 480 if (isTS && type == ":") return cont(typedef); |
443 } | 481 } |
444 function typedef(type) { | 482 function typedef(type) { |
445 if (type == "variable"){cx.marked = "variable-3"; return cont();} | 483 if (type == "variable"){cx.marked = "variable-3"; return cont();} |
446 } | 484 } |
447 function vardef() { | 485 function vardef() { |
448 return pass(pattern, maybetype, maybeAssign, vardefCont); | 486 return pass(pattern, maybetype, maybeAssign, vardefCont); |
449 } | 487 } |
450 function pattern(type, value) { | 488 function pattern(type, value) { |
451 if (type == "variable") { register(value); return cont(); } | 489 if (type == "variable") { register(value); return cont(); } |
452 if (type == "[") return cont(commasep(pattern, "]")); | 490 if (type == "[") return contCommasep(pattern, "]"); |
453 if (type == "{") return cont(commasep(proppattern, "}")); | 491 if (type == "{") return contCommasep(proppattern, "}"); |
454 } | 492 } |
455 function proppattern(type, value) { | 493 function proppattern(type, value) { |
456 if (type == "variable" && !cx.stream.match(/^\s*:/, false)) { | 494 if (type == "variable" && !cx.stream.match(/^\s*:/, false)) { |
457 register(value); | 495 register(value); |
458 return cont(maybeAssign); | 496 return cont(maybeAssign); |
459 } | 497 } |
460 if (type == "variable") cx.marked = "property"; | 498 if (type == "variable") cx.marked = "property"; |
461 return cont(expect(":"), pattern, maybeAssign); | 499 return cont(expect(":"), pattern, maybeAssign); |
462 } | 500 } |
463 function maybeAssign(_type, value) { | 501 function maybeAssign(_type, value) { |
464 if (value == "=") return cont(expressionNoComma); | 502 if (value == "=") return cont(expressionNoComma); |
465 } | 503 } |
466 function vardefCont(type) { | 504 function vardefCont(type) { |
467 if (type == ",") return cont(vardef); | 505 if (type == ",") return cont(vardef); |
468 } | 506 } |
469 function maybeelse(type, value) { | 507 function maybeelse(type, value) { |
470 if (type == "keyword b" && value == "else") return cont(pushlex("form"), sta
tement, poplex); | 508 if (type == "keyword b" && value == "else") return cont(pushlex("form", "els
e"), statement, poplex); |
471 } | 509 } |
472 function forspec(type) { | 510 function forspec(type) { |
473 if (type == "(") return cont(pushlex(")"), forspec1, expect(")")); | 511 if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex); |
474 } | 512 } |
475 function forspec1(type) { | 513 function forspec1(type) { |
476 if (type == "var") return cont(vardef, expect(";"), forspec2); | 514 if (type == "var") return cont(vardef, expect(";"), forspec2); |
477 if (type == ";") return cont(forspec2); | 515 if (type == ";") return cont(forspec2); |
478 if (type == "variable") return cont(formaybeinof); | 516 if (type == "variable") return cont(formaybeinof); |
479 return pass(expression, expect(";"), forspec2); | 517 return pass(expression, expect(";"), forspec2); |
480 } | 518 } |
481 function formaybeinof(_type, value) { | 519 function formaybeinof(_type, value) { |
482 if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(exp
ression); } | 520 if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(exp
ression); } |
483 return cont(maybeoperatorComma, forspec2); | 521 return cont(maybeoperatorComma, forspec2); |
484 } | 522 } |
485 function forspec2(type, value) { | 523 function forspec2(type, value) { |
486 if (type == ";") return cont(forspec3); | 524 if (type == ";") return cont(forspec3); |
487 if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(exp
ression); } | 525 if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(exp
ression); } |
488 return pass(expression, expect(";"), forspec3); | 526 return pass(expression, expect(";"), forspec3); |
489 } | 527 } |
490 function forspec3(type) { | 528 function forspec3(type) { |
491 if (type != ")") cont(expression); | 529 if (type != ")") cont(expression); |
492 } | 530 } |
493 function functiondef(type, value) { | 531 function functiondef(type, value) { |
494 if (value == "*") {cx.marked = "keyword"; return cont(functiondef);} | 532 if (value == "*") {cx.marked = "keyword"; return cont(functiondef);} |
495 if (type == "variable") {register(value); return cont(functiondef);} | 533 if (type == "variable") {register(value); return cont(functiondef);} |
496 if (type == "(") return cont(pushcontext, commasep(funarg, ")"), statement,
popcontext); | 534 if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"
), poplex, statement, popcontext); |
497 } | 535 } |
498 function funarg(type) { | 536 function funarg(type) { |
499 if (type == "spread") return cont(funarg); | 537 if (type == "spread") return cont(funarg); |
500 return pass(pattern, maybetype); | 538 return pass(pattern, maybetype); |
501 } | 539 } |
502 function className(type, value) { | 540 function className(type, value) { |
503 if (type == "variable") {register(value); return cont(classNameAfter);} | 541 if (type == "variable") {register(value); return cont(classNameAfter);} |
504 } | 542 } |
505 function classNameAfter(_type, value) { | 543 function classNameAfter(type, value) { |
506 if (value == "extends") return cont(expression); | 544 if (value == "extends") return cont(expression, classNameAfter); |
| 545 if (type == "{") return cont(pushlex("}"), classBody, poplex); |
507 } | 546 } |
508 function objlit(type) { | 547 function classBody(type, value) { |
509 if (type == "{") return cont(commasep(objprop, "}")); | 548 if (type == "variable" || cx.style == "keyword") { |
| 549 cx.marked = "property"; |
| 550 if (value == "get" || value == "set") return cont(classGetterSetter, funct
iondef, classBody); |
| 551 return cont(functiondef, classBody); |
| 552 } |
| 553 if (value == "*") { |
| 554 cx.marked = "keyword"; |
| 555 return cont(classBody); |
| 556 } |
| 557 if (type == ";") return cont(classBody); |
| 558 if (type == "}") return cont(); |
| 559 } |
| 560 function classGetterSetter(type) { |
| 561 if (type != "variable") return pass(); |
| 562 cx.marked = "property"; |
| 563 return cont(); |
510 } | 564 } |
511 function afterModule(type, value) { | 565 function afterModule(type, value) { |
512 if (type == "string") return cont(statement); | 566 if (type == "string") return cont(statement); |
513 if (type == "variable") { register(value); return cont(maybeFrom); } | 567 if (type == "variable") { register(value); return cont(maybeFrom); } |
514 } | 568 } |
515 function afterExport(_type, value) { | 569 function afterExport(_type, value) { |
516 if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";"
)); } | 570 if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";"
)); } |
517 if (value == "default") { cx.marked = "keyword"; return cont(expression, exp
ect(";")); } | 571 if (value == "default") { cx.marked = "keyword"; return cont(expression, exp
ect(";")); } |
518 return pass(statement); | 572 return pass(statement); |
519 } | 573 } |
520 function afterImport(type) { | 574 function afterImport(type) { |
521 if (type == "string") return cont(); | 575 if (type == "string") return cont(); |
522 return pass(importSpec, maybeFrom); | 576 return pass(importSpec, maybeFrom); |
523 } | 577 } |
524 function importSpec(type, value) { | 578 function importSpec(type, value) { |
525 if (type == "{") return cont(commasep(importSpec, "}")); | 579 if (type == "{") return contCommasep(importSpec, "}"); |
526 if (type == "variable") register(value); | 580 if (type == "variable") register(value); |
527 return cont(); | 581 return cont(); |
528 } | 582 } |
529 function maybeFrom(_type, value) { | 583 function maybeFrom(_type, value) { |
530 if (value == "from") { cx.marked = "keyword"; return cont(expression); } | 584 if (value == "from") { cx.marked = "keyword"; return cont(expression); } |
531 } | 585 } |
| 586 function arrayLiteral(type) { |
| 587 if (type == "]") return cont(); |
| 588 return pass(expressionNoComma, maybeArrayComprehension); |
| 589 } |
532 function maybeArrayComprehension(type) { | 590 function maybeArrayComprehension(type) { |
533 if (type == "for") return pass(comprehension); | 591 if (type == "for") return pass(comprehension, expect("]")); |
534 if (type == ",") return cont(commasep(expressionNoComma, "]", false)); | 592 if (type == ",") return cont(commasep(expressionNoComma, "]")); |
535 return pass(commasep(expressionNoComma, "]", false)); | 593 return pass(commasep(expressionNoComma, "]")); |
536 } | 594 } |
537 function comprehension(type) { | 595 function comprehension(type) { |
538 if (type == "for") return cont(forspec, comprehension); | 596 if (type == "for") return cont(forspec, comprehension); |
539 if (type == "if") return cont(expression, comprehension); | 597 if (type == "if") return cont(expression, comprehension); |
540 } | 598 } |
541 | 599 |
542 // Interface | 600 // Interface |
543 | 601 |
544 return { | 602 return { |
545 startState: function(basecolumn) { | 603 startState: function(basecolumn) { |
546 var state = { | 604 var state = { |
547 tokenize: tokenBase, | 605 tokenize: tokenBase, |
548 lastType: "sof", | 606 lastType: "sof", |
549 cc: [], | 607 cc: [], |
550 lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false
), | 608 lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false
), |
551 localVars: parserConfig.localVars, | 609 localVars: parserConfig.localVars, |
552 context: parserConfig.localVars && {vars: parserConfig.localVars}, | 610 context: parserConfig.localVars && {vars: parserConfig.localVars}, |
553 indented: 0 | 611 indented: 0 |
554 }; | 612 }; |
555 if (parserConfig.globalVars) state.globalVars = parserConfig.globalVars; | 613 if (parserConfig.globalVars && typeof parserConfig.globalVars == "object") |
| 614 state.globalVars = parserConfig.globalVars; |
556 return state; | 615 return state; |
557 }, | 616 }, |
558 | 617 |
559 token: function(stream, state) { | 618 token: function(stream, state) { |
560 if (stream.sol()) { | 619 if (stream.sol()) { |
561 if (!state.lexical.hasOwnProperty("align")) | 620 if (!state.lexical.hasOwnProperty("align")) |
562 state.lexical.align = false; | 621 state.lexical.align = false; |
563 state.indented = stream.indentation(); | 622 state.indented = stream.indentation(); |
564 findFatArrow(stream, state); | 623 findFatArrow(stream, state); |
565 } | 624 } |
566 if (state.tokenize != tokenComment && stream.eatSpace()) return null; | 625 if (state.tokenize != tokenComment && stream.eatSpace()) return null; |
567 var style = state.tokenize(stream, state); | 626 var style = state.tokenize(stream, state); |
568 if (type == "comment") return style; | 627 if (type == "comment") return style; |
569 state.lastType = type == "operator" && (content == "++" || content == "--"
) ? "incdec" : type; | 628 state.lastType = type == "operator" && (content == "++" || content == "--"
) ? "incdec" : type; |
570 return parseJS(state, style, type, content, stream); | 629 return parseJS(state, style, type, content, stream); |
571 }, | 630 }, |
572 | 631 |
573 indent: function(state, textAfter) { | 632 indent: function(state, textAfter) { |
574 if (state.tokenize == tokenComment) return CodeMirror.Pass; | 633 if (state.tokenize == tokenComment) return CodeMirror.Pass; |
575 if (state.tokenize != tokenBase) return 0; | 634 if (state.tokenize != tokenBase) return 0; |
576 var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical; | 635 var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical; |
577 // Kludge to prevent 'maybelse' from blocking lexical scope pops | 636 // Kludge to prevent 'maybelse' from blocking lexical scope pops |
578 for (var i = state.cc.length - 1; i >= 0; --i) { | 637 if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >=
0; --i) { |
579 var c = state.cc[i]; | 638 var c = state.cc[i]; |
580 if (c == poplex) lexical = lexical.prev; | 639 if (c == poplex) lexical = lexical.prev; |
581 else if (c != maybeelse) break; | 640 else if (c != maybeelse) break; |
582 } | 641 } |
583 if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev; | 642 if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev; |
584 if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat") | 643 if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat") |
585 lexical = lexical.prev; | 644 lexical = lexical.prev; |
586 var type = lexical.type, closing = firstChar == type; | 645 var type = lexical.type, closing = firstChar == type; |
587 | 646 |
588 if (type == "vardef") return lexical.indented + (state.lastType == "operat
or" || state.lastType == "," ? lexical.info + 1 : 0); | 647 if (type == "vardef") return lexical.indented + (state.lastType == "operat
or" || state.lastType == "," ? lexical.info + 1 : 0); |
589 else if (type == "form" && firstChar == "{") return lexical.indented; | 648 else if (type == "form" && firstChar == "{") return lexical.indented; |
590 else if (type == "form") return lexical.indented + indentUnit; | 649 else if (type == "form") return lexical.indented + indentUnit; |
591 else if (type == "stat") | 650 else if (type == "stat") |
592 return lexical.indented + (state.lastType == "operator" || state.lastTyp
e == "," ? statementIndent || indentUnit : 0); | 651 return lexical.indented + (state.lastType == "operator" || state.lastTyp
e == "," ? statementIndent || indentUnit : 0); |
593 else if (lexical.info == "switch" && !closing && parserConfig.doubleIndent
Switch != false) | 652 else if (lexical.info == "switch" && !closing && parserConfig.doubleIndent
Switch != false) |
594 return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? inden
tUnit : 2 * indentUnit); | 653 return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? inden
tUnit : 2 * indentUnit); |
595 else if (lexical.align) return lexical.column + (closing ? 0 : 1); | 654 else if (lexical.align) return lexical.column + (closing ? 0 : 1); |
596 else return lexical.indented + (closing ? 0 : indentUnit); | 655 else return lexical.indented + (closing ? 0 : indentUnit); |
597 }, | 656 }, |
598 | 657 |
599 electricChars: ":{}", | 658 electricChars: ":{}", |
600 blockCommentStart: jsonMode ? null : "/*", | 659 blockCommentStart: jsonMode ? null : "/*", |
601 blockCommentEnd: jsonMode ? null : "*/", | 660 blockCommentEnd: jsonMode ? null : "*/", |
602 lineComment: jsonMode ? null : "//", | 661 lineComment: jsonMode ? null : "//", |
603 fold: "brace", | 662 fold: "brace", |
604 | 663 |
605 helperType: jsonMode ? "json" : "javascript", | 664 helperType: jsonMode ? "json" : "javascript", |
| 665 jsonldMode: jsonldMode, |
606 jsonMode: jsonMode | 666 jsonMode: jsonMode |
607 }; | 667 }; |
608 }); | 668 }); |
609 | 669 |
| 670 CodeMirror.registerHelper("wordChars", "javascript", /[\\w$]/); |
| 671 |
610 CodeMirror.defineMIME("text/javascript", "javascript"); | 672 CodeMirror.defineMIME("text/javascript", "javascript"); |
611 CodeMirror.defineMIME("text/ecmascript", "javascript"); | 673 CodeMirror.defineMIME("text/ecmascript", "javascript"); |
612 CodeMirror.defineMIME("application/javascript", "javascript"); | 674 CodeMirror.defineMIME("application/javascript", "javascript"); |
| 675 CodeMirror.defineMIME("application/x-javascript", "javascript"); |
613 CodeMirror.defineMIME("application/ecmascript", "javascript"); | 676 CodeMirror.defineMIME("application/ecmascript", "javascript"); |
614 CodeMirror.defineMIME("application/json", {name: "javascript", json: true}); | 677 CodeMirror.defineMIME("application/json", {name: "javascript", json: true}); |
615 CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true}); | 678 CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true}); |
| 679 CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true})
; |
616 CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true
}); | 680 CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true
}); |
617 CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript
: true }); | 681 CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript
: true }); |
| 682 |
| 683 }); |
OLD | NEW |