// CodeMirror, copyright (c) by Marijn Haverbeke and others // Distributed under an MIT license: https://codemirror.net/LICENSE // Yacas mode copyright (c) 2015 by Grzegorz Mazur // Loosely based on mathematica mode by Calin Barbat ;(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) // Plain browser env else mod(CodeMirror) })(function (CodeMirror) { 'use strict' CodeMirror.defineMode('yacas', function (_config, _parserConfig) { function words(str) { var obj = {}, words = str.split(' ') for (var i = 0; i < words.length; ++i) obj[words[i]] = true return obj } var bodiedOps = words( 'Assert BackQuote D Defun Deriv For ForEach FromFile ' + 'FromString Function Integrate InverseTaylor Limit ' + 'LocalSymbols Macro MacroRule MacroRulePattern ' + 'NIntegrate Rule RulePattern Subst TD TExplicitSum ' + 'TSum Taylor Taylor1 Taylor2 Taylor3 ToFile ' + 'ToStdout ToString TraceRule Until While' ) // patterns var pFloatForm = '(?:(?:\\.\\d+|\\d+\\.\\d*|\\d+)(?:[eE][+-]?\\d+)?)' var pIdentifier = "(?:[a-zA-Z\\$'][a-zA-Z0-9\\$']*)" // regular expressions var reFloatForm = new RegExp(pFloatForm) var reIdentifier = new RegExp(pIdentifier) var rePattern = new RegExp(pIdentifier + '?_' + pIdentifier) var reFunctionLike = new RegExp(pIdentifier + '\\s*\\(') 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.tokenize = tokenComment return state.tokenize(stream, state) } if (stream.eat('/')) { stream.skipToEnd() return 'comment' } } // go back one character stream.backUp(1) // update scope info var m = stream.match(/^(\w+)\s*\(/, false) if (m !== null && bodiedOps.hasOwnProperty(m[1])) state.scopes.push('bodied') var scope = currentScope(state) if (scope === 'bodied' && ch === '[') state.scopes.pop() if (ch === '[' || ch === '{' || ch === '(') state.scopes.push(ch) scope = currentScope(state) if ((scope === '[' && ch === ']') || (scope === '{' && ch === '}') || (scope === '(' && ch === ')')) state.scopes.pop() if (ch === ';') { while (scope === 'bodied') { state.scopes.pop() scope = currentScope(state) } } // look for ordered rules if (stream.match(/\d+ *#/, true, false)) { return 'qualifier' } // look for numbers if (stream.match(reFloatForm, true, false)) { return 'number' } // look for placeholders if (stream.match(rePattern, true, false)) { return 'variable-3' } // match all braces separately if (stream.match(/(?:\[|\]|{|}|\(|\))/, true, false)) { return 'bracket' } // literals looking like function calls if (stream.match(reFunctionLike, true, false)) { stream.backUp(1) return 'variable' } // all other identifiers if (stream.match(reIdentifier, true, false)) { return 'variable-2' } // operators; note that operators like @@ or /; are matched separately for each symbol. if (stream.match(/(?:\\|\+|\-|\*|\/|,|;|\.|:|@|~|=|>|<|&|\||_|`|'|\^|\?|!|%|#)/, true, false)) { return 'operator' } // everything else is an error 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 ((next = stream.next()) != null) { if (prev === '*' && next === '/') { state.tokenize = tokenBase break } prev = next } return 'comment' } function currentScope(state) { var scope = null if (state.scopes.length > 0) scope = state.scopes[state.scopes.length - 1] return scope } return { startState: function () { return { tokenize: tokenBase, scopes: [], } }, token: function (stream, state) { if (stream.eatSpace()) return null return state.tokenize(stream, state) }, indent: function (state, textAfter) { if (state.tokenize !== tokenBase && state.tokenize !== null) return CodeMirror.Pass var delta = 0 if (textAfter === ']' || textAfter === '];' || textAfter === '}' || textAfter === '};' || textAfter === ');') delta = -1 return (state.scopes.length + delta) * _config.indentUnit }, electricChars: '{}[]();', blockCommentStart: '/*', blockCommentEnd: '*/', lineComment: '//', } }) CodeMirror.defineMIME('text/x-yacas', { name: 'yacas', }) })