all repos — NoPaste @ 29b774f090102303e43cf939b38ac2083e62d9f1

Resurrected - The PussTheCat.org fork of NoPaste

scripts/CodeMirror/mode/haxe/haxe.js (view raw)

  1// CodeMirror, copyright (c) by Marijn Haverbeke and others
  2// Distributed under an MIT license: https://codemirror.net/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
 14CodeMirror.defineMode("haxe", function(config, parserConfig) {
 15  var indentUnit = config.indentUnit;
 16
 17  // Tokenizer
 18
 19  function kw(type) {return {type: type, style: "keyword"};}
 20  var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
 21  var operator = kw("operator"), atom = {type: "atom", style: "atom"}, attribute = {type:"attribute", style: "attribute"};
 22  var type = kw("typedef");
 23  var keywords = {
 24    "if": A, "while": A, "else": B, "do": B, "try": B,
 25    "return": C, "break": C, "continue": C, "new": C, "throw": C,
 26    "var": kw("var"), "inline":attribute, "static": attribute, "using":kw("import"),
 27    "public": attribute, "private": attribute, "cast": kw("cast"), "import": kw("import"), "macro": kw("macro"),
 28    "function": kw("function"), "catch": kw("catch"), "untyped": kw("untyped"), "callback": kw("cb"),
 29    "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
 30    "in": operator, "never": kw("property_access"), "trace":kw("trace"),
 31    "class": type, "abstract":type, "enum":type, "interface":type, "typedef":type, "extends":type, "implements":type, "dynamic":type,
 32    "true": atom, "false": atom, "null": atom
 33  };
 34
 35  var isOperatorChar = /[+\-*&%=<>!?|]/;
 36
 37  function chain(stream, state, f) {
 38    state.tokenize = f;
 39    return f(stream, state);
 40  }
 41
 42  function toUnescaped(stream, end) {
 43    var escaped = false, next;
 44    while ((next = stream.next()) != null) {
 45      if (next == end && !escaped)
 46        return true;
 47      escaped = !escaped && next == "\\";
 48    }
 49  }
 50
 51  // Used as scratch variables to communicate multiple values without
 52  // consing up tons of objects.
 53  var type, content;
 54  function ret(tp, style, cont) {
 55    type = tp; content = cont;
 56    return style;
 57  }
 58
 59  function haxeTokenBase(stream, state) {
 60    var ch = stream.next();
 61    if (ch == '"' || ch == "'") {
 62      return chain(stream, state, haxeTokenString(ch));
 63    } else if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
 64      return ret(ch);
 65    } else if (ch == "0" && stream.eat(/x/i)) {
 66      stream.eatWhile(/[\da-f]/i);
 67      return ret("number", "number");
 68    } else if (/\d/.test(ch) || ch == "-" && stream.eat(/\d/)) {
 69      stream.match(/^\d*(?:\.\d*(?!\.))?(?:[eE][+\-]?\d+)?/);
 70      return ret("number", "number");
 71    } else if (state.reAllowed && (ch == "~" && stream.eat(/\//))) {
 72      toUnescaped(stream, "/");
 73      stream.eatWhile(/[gimsu]/);
 74      return ret("regexp", "string-2");
 75    } else if (ch == "/") {
 76      if (stream.eat("*")) {
 77        return chain(stream, state, haxeTokenComment);
 78      } else if (stream.eat("/")) {
 79        stream.skipToEnd();
 80        return ret("comment", "comment");
 81      } else {
 82        stream.eatWhile(isOperatorChar);
 83        return ret("operator", null, stream.current());
 84      }
 85    } else if (ch == "#") {
 86        stream.skipToEnd();
 87        return ret("conditional", "meta");
 88    } else if (ch == "@") {
 89      stream.eat(/:/);
 90      stream.eatWhile(/[\w_]/);
 91      return ret ("metadata", "meta");
 92    } else if (isOperatorChar.test(ch)) {
 93      stream.eatWhile(isOperatorChar);
 94      return ret("operator", null, stream.current());
 95    } else {
 96      var word;
 97      if(/[A-Z]/.test(ch)) {
 98        stream.eatWhile(/[\w_<>]/);
 99        word = stream.current();
100        return ret("type", "variable-3", word);
101      } else {
102        stream.eatWhile(/[\w_]/);
103        var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
104        return (known && state.kwAllowed) ? ret(known.type, known.style, word) :
105                       ret("variable", "variable", word);
106      }
107    }
108  }
109
110  function haxeTokenString(quote) {
111    return function(stream, state) {
112      if (toUnescaped(stream, quote))
113        state.tokenize = haxeTokenBase;
114      return ret("string", "string");
115    };
116  }
117
118  function haxeTokenComment(stream, state) {
119    var maybeEnd = false, ch;
120    while (ch = stream.next()) {
121      if (ch == "/" && maybeEnd) {
122        state.tokenize = haxeTokenBase;
123        break;
124      }
125      maybeEnd = (ch == "*");
126    }
127    return ret("comment", "comment");
128  }
129
130  // Parser
131
132  var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true};
133
134  function HaxeLexical(indented, column, type, align, prev, info) {
135    this.indented = indented;
136    this.column = column;
137    this.type = type;
138    this.prev = prev;
139    this.info = info;
140    if (align != null) this.align = align;
141  }
142
143  function inScope(state, varname) {
144    for (var v = state.localVars; v; v = v.next)
145      if (v.name == varname) return true;
146  }
147
148  function parseHaxe(state, style, type, content, stream) {
149    var cc = state.cc;
150    // Communicate our context to the combinators.
151    // (Less wasteful than consing up a hundred closures on every call.)
152    cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc;
153
154    if (!state.lexical.hasOwnProperty("align"))
155      state.lexical.align = true;
156
157    while(true) {
158      var combinator = cc.length ? cc.pop() : statement;
159      if (combinator(type, content)) {
160        while(cc.length && cc[cc.length - 1].lex)
161          cc.pop()();
162        if (cx.marked) return cx.marked;
163        if (type == "variable" && inScope(state, content)) return "variable-2";
164        if (type == "variable" && imported(state, content)) return "variable-3";
165        return style;
166      }
167    }
168  }
169
170  function imported(state, typename) {
171    if (/[a-z]/.test(typename.charAt(0)))
172      return false;
173    var len = state.importedtypes.length;
174    for (var i = 0; i<len; i++)
175      if(state.importedtypes[i]==typename) return true;
176  }
177
178  function registerimport(importname) {
179    var state = cx.state;
180    for (var t = state.importedtypes; t; t = t.next)
181      if(t.name == importname) return;
182    state.importedtypes = { name: importname, next: state.importedtypes };
183  }
184  // Combinator utils
185
186  var cx = {state: null, column: null, marked: null, cc: null};
187  function pass() {
188    for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
189  }
190  function cont() {
191    pass.apply(null, arguments);
192    return true;
193  }
194  function inList(name, list) {
195    for (var v = list; v; v = v.next)
196      if (v.name == name) return true;
197    return false;
198  }
199  function register(varname) {
200    var state = cx.state;
201    if (state.context) {
202      cx.marked = "def";
203      if (inList(varname, state.localVars)) return;
204      state.localVars = {name: varname, next: state.localVars};
205    } else if (state.globalVars) {
206      if (inList(varname, state.globalVars)) return;
207      state.globalVars = {name: varname, next: state.globalVars};
208    }
209  }
210
211  // Combinators
212
213  var defaultVars = {name: "this", next: null};
214  function pushcontext() {
215    if (!cx.state.context) cx.state.localVars = defaultVars;
216    cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
217  }
218  function popcontext() {
219    cx.state.localVars = cx.state.context.vars;
220    cx.state.context = cx.state.context.prev;
221  }
222  popcontext.lex = true;
223  function pushlex(type, info) {
224    var result = function() {
225      var state = cx.state;
226      state.lexical = new HaxeLexical(state.indented, cx.stream.column(), type, null, state.lexical, info);
227    };
228    result.lex = true;
229    return result;
230  }
231  function poplex() {
232    var state = cx.state;
233    if (state.lexical.prev) {
234      if (state.lexical.type == ")")
235        state.indented = state.lexical.indented;
236      state.lexical = state.lexical.prev;
237    }
238  }
239  poplex.lex = true;
240
241  function expect(wanted) {
242    function f(type) {
243      if (type == wanted) return cont();
244      else if (wanted == ";") return pass();
245      else return cont(f);
246    }
247    return f;
248  }
249
250  function statement(type) {
251    if (type == "@") return cont(metadef);
252    if (type == "var") return cont(pushlex("vardef"), vardef1, expect(";"), poplex);
253    if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex);
254    if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
255    if (type == "{") return cont(pushlex("}"), pushcontext, block, poplex, popcontext);
256    if (type == ";") return cont();
257    if (type == "attribute") return cont(maybeattribute);
258    if (type == "function") return cont(functiondef);
259    if (type == "for") return cont(pushlex("form"), expect("("), pushlex(")"), forspec1, expect(")"),
260                                   poplex, statement, poplex);
261    if (type == "variable") return cont(pushlex("stat"), maybelabel);
262    if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"),
263                                      block, poplex, poplex);
264    if (type == "case") return cont(expression, expect(":"));
265    if (type == "default") return cont(expect(":"));
266    if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
267                                     statement, poplex, popcontext);
268    if (type == "import") return cont(importdef, expect(";"));
269    if (type == "typedef") return cont(typedef);
270    return pass(pushlex("stat"), expression, expect(";"), poplex);
271  }
272  function expression(type) {
273    if (atomicTypes.hasOwnProperty(type)) return cont(maybeoperator);
274    if (type == "type" ) return cont(maybeoperator);
275    if (type == "function") return cont(functiondef);
276    if (type == "keyword c") return cont(maybeexpression);
277    if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeoperator);
278    if (type == "operator") return cont(expression);
279    if (type == "[") return cont(pushlex("]"), commasep(maybeexpression, "]"), poplex, maybeoperator);
280    if (type == "{") return cont(pushlex("}"), commasep(objprop, "}"), poplex, maybeoperator);
281    return cont();
282  }
283  function maybeexpression(type) {
284    if (type.match(/[;\}\)\],]/)) return pass();
285    return pass(expression);
286  }
287
288  function maybeoperator(type, value) {
289    if (type == "operator" && /\+\+|--/.test(value)) return cont(maybeoperator);
290    if (type == "operator" || type == ":") return cont(expression);
291    if (type == ";") return;
292    if (type == "(") return cont(pushlex(")"), commasep(expression, ")"), poplex, maybeoperator);
293    if (type == ".") return cont(property, maybeoperator);
294    if (type == "[") return cont(pushlex("]"), expression, expect("]"), poplex, maybeoperator);
295  }
296
297  function maybeattribute(type) {
298    if (type == "attribute") return cont(maybeattribute);
299    if (type == "function") return cont(functiondef);
300    if (type == "var") return cont(vardef1);
301  }
302
303  function metadef(type) {
304    if(type == ":") return cont(metadef);
305    if(type == "variable") return cont(metadef);
306    if(type == "(") return cont(pushlex(")"), commasep(metaargs, ")"), poplex, statement);
307  }
308  function metaargs(type) {
309    if(type == "variable") return cont();
310  }
311
312  function importdef (type, value) {
313    if(type == "variable" && /[A-Z]/.test(value.charAt(0))) { registerimport(value); return cont(); }
314    else if(type == "variable" || type == "property" || type == "." || value == "*") return cont(importdef);
315  }
316
317  function typedef (type, value)
318  {
319    if(type == "variable" && /[A-Z]/.test(value.charAt(0))) { registerimport(value); return cont(); }
320    else if (type == "type" && /[A-Z]/.test(value.charAt(0))) { return cont(); }
321  }
322
323  function maybelabel(type) {
324    if (type == ":") return cont(poplex, statement);
325    return pass(maybeoperator, expect(";"), poplex);
326  }
327  function property(type) {
328    if (type == "variable") {cx.marked = "property"; return cont();}
329  }
330  function objprop(type) {
331    if (type == "variable") cx.marked = "property";
332    if (atomicTypes.hasOwnProperty(type)) return cont(expect(":"), expression);
333  }
334  function commasep(what, end) {
335    function proceed(type) {
336      if (type == ",") return cont(what, proceed);
337      if (type == end) return cont();
338      return cont(expect(end));
339    }
340    return function(type) {
341      if (type == end) return cont();
342      else return pass(what, proceed);
343    };
344  }
345  function block(type) {
346    if (type == "}") return cont();
347    return pass(statement, block);
348  }
349  function vardef1(type, value) {
350    if (type == "variable"){register(value); return cont(typeuse, vardef2);}
351    return cont();
352  }
353  function vardef2(type, value) {
354    if (value == "=") return cont(expression, vardef2);
355    if (type == ",") return cont(vardef1);
356  }
357  function forspec1(type, value) {
358    if (type == "variable") {
359      register(value);
360      return cont(forin, expression)
361    } else {
362      return pass()
363    }
364  }
365  function forin(_type, value) {
366    if (value == "in") return cont();
367  }
368  function functiondef(type, value) {
369    //function names starting with upper-case letters are recognised as types, so cludging them together here.
370    if (type == "variable" || type == "type") {register(value); return cont(functiondef);}
371    if (value == "new") return cont(functiondef);
372    if (type == "(") return cont(pushlex(")"), pushcontext, commasep(funarg, ")"), poplex, typeuse, statement, popcontext);
373  }
374  function typeuse(type) {
375    if(type == ":") return cont(typestring);
376  }
377  function typestring(type) {
378    if(type == "type") return cont();
379    if(type == "variable") return cont();
380    if(type == "{") return cont(pushlex("}"), commasep(typeprop, "}"), poplex);
381  }
382  function typeprop(type) {
383    if(type == "variable") return cont(typeuse);
384  }
385  function funarg(type, value) {
386    if (type == "variable") {register(value); return cont(typeuse);}
387  }
388
389  // Interface
390  return {
391    startState: function(basecolumn) {
392      var defaulttypes = ["Int", "Float", "String", "Void", "Std", "Bool", "Dynamic", "Array"];
393      var state = {
394        tokenize: haxeTokenBase,
395        reAllowed: true,
396        kwAllowed: true,
397        cc: [],
398        lexical: new HaxeLexical((basecolumn || 0) - indentUnit, 0, "block", false),
399        localVars: parserConfig.localVars,
400        importedtypes: defaulttypes,
401        context: parserConfig.localVars && {vars: parserConfig.localVars},
402        indented: 0
403      };
404      if (parserConfig.globalVars && typeof parserConfig.globalVars == "object")
405        state.globalVars = parserConfig.globalVars;
406      return state;
407    },
408
409    token: function(stream, state) {
410      if (stream.sol()) {
411        if (!state.lexical.hasOwnProperty("align"))
412          state.lexical.align = false;
413        state.indented = stream.indentation();
414      }
415      if (stream.eatSpace()) return null;
416      var style = state.tokenize(stream, state);
417      if (type == "comment") return style;
418      state.reAllowed = !!(type == "operator" || type == "keyword c" || type.match(/^[\[{}\(,;:]$/));
419      state.kwAllowed = type != '.';
420      return parseHaxe(state, style, type, content, stream);
421    },
422
423    indent: function(state, textAfter) {
424      if (state.tokenize != haxeTokenBase) return 0;
425      var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical;
426      if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev;
427      var type = lexical.type, closing = firstChar == type;
428      if (type == "vardef") return lexical.indented + 4;
429      else if (type == "form" && firstChar == "{") return lexical.indented;
430      else if (type == "stat" || type == "form") return lexical.indented + indentUnit;
431      else if (lexical.info == "switch" && !closing)
432        return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
433      else if (lexical.align) return lexical.column + (closing ? 0 : 1);
434      else return lexical.indented + (closing ? 0 : indentUnit);
435    },
436
437    electricChars: "{}",
438    blockCommentStart: "/*",
439    blockCommentEnd: "*/",
440    lineComment: "//"
441  };
442});
443
444CodeMirror.defineMIME("text/x-haxe", "haxe");
445
446CodeMirror.defineMode("hxml", function () {
447
448  return {
449    startState: function () {
450      return {
451        define: false,
452        inString: false
453      };
454    },
455    token: function (stream, state) {
456      var ch = stream.peek();
457      var sol = stream.sol();
458
459      ///* comments */
460      if (ch == "#") {
461        stream.skipToEnd();
462        return "comment";
463      }
464      if (sol && ch == "-") {
465        var style = "variable-2";
466
467        stream.eat(/-/);
468
469        if (stream.peek() == "-") {
470          stream.eat(/-/);
471          style = "keyword a";
472        }
473
474        if (stream.peek() == "D") {
475          stream.eat(/[D]/);
476          style = "keyword c";
477          state.define = true;
478        }
479
480        stream.eatWhile(/[A-Z]/i);
481        return style;
482      }
483
484      var ch = stream.peek();
485
486      if (state.inString == false && ch == "'") {
487        state.inString = true;
488        stream.next();
489      }
490
491      if (state.inString == true) {
492        if (stream.skipTo("'")) {
493
494        } else {
495          stream.skipToEnd();
496        }
497
498        if (stream.peek() == "'") {
499          stream.next();
500          state.inString = false;
501        }
502
503        return "string";
504      }
505
506      stream.next();
507      return null;
508    },
509    lineComment: "#"
510  };
511});
512
513CodeMirror.defineMIME("text/x-hxml", "hxml");
514
515});