| 
									
										
										
										
											2018-01-21 10:33:32 -05:00
										 |  |  | // CodeMirror, copyright (c) by Marijn Haverbeke and others
 | 
					
						
							| 
									
										
										
										
											2018-10-07 12:02:07 +02:00
										 |  |  | // Distributed under an MIT license: https://codemirror.net/LICENSE
 | 
					
						
							| 
									
										
										
										
											2018-01-21 10:33:32 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | // 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
 | 
					
						
							| 
									
										
										
										
											2018-08-15 11:25:30 +02:00
										 |  |  |     if (stream.match(/([a-zA-Z\$][a-zA-Z0-9\$]*(?:`[a-zA-Z0-9\$]+)*::usage)/, true, false)) { | 
					
						
							| 
									
										
										
										
											2018-01-21 10:33:32 -05:00
										 |  |  |       return 'meta'; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // message
 | 
					
						
							| 
									
										
										
										
											2018-08-15 11:25:30 +02:00
										 |  |  |     if (stream.match(/([a-zA-Z\$][a-zA-Z0-9\$]*(?:`[a-zA-Z0-9\$]+)*::[a-zA-Z\$][a-zA-Z0-9\$]*):?/, true, false)) { | 
					
						
							| 
									
										
										
										
											2018-01-21 10:33:32 -05:00
										 |  |  |       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' | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | }); |