|
|
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
// Yacas mode copyright (c) 2015 by Grzegorz Mazur
// Loosely based on mathematica mode by Calin Barbat
(function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror")); else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); else // Plain browser env
mod(CodeMirror); })(function(CodeMirror) { "use strict";
CodeMirror.defineMode('yacas', function(_config, _parserConfig) {
function words(str) { var obj = {}, words = str.split(" "); for (var i = 0; i < words.length; ++i) obj[words[i]] = true; return obj; }
var bodiedOps = words("Assert BackQuote D Defun Deriv For ForEach FromFile " + "FromString Function Integrate InverseTaylor Limit " + "LocalSymbols Macro MacroRule MacroRulePattern " + "NIntegrate Rule RulePattern Subst TD TExplicitSum " + "TSum Taylor Taylor1 Taylor2 Taylor3 ToFile " + "ToStdout ToString TraceRule Until While");
// patterns
var pFloatForm = "(?:(?:\\.\\d+|\\d+\\.\\d*|\\d+)(?:[eE][+-]?\\d+)?)"; var pIdentifier = "(?:[a-zA-Z\\$'][a-zA-Z0-9\\$']*)";
// regular expressions
var reFloatForm = new RegExp(pFloatForm); var reIdentifier = new RegExp(pIdentifier); var rePattern = new RegExp(pIdentifier + "?_" + pIdentifier); var reFunctionLike = new RegExp(pIdentifier + "\\s*\\(");
function tokenBase(stream, state) { var ch;
// get next character
ch = stream.next();
// string
if (ch === '"') { state.tokenize = tokenString; return state.tokenize(stream, state); }
// comment
if (ch === '/') { if (stream.eat('*')) { state.tokenize = tokenComment; return state.tokenize(stream, state); } if (stream.eat("/")) { stream.skipToEnd(); return "comment"; } }
// go back one character
stream.backUp(1);
// update scope info
var m = stream.match(/^(\w+)\s*\(/, false); if (m !== null && bodiedOps.hasOwnProperty(m[1])) state.scopes.push('bodied');
var scope = currentScope(state);
if (scope === 'bodied' && ch === '[') state.scopes.pop();
if (ch === '[' || ch === '{' || ch === '(') state.scopes.push(ch);
scope = currentScope(state);
if (scope === '[' && ch === ']' || scope === '{' && ch === '}' || scope === '(' && ch === ')') state.scopes.pop();
if (ch === ';') { while (scope === 'bodied') { state.scopes.pop(); scope = currentScope(state); } }
// look for ordered rules
if (stream.match(/\d+ *#/, true, false)) { return 'qualifier'; }
// look for numbers
if (stream.match(reFloatForm, true, false)) { return 'number'; }
// look for placeholders
if (stream.match(rePattern, true, false)) { return 'variable-3'; }
// match all braces separately
if (stream.match(/(?:\[|\]|{|}|\(|\))/, true, false)) { return 'bracket'; }
// literals looking like function calls
if (stream.match(reFunctionLike, true, false)) { stream.backUp(1); return 'variable'; }
// all other identifiers
if (stream.match(reIdentifier, true, false)) { return 'variable-2'; }
// operators; note that operators like @@ or /; are matched separately for each symbol.
if (stream.match(/(?:\\|\+|\-|\*|\/|,|;|\.|:|@|~|=|>|<|&|\||_|`|'|\^|\?|!|%|#)/, true, false)) { return 'operator'; }
// everything else is an error
return 'error'; }
function tokenString(stream, state) { var next, end = false, escaped = false; while ((next = stream.next()) != null) { if (next === '"' && !escaped) { end = true; break; } escaped = !escaped && next === '\\'; } if (end && !escaped) { state.tokenize = tokenBase; } return 'string'; };
function tokenComment(stream, state) { var prev, next; while((next = stream.next()) != null) { if (prev === '*' && next === '/') { state.tokenize = tokenBase; break; } prev = next; } return 'comment'; }
function currentScope(state) { var scope = null; if (state.scopes.length > 0) scope = state.scopes[state.scopes.length - 1]; return scope; }
return { startState: function() { return { tokenize: tokenBase, scopes: [] }; }, token: function(stream, state) { if (stream.eatSpace()) return null; return state.tokenize(stream, state); }, indent: function(state, textAfter) { if (state.tokenize !== tokenBase && state.tokenize !== null) return CodeMirror.Pass;
var delta = 0; if (textAfter === ']' || textAfter === '];' || textAfter === '}' || textAfter === '};' || textAfter === ');') delta = -1;
return (state.scopes.length + delta) * _config.indentUnit; }, electricChars: "{}[]();", blockCommentStart: "/*", blockCommentEnd: "*/", lineComment: "//" }; });
CodeMirror.defineMIME('text/x-yacas', { name: 'yacas' });
});
|