scripts/CodeMirror/mode/modelica/modelica.js (view raw)
1// CodeMirror, copyright (c) by Marijn Haverbeke and others
2// Distributed under an MIT license: https://codemirror.net/LICENSE
3
4// Modelica support for CodeMirror, copyright (c) by Lennart Ochel
5
6(function(mod) {
7 if (typeof exports == "object" && typeof module == "object") // CommonJS
8 mod(require("../../lib/codemirror"));
9 else if (typeof define == "function" && define.amd) // AMD
10 define(["../../lib/codemirror"], mod);
11 else // Plain browser env
12 mod(CodeMirror);
13})
14
15(function(CodeMirror) {
16 "use strict";
17
18 CodeMirror.defineMode("modelica", function(config, parserConfig) {
19
20 var indentUnit = config.indentUnit;
21 var keywords = parserConfig.keywords || {};
22 var builtin = parserConfig.builtin || {};
23 var atoms = parserConfig.atoms || {};
24
25 var isSingleOperatorChar = /[;=\(:\),{}.*<>+\-\/^\[\]]/;
26 var isDoubleOperatorChar = /(:=|<=|>=|==|<>|\.\+|\.\-|\.\*|\.\/|\.\^)/;
27 var isDigit = /[0-9]/;
28 var isNonDigit = /[_a-zA-Z]/;
29
30 function tokenLineComment(stream, state) {
31 stream.skipToEnd();
32 state.tokenize = null;
33 return "comment";
34 }
35
36 function tokenBlockComment(stream, state) {
37 var maybeEnd = false, ch;
38 while (ch = stream.next()) {
39 if (maybeEnd && ch == "/") {
40 state.tokenize = null;
41 break;
42 }
43 maybeEnd = (ch == "*");
44 }
45 return "comment";
46 }
47
48 function tokenString(stream, state) {
49 var escaped = false, ch;
50 while ((ch = stream.next()) != null) {
51 if (ch == '"' && !escaped) {
52 state.tokenize = null;
53 state.sol = false;
54 break;
55 }
56 escaped = !escaped && ch == "\\";
57 }
58
59 return "string";
60 }
61
62 function tokenIdent(stream, state) {
63 stream.eatWhile(isDigit);
64 while (stream.eat(isDigit) || stream.eat(isNonDigit)) { }
65
66
67 var cur = stream.current();
68
69 if(state.sol && (cur == "package" || cur == "model" || cur == "when" || cur == "connector")) state.level++;
70 else if(state.sol && cur == "end" && state.level > 0) state.level--;
71
72 state.tokenize = null;
73 state.sol = false;
74
75 if (keywords.propertyIsEnumerable(cur)) return "keyword";
76 else if (builtin.propertyIsEnumerable(cur)) return "builtin";
77 else if (atoms.propertyIsEnumerable(cur)) return "atom";
78 else return "variable";
79 }
80
81 function tokenQIdent(stream, state) {
82 while (stream.eat(/[^']/)) { }
83
84 state.tokenize = null;
85 state.sol = false;
86
87 if(stream.eat("'"))
88 return "variable";
89 else
90 return "error";
91 }
92
93 function tokenUnsignedNuber(stream, state) {
94 stream.eatWhile(isDigit);
95 if (stream.eat('.')) {
96 stream.eatWhile(isDigit);
97 }
98 if (stream.eat('e') || stream.eat('E')) {
99 if (!stream.eat('-'))
100 stream.eat('+');
101 stream.eatWhile(isDigit);
102 }
103
104 state.tokenize = null;
105 state.sol = false;
106 return "number";
107 }
108
109 // Interface
110 return {
111 startState: function() {
112 return {
113 tokenize: null,
114 level: 0,
115 sol: true
116 };
117 },
118
119 token: function(stream, state) {
120 if(state.tokenize != null) {
121 return state.tokenize(stream, state);
122 }
123
124 if(stream.sol()) {
125 state.sol = true;
126 }
127
128 // WHITESPACE
129 if(stream.eatSpace()) {
130 state.tokenize = null;
131 return null;
132 }
133
134 var ch = stream.next();
135
136 // LINECOMMENT
137 if(ch == '/' && stream.eat('/')) {
138 state.tokenize = tokenLineComment;
139 }
140 // BLOCKCOMMENT
141 else if(ch == '/' && stream.eat('*')) {
142 state.tokenize = tokenBlockComment;
143 }
144 // TWO SYMBOL TOKENS
145 else if(isDoubleOperatorChar.test(ch+stream.peek())) {
146 stream.next();
147 state.tokenize = null;
148 return "operator";
149 }
150 // SINGLE SYMBOL TOKENS
151 else if(isSingleOperatorChar.test(ch)) {
152 state.tokenize = null;
153 return "operator";
154 }
155 // IDENT
156 else if(isNonDigit.test(ch)) {
157 state.tokenize = tokenIdent;
158 }
159 // Q-IDENT
160 else if(ch == "'" && stream.peek() && stream.peek() != "'") {
161 state.tokenize = tokenQIdent;
162 }
163 // STRING
164 else if(ch == '"') {
165 state.tokenize = tokenString;
166 }
167 // UNSIGNED_NUBER
168 else if(isDigit.test(ch)) {
169 state.tokenize = tokenUnsignedNuber;
170 }
171 // ERROR
172 else {
173 state.tokenize = null;
174 return "error";
175 }
176
177 return state.tokenize(stream, state);
178 },
179
180 indent: function(state, textAfter) {
181 if (state.tokenize != null) return CodeMirror.Pass;
182
183 var level = state.level;
184 if(/(algorithm)/.test(textAfter)) level--;
185 if(/(equation)/.test(textAfter)) level--;
186 if(/(initial algorithm)/.test(textAfter)) level--;
187 if(/(initial equation)/.test(textAfter)) level--;
188 if(/(end)/.test(textAfter)) level--;
189
190 if(level > 0)
191 return indentUnit*level;
192 else
193 return 0;
194 },
195
196 blockCommentStart: "/*",
197 blockCommentEnd: "*/",
198 lineComment: "//"
199 };
200 });
201
202 function words(str) {
203 var obj = {}, words = str.split(" ");
204 for (var i=0; i<words.length; ++i)
205 obj[words[i]] = true;
206 return obj;
207 }
208
209 var modelicaKeywords = "algorithm and annotation assert block break class connect connector constant constrainedby der discrete each else elseif elsewhen encapsulated end enumeration equation expandable extends external false final flow for function if import impure in initial inner input loop model not operator or outer output package parameter partial protected public pure record redeclare replaceable return stream then true type when while within";
210 var modelicaBuiltin = "abs acos actualStream asin atan atan2 cardinality ceil cos cosh delay div edge exp floor getInstanceName homotopy inStream integer log log10 mod pre reinit rem semiLinear sign sin sinh spatialDistribution sqrt tan tanh";
211 var modelicaAtoms = "Real Boolean Integer String";
212
213 function def(mimes, mode) {
214 if (typeof mimes == "string")
215 mimes = [mimes];
216
217 var words = [];
218
219 function add(obj) {
220 if (obj)
221 for (var prop in obj)
222 if (obj.hasOwnProperty(prop))
223 words.push(prop);
224 }
225
226 add(mode.keywords);
227 add(mode.builtin);
228 add(mode.atoms);
229
230 if (words.length) {
231 mode.helperType = mimes[0];
232 CodeMirror.registerHelper("hintWords", mimes[0], words);
233 }
234
235 for (var i=0; i<mimes.length; ++i)
236 CodeMirror.defineMIME(mimes[i], mode);
237 }
238
239 def(["text/x-modelica"], {
240 name: "modelica",
241 keywords: words(modelicaKeywords),
242 builtin: words(modelicaBuiltin),
243 atoms: words(modelicaAtoms)
244 });
245});