File modules/editor/codemirror/mode/yacas/yacas.js

Last commit: Sun Dec 17 01:14:09 2017 +0100	Jan Dankert	Integration eines weiteren Code-Editors: Codemirror. Demnächst müssen wir hier mal aufräumen und andere Editoren rauswerfen.
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 // Distributed under an MIT license: http://codemirror.net/LICENSE 3 4 // Yacas mode copyright (c) 2015 by Grzegorz Mazur 5 // Loosely based on mathematica mode by Calin Barbat 6 7 (function(mod) { 8 if (typeof exports == "object" && typeof module == "object") // CommonJS 9 mod(require("../../lib/codemirror")); 10 else if (typeof define == "function" && define.amd) // AMD 11 define(["../../lib/codemirror"], mod); 12 else // Plain browser env 13 mod(CodeMirror); 14 })(function(CodeMirror) { 15 "use strict"; 16 17 CodeMirror.defineMode('yacas', function(_config, _parserConfig) { 18 19 function words(str) { 20 var obj = {}, words = str.split(" "); 21 for (var i = 0; i < words.length; ++i) obj[words[i]] = true; 22 return obj; 23 } 24 25 var bodiedOps = words("Assert BackQuote D Defun Deriv For ForEach FromFile " + 26 "FromString Function Integrate InverseTaylor Limit " + 27 "LocalSymbols Macro MacroRule MacroRulePattern " + 28 "NIntegrate Rule RulePattern Subst TD TExplicitSum " + 29 "TSum Taylor Taylor1 Taylor2 Taylor3 ToFile " + 30 "ToStdout ToString TraceRule Until While"); 31 32 // patterns 33 var pFloatForm = "(?:(?:\\.\\d+|\\d+\\.\\d*|\\d+)(?:[eE][+-]?\\d+)?)"; 34 var pIdentifier = "(?:[a-zA-Z\\$'][a-zA-Z0-9\\$']*)"; 35 36 // regular expressions 37 var reFloatForm = new RegExp(pFloatForm); 38 var reIdentifier = new RegExp(pIdentifier); 39 var rePattern = new RegExp(pIdentifier + "?_" + pIdentifier); 40 var reFunctionLike = new RegExp(pIdentifier + "\\s*\\("); 41 42 function tokenBase(stream, state) { 43 var ch; 44 45 // get next character 46 ch = stream.next(); 47 48 // string 49 if (ch === '"') { 50 state.tokenize = tokenString; 51 return state.tokenize(stream, state); 52 } 53 54 // comment 55 if (ch === '/') { 56 if (stream.eat('*')) { 57 state.tokenize = tokenComment; 58 return state.tokenize(stream, state); 59 } 60 if (stream.eat("/")) { 61 stream.skipToEnd(); 62 return "comment"; 63 } 64 } 65 66 // go back one character 67 stream.backUp(1); 68 69 // update scope info 70 var m = stream.match(/^(\w+)\s*\(/, false); 71 if (m !== null && bodiedOps.hasOwnProperty(m[1])) 72 state.scopes.push('bodied'); 73 74 var scope = currentScope(state); 75 76 if (scope === 'bodied' && ch === '[') 77 state.scopes.pop(); 78 79 if (ch === '[' || ch === '{' || ch === '(') 80 state.scopes.push(ch); 81 82 scope = currentScope(state); 83 84 if (scope === '[' && ch === ']' || 85 scope === '{' && ch === '}' || 86 scope === '(' && ch === ')') 87 state.scopes.pop(); 88 89 if (ch === ';') { 90 while (scope === 'bodied') { 91 state.scopes.pop(); 92 scope = currentScope(state); 93 } 94 } 95 96 // look for ordered rules 97 if (stream.match(/\d+ *#/, true, false)) { 98 return 'qualifier'; 99 } 100 101 // look for numbers 102 if (stream.match(reFloatForm, true, false)) { 103 return 'number'; 104 } 105 106 // look for placeholders 107 if (stream.match(rePattern, true, false)) { 108 return 'variable-3'; 109 } 110 111 // match all braces separately 112 if (stream.match(/(?:\[|\]|{|}|\(|\))/, true, false)) { 113 return 'bracket'; 114 } 115 116 // literals looking like function calls 117 if (stream.match(reFunctionLike, true, false)) { 118 stream.backUp(1); 119 return 'variable'; 120 } 121 122 // all other identifiers 123 if (stream.match(reIdentifier, true, false)) { 124 return 'variable-2'; 125 } 126 127 // operators; note that operators like @@ or /; are matched separately for each symbol. 128 if (stream.match(/(?:\\|\+|\-|\*|\/|,|;|\.|:|@|~|=|>|<|&|\||_|`|'|\^|\?|!|%|#)/, true, false)) { 129 return 'operator'; 130 } 131 132 // everything else is an error 133 return 'error'; 134 } 135 136 function tokenString(stream, state) { 137 var next, end = false, escaped = false; 138 while ((next = stream.next()) != null) { 139 if (next === '"' && !escaped) { 140 end = true; 141 break; 142 } 143 escaped = !escaped && next === '\\'; 144 } 145 if (end && !escaped) { 146 state.tokenize = tokenBase; 147 } 148 return 'string'; 149 }; 150 151 function tokenComment(stream, state) { 152 var prev, next; 153 while((next = stream.next()) != null) { 154 if (prev === '*' && next === '/') { 155 state.tokenize = tokenBase; 156 break; 157 } 158 prev = next; 159 } 160 return 'comment'; 161 } 162 163 function currentScope(state) { 164 var scope = null; 165 if (state.scopes.length > 0) 166 scope = state.scopes[state.scopes.length - 1]; 167 return scope; 168 } 169 170 return { 171 startState: function() { 172 return { 173 tokenize: tokenBase, 174 scopes: [] 175 }; 176 }, 177 token: function(stream, state) { 178 if (stream.eatSpace()) return null; 179 return state.tokenize(stream, state); 180 }, 181 indent: function(state, textAfter) { 182 if (state.tokenize !== tokenBase && state.tokenize !== null) 183 return CodeMirror.Pass; 184 185 var delta = 0; 186 if (textAfter === ']' || textAfter === '];' || 187 textAfter === '}' || textAfter === '};' || 188 textAfter === ');') 189 delta = -1; 190 191 return (state.scopes.length + delta) * _config.indentUnit; 192 }, 193 electricChars: "{}[]();", 194 blockCommentStart: "/*", 195 blockCommentEnd: "*/", 196 lineComment: "//" 197 }; 198 }); 199 200 CodeMirror.defineMIME('text/x-yacas', { 201 name: 'yacas' 202 }); 203 204 });
Download modules/editor/codemirror/mode/yacas/yacas.js
History Sun, 17 Dec 2017 01:14:09 +0100 Jan Dankert Integration eines weiteren Code-Editors: Codemirror. Demnächst müssen wir hier mal aufräumen und andere Editoren rauswerfen.