openrat-cms

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

mathematica.js (5612B)


      1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
      2 // Distributed under an MIT license: http://codemirror.net/LICENSE
      3 
      4 // Mathematica mode copyright (c) 2015 by Calin Barbat
      5 // Based on code by Patrick Scheibe (halirutan)
      6 // See: https://github.com/halirutan/Mathematica-Source-Highlighting/tree/master/src/lang-mma.js
      7 
      8 (function(mod) {
      9   if (typeof exports == "object" && typeof module == "object") // CommonJS
     10     mod(require("../../lib/codemirror"));
     11   else if (typeof define == "function" && define.amd) // AMD
     12     define(["../../lib/codemirror"], mod);
     13   else // Plain browser env
     14     mod(CodeMirror);
     15 })(function(CodeMirror) {
     16 "use strict";
     17 
     18 CodeMirror.defineMode('mathematica', function(_config, _parserConfig) {
     19 
     20   // used pattern building blocks
     21   var Identifier = '[a-zA-Z\\$][a-zA-Z0-9\\$]*';
     22   var pBase      = "(?:\\d+)";
     23   var pFloat     = "(?:\\.\\d+|\\d+\\.\\d*|\\d+)";
     24   var pFloatBase = "(?:\\.\\w+|\\w+\\.\\w*|\\w+)";
     25   var pPrecision = "(?:`(?:`?"+pFloat+")?)";
     26 
     27   // regular expressions
     28   var reBaseForm        = new RegExp('(?:'+pBase+'(?:\\^\\^'+pFloatBase+pPrecision+'?(?:\\*\\^[+-]?\\d+)?))');
     29   var reFloatForm       = new RegExp('(?:' + pFloat + pPrecision + '?(?:\\*\\^[+-]?\\d+)?)');
     30   var reIdInContext     = new RegExp('(?:`?)(?:' + Identifier + ')(?:`(?:' + Identifier + '))*(?:`?)');
     31 
     32   function tokenBase(stream, state) {
     33     var ch;
     34 
     35     // get next character
     36     ch = stream.next();
     37 
     38     // string
     39     if (ch === '"') {
     40       state.tokenize = tokenString;
     41       return state.tokenize(stream, state);
     42     }
     43 
     44     // comment
     45     if (ch === '(') {
     46       if (stream.eat('*')) {
     47         state.commentLevel++;
     48         state.tokenize = tokenComment;
     49         return state.tokenize(stream, state);
     50       }
     51     }
     52 
     53     // go back one character
     54     stream.backUp(1);
     55 
     56     // look for numbers
     57     // Numbers in a baseform
     58     if (stream.match(reBaseForm, true, false)) {
     59       return 'number';
     60     }
     61 
     62     // Mathematica numbers. Floats (1.2, .2, 1.) can have optionally a precision (`float) or an accuracy definition
     63     // (``float). Note: while 1.2` is possible 1.2`` is not. At the end an exponent (float*^+12) can follow.
     64     if (stream.match(reFloatForm, true, false)) {
     65       return 'number';
     66     }
     67 
     68     /* In[23] and Out[34] */
     69     if (stream.match(/(?:In|Out)\[[0-9]*\]/, true, false)) {
     70       return 'atom';
     71     }
     72 
     73     // usage
     74     if (stream.match(/([a-zA-Z\$]+(?:`?[a-zA-Z0-9\$])*::usage)/, true, false)) {
     75       return 'meta';
     76     }
     77 
     78     // message
     79     if (stream.match(/([a-zA-Z\$]+(?:`?[a-zA-Z0-9\$])*::[a-zA-Z\$][a-zA-Z0-9\$]*):?/, true, false)) {
     80       return 'string-2';
     81     }
     82 
     83     // this makes a look-ahead match for something like variable:{_Integer}
     84     // the match is then forwarded to the mma-patterns tokenizer.
     85     if (stream.match(/([a-zA-Z\$][a-zA-Z0-9\$]*\s*:)(?:(?:[a-zA-Z\$][a-zA-Z0-9\$]*)|(?:[^:=>~@\^\&\*\)\[\]'\?,\|])).*/, true, false)) {
     86       return 'variable-2';
     87     }
     88 
     89     // catch variables which are used together with Blank (_), BlankSequence (__) or BlankNullSequence (___)
     90     // Cannot start with a number, but can have numbers at any other position. Examples
     91     // blub__Integer, a1_, b34_Integer32
     92     if (stream.match(/[a-zA-Z\$][a-zA-Z0-9\$]*_+[a-zA-Z\$][a-zA-Z0-9\$]*/, true, false)) {
     93       return 'variable-2';
     94     }
     95     if (stream.match(/[a-zA-Z\$][a-zA-Z0-9\$]*_+/, true, false)) {
     96       return 'variable-2';
     97     }
     98     if (stream.match(/_+[a-zA-Z\$][a-zA-Z0-9\$]*/, true, false)) {
     99       return 'variable-2';
    100     }
    101 
    102     // Named characters in Mathematica, like \[Gamma].
    103     if (stream.match(/\\\[[a-zA-Z\$][a-zA-Z0-9\$]*\]/, true, false)) {
    104       return 'variable-3';
    105     }
    106 
    107     // Match all braces separately
    108     if (stream.match(/(?:\[|\]|{|}|\(|\))/, true, false)) {
    109       return 'bracket';
    110     }
    111 
    112     // Catch Slots (#, ##, #3, ##9 and the V10 named slots #name). I have never seen someone using more than one digit after #, so we match
    113     // only one.
    114     if (stream.match(/(?:#[a-zA-Z\$][a-zA-Z0-9\$]*|#+[0-9]?)/, true, false)) {
    115       return 'variable-2';
    116     }
    117 
    118     // Literals like variables, keywords, functions
    119     if (stream.match(reIdInContext, true, false)) {
    120       return 'keyword';
    121     }
    122 
    123     // operators. Note that operators like @@ or /; are matched separately for each symbol.
    124     if (stream.match(/(?:\\|\+|\-|\*|\/|,|;|\.|:|@|~|=|>|<|&|\||_|`|'|\^|\?|!|%)/, true, false)) {
    125       return 'operator';
    126     }
    127 
    128     // everything else is an error
    129     stream.next(); // advance the stream.
    130     return 'error';
    131   }
    132 
    133   function tokenString(stream, state) {
    134     var next, end = false, escaped = false;
    135     while ((next = stream.next()) != null) {
    136       if (next === '"' && !escaped) {
    137         end = true;
    138         break;
    139       }
    140       escaped = !escaped && next === '\\';
    141     }
    142     if (end && !escaped) {
    143       state.tokenize = tokenBase;
    144     }
    145     return 'string';
    146   };
    147 
    148   function tokenComment(stream, state) {
    149     var prev, next;
    150     while(state.commentLevel > 0 && (next = stream.next()) != null) {
    151       if (prev === '(' && next === '*') state.commentLevel++;
    152       if (prev === '*' && next === ')') state.commentLevel--;
    153       prev = next;
    154     }
    155     if (state.commentLevel <= 0) {
    156       state.tokenize = tokenBase;
    157     }
    158     return 'comment';
    159   }
    160 
    161   return {
    162     startState: function() {return {tokenize: tokenBase, commentLevel: 0};},
    163     token: function(stream, state) {
    164       if (stream.eatSpace()) return null;
    165       return state.tokenize(stream, state);
    166     },
    167     blockCommentStart: "(*",
    168     blockCommentEnd: "*)"
    169   };
    170 });
    171 
    172 CodeMirror.defineMIME('text/x-mathematica', {
    173   name: 'mathematica'
    174 });
    175 
    176 });