openrat-cms

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

yacas.js (5426B)


      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 });