Mercurial
comparison .cms/lib/codemirror/mode/yacas/yacas.js @ 0:78edf6b517a0 draft
24.10
author | Coffee CMS <info@coffee-cms.ru> |
---|---|
date | Fri, 11 Oct 2024 22:40:23 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:78edf6b517a0 |
---|---|
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others | |
2 // Distributed under an MIT license: https://codemirror.net/5/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 }); |