0
|
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|
2 // Distributed under an MIT license: https://codemirror.net/5/LICENSE
|
|
3
|
|
4 (function(mod) {
|
|
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|
6 mod(require("../../lib/codemirror"));
|
|
7 else if (typeof define == "function" && define.amd) // AMD
|
|
8 define(["../../lib/codemirror"], mod);
|
|
9 else // Plain browser env
|
|
10 mod(CodeMirror);
|
|
11 })(function(CodeMirror) {
|
|
12 "use strict";
|
|
13
|
|
14 CodeMirror.defineMode("julia", function(config, parserConf) {
|
|
15 function wordRegexp(words, end, pre) {
|
|
16 if (typeof pre === "undefined") { pre = ""; }
|
|
17 if (typeof end === "undefined") { end = "\\b"; }
|
|
18 return new RegExp("^" + pre + "((" + words.join(")|(") + "))" + end);
|
|
19 }
|
|
20
|
|
21 var octChar = "\\\\[0-7]{1,3}";
|
|
22 var hexChar = "\\\\x[A-Fa-f0-9]{1,2}";
|
|
23 var sChar = "\\\\[abefnrtv0%?'\"\\\\]";
|
|
24 var uChar = "([^\\u0027\\u005C\\uD800-\\uDFFF]|[\\uD800-\\uDFFF][\\uDC00-\\uDFFF])";
|
|
25
|
|
26 var asciiOperatorsList = [
|
|
27 "[<>]:", "[<>=]=", "<<=?", ">>>?=?", "=>", "--?>", "<--[->]?", "\\/\\/",
|
|
28 "\\.{2,3}", "[\\.\\\\%*+\\-<>!\\/^|&]=?", "\\?", "\\$", "~", ":"
|
|
29 ];
|
|
30 var operators = parserConf.operators || wordRegexp([
|
|
31 "[<>]:", "[<>=]=", "[!=]==", "<<=?", ">>>?=?", "=>?", "--?>", "<--[->]?", "\\/\\/",
|
|
32 "[\\\\%*+\\-<>!\\/^|&\\u00F7\\u22BB]=?", "\\?", "\\$", "~", ":",
|
|
33 "\\u00D7", "\\u2208", "\\u2209", "\\u220B", "\\u220C", "\\u2218",
|
|
34 "\\u221A", "\\u221B", "\\u2229", "\\u222A", "\\u2260", "\\u2264",
|
|
35 "\\u2265", "\\u2286", "\\u2288", "\\u228A", "\\u22C5",
|
|
36 "\\b(in|isa)\\b(?!\.?\\()"
|
|
37 ], "");
|
|
38 var delimiters = parserConf.delimiters || /^[;,()[\]{}]/;
|
|
39 var identifiers = parserConf.identifiers ||
|
|
40 /^[_A-Za-z\u00A1-\u2217\u2219-\uFFFF][\w\u00A1-\u2217\u2219-\uFFFF]*!*/;
|
|
41
|
|
42 var chars = wordRegexp([octChar, hexChar, sChar, uChar], "'");
|
|
43
|
|
44 var openersList = ["begin", "function", "type", "struct", "immutable", "let",
|
|
45 "macro", "for", "while", "quote", "if", "else", "elseif", "try",
|
|
46 "finally", "catch", "do"];
|
|
47
|
|
48 var closersList = ["end", "else", "elseif", "catch", "finally"];
|
|
49
|
|
50 var keywordsList = ["if", "else", "elseif", "while", "for", "begin", "let",
|
|
51 "end", "do", "try", "catch", "finally", "return", "break", "continue",
|
|
52 "global", "local", "const", "export", "import", "importall", "using",
|
|
53 "function", "where", "macro", "module", "baremodule", "struct", "type",
|
|
54 "mutable", "immutable", "quote", "typealias", "abstract", "primitive",
|
|
55 "bitstype"];
|
|
56
|
|
57 var builtinsList = ["true", "false", "nothing", "NaN", "Inf"];
|
|
58
|
|
59 CodeMirror.registerHelper("hintWords", "julia", keywordsList.concat(builtinsList));
|
|
60
|
|
61 var openers = wordRegexp(openersList);
|
|
62 var closers = wordRegexp(closersList);
|
|
63 var keywords = wordRegexp(keywordsList);
|
|
64 var builtins = wordRegexp(builtinsList);
|
|
65
|
|
66 var macro = /^@[_A-Za-z\u00A1-\uFFFF][\w\u00A1-\uFFFF]*!*/;
|
|
67 var symbol = /^:[_A-Za-z\u00A1-\uFFFF][\w\u00A1-\uFFFF]*!*/;
|
|
68 var stringPrefixes = /^(`|([_A-Za-z\u00A1-\uFFFF]*"("")?))/;
|
|
69
|
|
70 var macroOperators = wordRegexp(asciiOperatorsList, "", "@");
|
|
71 var symbolOperators = wordRegexp(asciiOperatorsList, "", ":");
|
|
72
|
|
73 function inArray(state) {
|
|
74 return (state.nestedArrays > 0);
|
|
75 }
|
|
76
|
|
77 function inGenerator(state) {
|
|
78 return (state.nestedGenerators > 0);
|
|
79 }
|
|
80
|
|
81 function currentScope(state, n) {
|
|
82 if (typeof(n) === "undefined") { n = 0; }
|
|
83 if (state.scopes.length <= n) {
|
|
84 return null;
|
|
85 }
|
|
86 return state.scopes[state.scopes.length - (n + 1)];
|
|
87 }
|
|
88
|
|
89 // tokenizers
|
|
90 function tokenBase(stream, state) {
|
|
91 // Handle multiline comments
|
|
92 if (stream.match('#=', false)) {
|
|
93 state.tokenize = tokenComment;
|
|
94 return state.tokenize(stream, state);
|
|
95 }
|
|
96
|
|
97 // Handle scope changes
|
|
98 var leavingExpr = state.leavingExpr;
|
|
99 if (stream.sol()) {
|
|
100 leavingExpr = false;
|
|
101 }
|
|
102 state.leavingExpr = false;
|
|
103
|
|
104 if (leavingExpr) {
|
|
105 if (stream.match(/^'+/)) {
|
|
106 return "operator";
|
|
107 }
|
|
108 }
|
|
109
|
|
110 if (stream.match(/\.{4,}/)) {
|
|
111 return "error";
|
|
112 } else if (stream.match(/\.{1,3}/)) {
|
|
113 return "operator";
|
|
114 }
|
|
115
|
|
116 if (stream.eatSpace()) {
|
|
117 return null;
|
|
118 }
|
|
119
|
|
120 var ch = stream.peek();
|
|
121
|
|
122 // Handle single line comments
|
|
123 if (ch === '#') {
|
|
124 stream.skipToEnd();
|
|
125 return "comment";
|
|
126 }
|
|
127
|
|
128 if (ch === '[') {
|
|
129 state.scopes.push('[');
|
|
130 state.nestedArrays++;
|
|
131 }
|
|
132
|
|
133 if (ch === '(') {
|
|
134 state.scopes.push('(');
|
|
135 state.nestedGenerators++;
|
|
136 }
|
|
137
|
|
138 if (inArray(state) && ch === ']') {
|
|
139 while (state.scopes.length && currentScope(state) !== "[") { state.scopes.pop(); }
|
|
140 state.scopes.pop();
|
|
141 state.nestedArrays--;
|
|
142 state.leavingExpr = true;
|
|
143 }
|
|
144
|
|
145 if (inGenerator(state) && ch === ')') {
|
|
146 while (state.scopes.length && currentScope(state) !== "(") { state.scopes.pop(); }
|
|
147 state.scopes.pop();
|
|
148 state.nestedGenerators--;
|
|
149 state.leavingExpr = true;
|
|
150 }
|
|
151
|
|
152 if (inArray(state)) {
|
|
153 if (state.lastToken == "end" && stream.match(':')) {
|
|
154 return "operator";
|
|
155 }
|
|
156 if (stream.match('end')) {
|
|
157 return "number";
|
|
158 }
|
|
159 }
|
|
160
|
|
161 var match;
|
|
162 if (match = stream.match(openers, false)) {
|
|
163 state.scopes.push(match[0]);
|
|
164 }
|
|
165
|
|
166 if (stream.match(closers, false)) {
|
|
167 state.scopes.pop();
|
|
168 }
|
|
169
|
|
170 // Handle type annotations
|
|
171 if (stream.match(/^::(?![:\$])/)) {
|
|
172 state.tokenize = tokenAnnotation;
|
|
173 return state.tokenize(stream, state);
|
|
174 }
|
|
175
|
|
176 // Handle symbols
|
|
177 if (!leavingExpr && (stream.match(symbol) || stream.match(symbolOperators))) {
|
|
178 return "builtin";
|
|
179 }
|
|
180
|
|
181 // Handle parametric types
|
|
182 //if (stream.match(/^{[^}]*}(?=\()/)) {
|
|
183 // return "builtin";
|
|
184 //}
|
|
185
|
|
186 // Handle operators and Delimiters
|
|
187 if (stream.match(operators)) {
|
|
188 return "operator";
|
|
189 }
|
|
190
|
|
191 // Handle Number Literals
|
|
192 if (stream.match(/^\.?\d/, false)) {
|
|
193 var imMatcher = RegExp(/^im\b/);
|
|
194 var numberLiteral = false;
|
|
195 if (stream.match(/^0x\.[0-9a-f_]+p[\+\-]?[_\d]+/i)) { numberLiteral = true; }
|
|
196 // Integers
|
|
197 if (stream.match(/^0x[0-9a-f_]+/i)) { numberLiteral = true; } // Hex
|
|
198 if (stream.match(/^0b[01_]+/i)) { numberLiteral = true; } // Binary
|
|
199 if (stream.match(/^0o[0-7_]+/i)) { numberLiteral = true; } // Octal
|
|
200 // Floats
|
|
201 if (stream.match(/^(?:(?:\d[_\d]*)?\.(?!\.)(?:\d[_\d]*)?|\d[_\d]*\.(?!\.)(?:\d[_\d]*))?([Eef][\+\-]?[_\d]+)?/i)) { numberLiteral = true; }
|
|
202 if (stream.match(/^\d[_\d]*(e[\+\-]?\d+)?/i)) { numberLiteral = true; } // Decimal
|
|
203 if (numberLiteral) {
|
|
204 // Integer literals may be "long"
|
|
205 stream.match(imMatcher);
|
|
206 state.leavingExpr = true;
|
|
207 return "number";
|
|
208 }
|
|
209 }
|
|
210
|
|
211 // Handle Chars
|
|
212 if (stream.match('\'')) {
|
|
213 state.tokenize = tokenChar;
|
|
214 return state.tokenize(stream, state);
|
|
215 }
|
|
216
|
|
217 // Handle Strings
|
|
218 if (stream.match(stringPrefixes)) {
|
|
219 state.tokenize = tokenStringFactory(stream.current());
|
|
220 return state.tokenize(stream, state);
|
|
221 }
|
|
222
|
|
223 if (stream.match(macro) || stream.match(macroOperators)) {
|
|
224 return "meta";
|
|
225 }
|
|
226
|
|
227 if (stream.match(delimiters)) {
|
|
228 return null;
|
|
229 }
|
|
230
|
|
231 if (stream.match(keywords)) {
|
|
232 return "keyword";
|
|
233 }
|
|
234
|
|
235 if (stream.match(builtins)) {
|
|
236 return "builtin";
|
|
237 }
|
|
238
|
|
239 var isDefinition = state.isDefinition || state.lastToken == "function" ||
|
|
240 state.lastToken == "macro" || state.lastToken == "type" ||
|
|
241 state.lastToken == "struct" || state.lastToken == "immutable";
|
|
242
|
|
243 if (stream.match(identifiers)) {
|
|
244 if (isDefinition) {
|
|
245 if (stream.peek() === '.') {
|
|
246 state.isDefinition = true;
|
|
247 return "variable";
|
|
248 }
|
|
249 state.isDefinition = false;
|
|
250 return "def";
|
|
251 }
|
|
252 state.leavingExpr = true;
|
|
253 return "variable";
|
|
254 }
|
|
255
|
|
256 // Handle non-detected items
|
|
257 stream.next();
|
|
258 return "error";
|
|
259 }
|
|
260
|
|
261 function tokenAnnotation(stream, state) {
|
|
262 stream.match(/.*?(?=[,;{}()=\s]|$)/);
|
|
263 if (stream.match('{')) {
|
|
264 state.nestedParameters++;
|
|
265 } else if (stream.match('}') && state.nestedParameters > 0) {
|
|
266 state.nestedParameters--;
|
|
267 }
|
|
268 if (state.nestedParameters > 0) {
|
|
269 stream.match(/.*?(?={|})/) || stream.next();
|
|
270 } else if (state.nestedParameters == 0) {
|
|
271 state.tokenize = tokenBase;
|
|
272 }
|
|
273 return "builtin";
|
|
274 }
|
|
275
|
|
276 function tokenComment(stream, state) {
|
|
277 if (stream.match('#=')) {
|
|
278 state.nestedComments++;
|
|
279 }
|
|
280 if (!stream.match(/.*?(?=(#=|=#))/)) {
|
|
281 stream.skipToEnd();
|
|
282 }
|
|
283 if (stream.match('=#')) {
|
|
284 state.nestedComments--;
|
|
285 if (state.nestedComments == 0)
|
|
286 state.tokenize = tokenBase;
|
|
287 }
|
|
288 return "comment";
|
|
289 }
|
|
290
|
|
291 function tokenChar(stream, state) {
|
|
292 var isChar = false, match;
|
|
293 if (stream.match(chars)) {
|
|
294 isChar = true;
|
|
295 } else if (match = stream.match(/\\u([a-f0-9]{1,4})(?=')/i)) {
|
|
296 var value = parseInt(match[1], 16);
|
|
297 if (value <= 55295 || value >= 57344) { // (U+0,U+D7FF), (U+E000,U+FFFF)
|
|
298 isChar = true;
|
|
299 stream.next();
|
|
300 }
|
|
301 } else if (match = stream.match(/\\U([A-Fa-f0-9]{5,8})(?=')/)) {
|
|
302 var value = parseInt(match[1], 16);
|
|
303 if (value <= 1114111) { // U+10FFFF
|
|
304 isChar = true;
|
|
305 stream.next();
|
|
306 }
|
|
307 }
|
|
308 if (isChar) {
|
|
309 state.leavingExpr = true;
|
|
310 state.tokenize = tokenBase;
|
|
311 return "string";
|
|
312 }
|
|
313 if (!stream.match(/^[^']+(?=')/)) { stream.skipToEnd(); }
|
|
314 if (stream.match('\'')) { state.tokenize = tokenBase; }
|
|
315 return "error";
|
|
316 }
|
|
317
|
|
318 function tokenStringFactory(delimiter) {
|
|
319 if (delimiter.substr(-3) === '"""') {
|
|
320 delimiter = '"""';
|
|
321 } else if (delimiter.substr(-1) === '"') {
|
|
322 delimiter = '"';
|
|
323 }
|
|
324 function tokenString(stream, state) {
|
|
325 if (stream.eat('\\')) {
|
|
326 stream.next();
|
|
327 } else if (stream.match(delimiter)) {
|
|
328 state.tokenize = tokenBase;
|
|
329 state.leavingExpr = true;
|
|
330 return "string";
|
|
331 } else {
|
|
332 stream.eat(/[`"]/);
|
|
333 }
|
|
334 stream.eatWhile(/[^\\`"]/);
|
|
335 return "string";
|
|
336 }
|
|
337 return tokenString;
|
|
338 }
|
|
339
|
|
340 var external = {
|
|
341 startState: function() {
|
|
342 return {
|
|
343 tokenize: tokenBase,
|
|
344 scopes: [],
|
|
345 lastToken: null,
|
|
346 leavingExpr: false,
|
|
347 isDefinition: false,
|
|
348 nestedArrays: 0,
|
|
349 nestedComments: 0,
|
|
350 nestedGenerators: 0,
|
|
351 nestedParameters: 0,
|
|
352 firstParenPos: -1
|
|
353 };
|
|
354 },
|
|
355
|
|
356 token: function(stream, state) {
|
|
357 var style = state.tokenize(stream, state);
|
|
358 var current = stream.current();
|
|
359
|
|
360 if (current && style) {
|
|
361 state.lastToken = current;
|
|
362 }
|
|
363
|
|
364 return style;
|
|
365 },
|
|
366
|
|
367 indent: function(state, textAfter) {
|
|
368 var delta = 0;
|
|
369 if ( textAfter === ']' || textAfter === ')' || /^end\b/.test(textAfter) ||
|
|
370 /^else/.test(textAfter) || /^catch\b/.test(textAfter) || /^elseif\b/.test(textAfter) ||
|
|
371 /^finally/.test(textAfter) ) {
|
|
372 delta = -1;
|
|
373 }
|
|
374 return (state.scopes.length + delta) * config.indentUnit;
|
|
375 },
|
|
376
|
|
377 electricInput: /\b(end|else|catch|finally)\b/,
|
|
378 blockCommentStart: "#=",
|
|
379 blockCommentEnd: "=#",
|
|
380 lineComment: "#",
|
|
381 closeBrackets: "()[]{}\"\"",
|
|
382 fold: "indent"
|
|
383 };
|
|
384 return external;
|
|
385 });
|
|
386
|
|
387
|
|
388 CodeMirror.defineMIME("text/x-julia", "julia");
|
|
389
|
|
390 });
|