138 lines
3.4 KiB
JavaScript
138 lines
3.4 KiB
JavaScript
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|
// Distributed under an MIT license: http://codemirror.net/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) {
|
|
|
|
// 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);
|
|
|
|
// 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 === '/')
|
|
break;
|
|
prev = next;
|
|
}
|
|
state.tokenize = tokenBase;
|
|
return 'comment';
|
|
}
|
|
|
|
return {
|
|
startState: function() {return {tokenize: tokenBase, commentLevel: 0};},
|
|
token: function(stream, state) {
|
|
if (stream.eatSpace()) return null;
|
|
return state.tokenize(stream, state);
|
|
},
|
|
blockCommentStart: "/*",
|
|
blockCommentEnd: "*/",
|
|
lineComment: "//"
|
|
};
|
|
});
|
|
|
|
CodeMirror.defineMIME('text/x-yacas', {
|
|
name: 'yacas'
|
|
});
|
|
|
|
});
|