mirror of https://github.com/gogits/gogs.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
176 lines
5.5 KiB
176 lines
5.5 KiB
// CodeMirror, copyright (c) by Marijn Haverbeke and others |
|
// Distributed under an MIT license: http://codemirror.net/LICENSE |
|
|
|
// Mathematica mode copyright (c) 2015 by Calin Barbat |
|
// Based on code by Patrick Scheibe (halirutan) |
|
// See: https://github.com/halirutan/Mathematica-Source-Highlighting/tree/master/src/lang-mma.js |
|
|
|
(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('mathematica', function(_config, _parserConfig) { |
|
|
|
// used pattern building blocks |
|
var Identifier = '[a-zA-Z\\$][a-zA-Z0-9\\$]*'; |
|
var pBase = "(?:\\d+)"; |
|
var pFloat = "(?:\\.\\d+|\\d+\\.\\d*|\\d+)"; |
|
var pFloatBase = "(?:\\.\\w+|\\w+\\.\\w*|\\w+)"; |
|
var pPrecision = "(?:`(?:`?"+pFloat+")?)"; |
|
|
|
// regular expressions |
|
var reBaseForm = new RegExp('(?:'+pBase+'(?:\\^\\^'+pFloatBase+pPrecision+'?(?:\\*\\^[+-]?\\d+)?))'); |
|
var reFloatForm = new RegExp('(?:' + pFloat + pPrecision + '?(?:\\*\\^[+-]?\\d+)?)'); |
|
var reIdInContext = new RegExp('(?:`?)(?:' + Identifier + ')(?:`(?:' + Identifier + '))*(?:`?)'); |
|
|
|
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.commentLevel++; |
|
state.tokenize = tokenComment; |
|
return state.tokenize(stream, state); |
|
} |
|
} |
|
|
|
// go back one character |
|
stream.backUp(1); |
|
|
|
// look for numbers |
|
// Numbers in a baseform |
|
if (stream.match(reBaseForm, true, false)) { |
|
return 'number'; |
|
} |
|
|
|
// Mathematica numbers. Floats (1.2, .2, 1.) can have optionally a precision (`float) or an accuracy definition |
|
// (``float). Note: while 1.2` is possible 1.2`` is not. At the end an exponent (float*^+12) can follow. |
|
if (stream.match(reFloatForm, true, false)) { |
|
return 'number'; |
|
} |
|
|
|
/* In[23] and Out[34] */ |
|
if (stream.match(/(?:In|Out)\[[0-9]*\]/, true, false)) { |
|
return 'atom'; |
|
} |
|
|
|
// usage |
|
if (stream.match(/([a-zA-Z\$]+(?:`?[a-zA-Z0-9\$])*::usage)/, true, false)) { |
|
return 'meta'; |
|
} |
|
|
|
// message |
|
if (stream.match(/([a-zA-Z\$]+(?:`?[a-zA-Z0-9\$])*::[a-zA-Z\$][a-zA-Z0-9\$]*):?/, true, false)) { |
|
return 'string-2'; |
|
} |
|
|
|
// this makes a look-ahead match for something like variable:{_Integer} |
|
// the match is then forwarded to the mma-patterns tokenizer. |
|
if (stream.match(/([a-zA-Z\$][a-zA-Z0-9\$]*\s*:)(?:(?:[a-zA-Z\$][a-zA-Z0-9\$]*)|(?:[^:=>~@\^\&\*\)\[\]'\?,\|])).*/, true, false)) { |
|
return 'variable-2'; |
|
} |
|
|
|
// catch variables which are used together with Blank (_), BlankSequence (__) or BlankNullSequence (___) |
|
// Cannot start with a number, but can have numbers at any other position. Examples |
|
// blub__Integer, a1_, b34_Integer32 |
|
if (stream.match(/[a-zA-Z\$][a-zA-Z0-9\$]*_+[a-zA-Z\$][a-zA-Z0-9\$]*/, true, false)) { |
|
return 'variable-2'; |
|
} |
|
if (stream.match(/[a-zA-Z\$][a-zA-Z0-9\$]*_+/, true, false)) { |
|
return 'variable-2'; |
|
} |
|
if (stream.match(/_+[a-zA-Z\$][a-zA-Z0-9\$]*/, true, false)) { |
|
return 'variable-2'; |
|
} |
|
|
|
// Named characters in Mathematica, like \[Gamma]. |
|
if (stream.match(/\\\[[a-zA-Z\$][a-zA-Z0-9\$]*\]/, true, false)) { |
|
return 'variable-3'; |
|
} |
|
|
|
// Match all braces separately |
|
if (stream.match(/(?:\[|\]|{|}|\(|\))/, true, false)) { |
|
return 'bracket'; |
|
} |
|
|
|
// Catch Slots (#, ##, #3, ##9 and the V10 named slots #name). I have never seen someone using more than one digit after #, so we match |
|
// only one. |
|
if (stream.match(/(?:#[a-zA-Z\$][a-zA-Z0-9\$]*|#+[0-9]?)/, true, false)) { |
|
return 'variable-2'; |
|
} |
|
|
|
// Literals like variables, keywords, functions |
|
if (stream.match(reIdInContext, true, false)) { |
|
return 'keyword'; |
|
} |
|
|
|
// operators. Note that operators like @@ or /; are matched separately for each symbol. |
|
if (stream.match(/(?:\\|\+|\-|\*|\/|,|;|\.|:|@|~|=|>|<|&|\||_|`|'|\^|\?|!|%)/, true, false)) { |
|
return 'operator'; |
|
} |
|
|
|
// everything else is an error |
|
stream.next(); // advance the stream. |
|
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(state.commentLevel > 0 && (next = stream.next()) != null) { |
|
if (prev === '(' && next === '*') state.commentLevel++; |
|
if (prev === '*' && next === ')') state.commentLevel--; |
|
prev = next; |
|
} |
|
if (state.commentLevel <= 0) { |
|
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: "*)" |
|
}; |
|
}); |
|
|
|
CodeMirror.defineMIME('text/x-mathematica', { |
|
name: 'mathematica' |
|
}); |
|
|
|
});
|
|
|