UNPKG

codemirror-mode-chapel

Version:
308 lines (281 loc) 11.4 kB
// CodeMirror, copyright (c) by Marijn Haverbeke and others // Distributed under an MIT license: https://codemirror.net/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../codemirror/lib/codemirror")); else if (typeof define == "function" && define.amd) // AMD define(["../codemirror/lib/codemirror"], mod); else // Plain browser env mod(CodeMirror); })(function(CodeMirror) { "use strict"; function Context(indented, column, type, info, align, prev) { this.indented = indented; this.column = column; this.type = type; this.info = info; this.align = align; this.prev = prev; } function pushContext(state, col, type, info) { var indent = state.indented; if (state.context && state.context.type == "statement" && type != "statement") indent = state.context.indented; return state.context = new Context(indent, col, type, info, null, state.context); } function popContext(state) { var t = state.context.type; if (t == ")" || t == "]" || t == "}") state.indented = state.context.indented; return state.context = state.context.prev; } function typeBefore(stream, state) { if (state.prevToken == "variable" || state.prevToken == "type") return true; if (state.typeAtEndOfLine && stream.column() == stream.indentation()) return true; } function isTopScope(context) { for (;;) { if (!context || context.type == "top") return true; if (context.type == "}") return false; context = context.prev; } } CodeMirror.defineMode("chapel", function(config, parserConfig) { var indentUnit = config.indentUnit, statementIndentUnit = parserConfig.statementIndentUnit || indentUnit, dontAlignCalls = parserConfig.dontAlignCalls, keywords = parserConfig.keywords || {}, types = parserConfig.types || {}, builtin = parserConfig.builtin || {}, blockKeywords = parserConfig.blockKeywords || {}, atoms = parserConfig.atoms || {}, multiLineStrings = parserConfig.multiLineStrings, indentStatements = parserConfig.indentStatements !== false, indentSwitch = parserConfig.indentSwitch !== false, isPunctuationChar = parserConfig.isPunctuationChar || /[\[\]{}\(\),;\:\.\?]/, numberStart = parserConfig.numberStart || /[\d\.]/, number = parserConfig.number || /^(?:0[xX][a-f\d]+|0[bB][01]+|0[oO][0-7]+|(?:\d+\.?\d*|\.\d+)(?:[eE][-+]?\d+)?((([+-](?:\d+\.?\d*|\.\d+)(?:[eE][-+]?\d+)?i)?|i?)?|i?))(u|ll?|l|f)?/i, isOperatorChar = parserConfig.isOperatorChar || /^(=|\+=|-=|\*=|\/=|\*\*=|%=|&=|\|=|\^=|&&=|\|\|=|<<=|>>=|<=>|<~>|\.\.|by|#|\.\.\.|&&|\|\||!|&|\||\^|~|<<|>>|==|!=|<=|>=|<|>|[+\-*/%]|\*\*)/, isIdentifierChar = parserConfig.isIdentifierChar || /[\w\$_\xa1-\uffff]/, // An optional function that takes a {string} token and returns true if it // should be treated as a builtin. isReservedIdentifier = parserConfig.isReservedIdentifier || false; var curPunc; function tokenBase(stream, state) { var ch = stream.next(); // Handle Strings if (ch == '"' || ch == "'") { state.tokenize = tokenString(ch); return state.tokenize(stream, state); } // Handle Punctuations if (isPunctuationChar.test(ch)) { curPunc = ch; return null; } // Handle Numbers if (numberStart.test(ch)) { stream.backUp(1) if (stream.match(number)) return "number" stream.next() } //Handle comments if (ch == "/") { if (stream.eat("*")) { state.tokenize = tokenNestedComment(1) return state.tokenize(stream, state) } if (stream.eat("/")) { stream.skipToEnd(); return "comment"; } } //Handle operators if (isOperatorChar.test(ch)) { while (!stream.match(/^\/[\/*]/, false) && stream.eat(isOperatorChar)) {} return "operator"; } stream.eatWhile(isIdentifierChar); var cur = stream.current(); if (contains(keywords, cur)) { if (contains(blockKeywords, cur)) curPunc = "newstatement"; return "keyword"; } if (contains(types, cur)) return "type"; if (contains(builtin, cur)|| (isReservedIdentifier && isReservedIdentifier(cur))) { if (contains(blockKeywords, cur)) curPunc = "newstatement"; return "builtin"; } if (contains(atoms, cur)) return "atom"; return "variable"; } function tokenString(quote) { return function(stream, state) { var escaped = false, next, end = false; while ((next = stream.next()) != null) { if (next == quote && !escaped) {end = true; break;} escaped = !escaped && next == "\\"; } if (end || !(escaped || multiLineStrings)) state.tokenize = null; return "string"; }; } function maybeEOL(stream, state) { if (parserConfig.typeFirstDefinitions && stream.eol() && isTopScope(state.context)) state.typeAtEndOfLine = typeBefore(stream, state) } // Interface return { startState: function(basecolumn) { return { tokenize: null, context: new Context((basecolumn || 0) - indentUnit, 0, "top", null, false), indented: 0, startOfLine: true, prevToken: null }; }, token: function(stream, state) { var ctx = state.context; // console.log("type:",ctx.type,"align",ctx.align,"indented",ctx.indented,"prev",ctx.prev); if (stream.sol()) { if (ctx.align == null) ctx.align = false; state.indented = stream.indentation(); state.startOfLine = true; } if (stream.eatSpace()) { maybeEOL(stream, state); return null; } curPunc = null; var style = (state.tokenize || tokenBase)(stream, state); if (style == "comment" || style == "meta") return style; if (ctx.align == null) ctx.align = true; if (curPunc == ";" || curPunc == ":" || (curPunc == "," && stream.match(/^\s*(?:\/\/.*)?$/, false))) while (state.context.type == "statement") popContext(state); else if (curPunc == "{") pushContext(state, stream.column(), "}"); else if (curPunc == "[") pushContext(state, stream.column(), "]"); else if (curPunc == "(") pushContext(state, stream.column(), ")"); else if (curPunc == "}") { while (ctx.type == "statement") ctx = popContext(state); if (ctx.type == "}") ctx = popContext(state); while (ctx.type == "statement") ctx = popContext(state); } else if (curPunc == ctx.type) popContext(state); else if (indentStatements && (((ctx.type == "}" || ctx.type == "top") && curPunc != ";") || (ctx.type == "statement" && curPunc == "newstatement"))) { pushContext(state, stream.column(), "statement", stream.current()); } state.startOfLine = false; state.prevToken = style || curPunc; maybeEOL(stream, state); return style; }, indent: function(state, textAfter) { if (state.tokenize != tokenBase && state.tokenize != null || state.typeAtEndOfLine) return CodeMirror.Pass; var ctx = state.context, firstChar = textAfter && textAfter.charAt(0); var closing = firstChar == ctx.type; if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev; if (parserConfig.dontIndentStatements) while (ctx.type == "statement" && parserConfig.dontIndentStatements.test(ctx.info)) ctx = ctx.prev var switchBlock = ctx.prev && ctx.prev.info == "select"; if (parserConfig.allmanIndentation && /[{(]/.test(firstChar)) { while (ctx.type != "top" && ctx.type != "}") ctx = ctx.prev return ctx.indented } if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit); if (ctx.align && (!dontAlignCalls || ctx.type != ")")) return ctx.column + (closing ? 0 : 1); if (ctx.type == ")" && !closing) return ctx.indented + statementIndentUnit; return ctx.indented + (closing ? 0 : indentUnit) + (!closing && switchBlock && !/^(?:when|otherwise)\b/.test(textAfter) ? indentUnit : 0); }, electricInput: indentSwitch ? /^\s*(?:when .*?:|otherwise:|\{\}?|\})$/ : /^\s*[{}]$/, blockCommentStart: "/*", blockCommentEnd: "*/", blockCommentContinue: " * ", lineComment: "//", fold: "brace" }; }); function words(str) { var obj = {}, words = str.split(" "); for (var i = 0; i < words.length; ++i) obj[words[i]] = true; return obj; } function contains(words, word) { if (typeof words === "function") { return words(word); } else { return words.propertyIsEnumerable(word); } } var chapelKeywords = "# align as atomic begin borrowed break by catch class cobegin "+ "coforall config const continue delete dmapped do domain else enum except export "+ "extern for forall if in index inline inout iter label lambda let local module new nil "+ "noinit on only otherwise out param private proc public record "+ "reduce ref require return scan select serial shared single sparse subdomain "+ "sync then try type union unmanaged use var when where while with write writeln "+ "yield zip "; // Do not use this. Use the ChapelTypes function below. This is global just to avoid // excessive calls when chapelTypes is being called multiple times during a parse. var basicChapelTypes = words("int uint bool real imag complex string void _void record domain"+ "subdomain sparse"); // Returns true if identifier is a "Chapel" type. // Chapel type is defined as those that are reserved by the compiler (basicTypes), function chapelTypes(identifier) { return contains(basicChapelTypes, identifier); } var chapelBlockKeywords = "catch class coforall do else for forall if otherwise select"+ "try when while"; var chapelDefKeywords = "begin class cobegin config const iter module new param type var where"; function tokenNestedComment(depth) { return function (stream, state) { var ch while (ch = stream.next()) { if (ch == "*" && stream.eat("/")) { if (depth == 1) { state.tokenize = null break } else { state.tokenize = tokenNestedComment(depth - 1) return state.tokenize(stream, state) } } else if (ch == "/" && stream.eat("*")) { state.tokenize = tokenNestedComment(depth + 1) return state.tokenize(stream, state) } } return "comment"; } } function def(mimes, mode) { if (typeof mimes == "string") mimes = [mimes]; var words = []; function add(obj) { if (obj) for (var prop in obj) if (obj.hasOwnProperty(prop)) words.push(prop); } add(mode.keywords); add(mode.types); add(mode.builtin); add(mode.atoms); if (words.length) { mode.helperType = mimes[0]; CodeMirror.registerHelper("hintWords", mimes[0], words); } for (var i = 0; i < mimes.length; ++i) CodeMirror.defineMIME(mimes[i], mode); } def(["text/chapel"], { name: "chapel", keywords: words(chapelKeywords+" halt override owned "), types: chapelTypes, blockKeywords: words(chapelBlockKeywords), defKeywords: words(chapelDefKeywords), typeFirstDefinitions: true, atoms: words("nil true false"), }); });