cellml-text-editor 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cellml-text-editor.js +306 -229
- package/dist/cellml-text-editor.umd.cjs +10 -10
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
var n = /* @__PURE__ */ ((
|
|
2
|
-
class
|
|
1
|
+
var n = /* @__PURE__ */ ((c) => (c[c.Unknown = 0] = "Unknown", c[c.EOF = 1] = "EOF", c[c.Identifier = 2] = "Identifier", c[c.Number = 3] = "Number", c[c.String = 4] = "String", c[c.KwDef = 5] = "KwDef", c[c.KwModel = 6] = "KwModel", c[c.KwComp = 7] = "KwComp", c[c.KwEndDef = 8] = "KwEndDef", c[c.KwAs = 9] = "KwAs", c[c.KwVar = 10] = "KwVar", c[c.KwUnit = 11] = "KwUnit", c[c.KwSel = 12] = "KwSel", c[c.KwCase = 13] = "KwCase", c[c.KwOtherwise = 14] = "KwOtherwise", c[c.KwEndSel = 15] = "KwEndSel", c[c.OpAss = 16] = "OpAss", c[c.OpPlus = 17] = "OpPlus", c[c.OpMinus = 18] = "OpMinus", c[c.OpTimes = 19] = "OpTimes", c[c.OpDivide = 20] = "OpDivide", c[c.OpComma = 21] = "OpComma", c[c.Colon = 22] = "Colon", c[c.SemiColon = 23] = "SemiColon", c[c.LParam = 24] = "LParam", c[c.RParam = 25] = "RParam", c[c.LBrace = 26] = "LBrace", c[c.RBrace = 27] = "RBrace", c[c.OpEq = 28] = "OpEq", c[c.OpNe = 29] = "OpNe", c[c.OpLt = 30] = "OpLt", c[c.OpLe = 31] = "OpLe", c[c.OpGt = 32] = "OpGt", c[c.OpGe = 33] = "OpGe", c[c.OpAnd = 34] = "OpAnd", c[c.OpOr = 35] = "OpOr", c))(n || {});
|
|
2
|
+
class N {
|
|
3
3
|
input;
|
|
4
4
|
pos = 0;
|
|
5
5
|
line = 1;
|
|
@@ -22,16 +22,16 @@ class x {
|
|
|
22
22
|
this.currentToken = 1;
|
|
23
23
|
return;
|
|
24
24
|
}
|
|
25
|
-
const
|
|
26
|
-
if (/[a-zA-Z_]/.test(
|
|
25
|
+
const t = this.input[this.pos];
|
|
26
|
+
if (/[a-zA-Z_]/.test(t || "")) {
|
|
27
27
|
let i = this.pos;
|
|
28
28
|
for (; this.pos < this.length && /[a-zA-Z0-9_]/.test(this.input[this.pos] || ""); )
|
|
29
29
|
this.pos++;
|
|
30
|
-
const
|
|
31
|
-
this.currentValue =
|
|
30
|
+
const s = this.input.slice(i, this.pos);
|
|
31
|
+
this.currentValue = s, this.currentToken = this.getKeywordType(s);
|
|
32
32
|
return;
|
|
33
33
|
}
|
|
34
|
-
if (/[0-9]/.test(
|
|
34
|
+
if (/[0-9]/.test(t || "") || t === "." && /[0-9]/.test(this.input[this.pos + 1] || "")) {
|
|
35
35
|
let i = this.pos;
|
|
36
36
|
for (; this.pos < this.length && /[0-9]/.test(this.input[this.pos] || ""); ) this.pos++;
|
|
37
37
|
if (this.input[this.pos] === ".")
|
|
@@ -41,7 +41,7 @@ class x {
|
|
|
41
41
|
this.currentValue = this.input.slice(i, this.pos), this.currentToken = 3;
|
|
42
42
|
return;
|
|
43
43
|
}
|
|
44
|
-
switch (this.pos++, this.currentValue =
|
|
44
|
+
switch (this.pos++, this.currentValue = t || "", t) {
|
|
45
45
|
// --- ASSIGNMENT VS EQUALITY ---
|
|
46
46
|
case "=":
|
|
47
47
|
this.input[this.pos] === "=" ? (this.pos++, this.currentValue = "==", this.currentToken = 28) : this.currentToken = 16;
|
|
@@ -90,7 +90,7 @@ class x {
|
|
|
90
90
|
this.currentToken = 21;
|
|
91
91
|
break;
|
|
92
92
|
default:
|
|
93
|
-
console.warn("Unknown char:",
|
|
93
|
+
console.warn("Unknown char:", t), this.currentToken = 0;
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
96
|
getLine() {
|
|
@@ -99,11 +99,11 @@ class x {
|
|
|
99
99
|
skipWhitespace() {
|
|
100
100
|
let e = 0;
|
|
101
101
|
for (; this.pos < this.length; ) {
|
|
102
|
-
const
|
|
103
|
-
if (/\s/.test(
|
|
104
|
-
|
|
102
|
+
const t = this.input[this.pos];
|
|
103
|
+
if (/\s/.test(t || ""))
|
|
104
|
+
t === `
|
|
105
105
|
` && e++, this.pos++;
|
|
106
|
-
else if (
|
|
106
|
+
else if (t === "/" && this.input[this.pos + 1] === "/")
|
|
107
107
|
for (this.pos += 2; this.pos < this.length && this.input[this.pos] !== `
|
|
108
108
|
`; ) this.pos++;
|
|
109
109
|
else
|
|
@@ -145,7 +145,7 @@ class x {
|
|
|
145
145
|
}
|
|
146
146
|
}
|
|
147
147
|
const m = "http://www.cellml.org/cellml/2.0#", h = "http://www.w3.org/1998/Math/MathML";
|
|
148
|
-
class
|
|
148
|
+
class E {
|
|
149
149
|
scanner;
|
|
150
150
|
doc;
|
|
151
151
|
sourceLineAttr;
|
|
@@ -153,15 +153,15 @@ class $ {
|
|
|
153
153
|
this.sourceLineAttr = e.sourceLineAttribute === void 0 ? "data-source-location" : e.sourceLineAttribute;
|
|
154
154
|
}
|
|
155
155
|
parse(e) {
|
|
156
|
-
this.scanner = new
|
|
156
|
+
this.scanner = new N(e), this.doc = document.implementation.createDocument(m, "model", null);
|
|
157
157
|
try {
|
|
158
|
-
const
|
|
159
|
-
for (this.expect(n.KwDef), this.expect(n.KwModel), this.scanner.token === n.Identifier && (
|
|
160
|
-
this.scanner.token === n.KwDef ? this.parseBlock(
|
|
158
|
+
const t = this.doc.documentElement;
|
|
159
|
+
for (this.expect(n.KwDef), this.expect(n.KwModel), this.scanner.token === n.Identifier && (t.setAttribute("name", this.scanner.value), this.scanner.nextToken()), this.expect(n.KwAs); this.scanner.token !== n.KwEndDef && this.scanner.token !== n.EOF; )
|
|
160
|
+
this.scanner.token === n.KwDef ? this.parseBlock(t) : this.scanner.nextToken();
|
|
161
161
|
return this.expect(n.KwEndDef), this.expect(n.SemiColon), { xml: `<?xml version="1.0" encoding="UTF-8"?>
|
|
162
|
-
` + this.serialize(
|
|
163
|
-
} catch (
|
|
164
|
-
return { xml: null, errors: [{ line: this.scanner.getLine(), message:
|
|
162
|
+
` + this.serialize(t), errors: [] };
|
|
163
|
+
} catch (t) {
|
|
164
|
+
return { xml: null, errors: [{ line: this.scanner.getLine(), message: t.message || "Unknown parsing error" }] };
|
|
165
165
|
}
|
|
166
166
|
}
|
|
167
167
|
parseBlock(e) {
|
|
@@ -174,29 +174,29 @@ class $ {
|
|
|
174
174
|
}
|
|
175
175
|
parseComponent(e) {
|
|
176
176
|
this.expect(n.KwComp);
|
|
177
|
-
const
|
|
177
|
+
const t = this.expectValue(n.Identifier);
|
|
178
178
|
this.expect(n.KwAs);
|
|
179
179
|
const i = this.doc.createElementNS(m, "component");
|
|
180
|
-
for (i.setAttribute("name",
|
|
180
|
+
for (i.setAttribute("name", t), e.appendChild(i); this.scanner.token !== n.KwEndDef && this.scanner.token !== n.EOF; )
|
|
181
181
|
this.scanner.token === n.KwVar ? this.parseVariable(i) : this.scanner.token === n.Identifier || this.scanner.token === n.KwSel ? this.parseMathEquation(i) : this.scanner.nextToken();
|
|
182
182
|
this.expect(n.KwEndDef), this.expect(n.SemiColon);
|
|
183
183
|
}
|
|
184
184
|
// var V: millivolt {init: -65, interface: public};
|
|
185
185
|
parseVariable(e) {
|
|
186
186
|
this.expect(n.KwVar);
|
|
187
|
-
const
|
|
187
|
+
const t = this.expectValue(n.Identifier);
|
|
188
188
|
this.expect(n.Colon);
|
|
189
|
-
const i = this.expectValue(n.Identifier),
|
|
190
|
-
if (
|
|
189
|
+
const i = this.expectValue(n.Identifier), s = this.doc.createElementNS(m, "variable");
|
|
190
|
+
if (s.setAttribute("name", t), s.setAttribute("units", i), this.scanner.token === n.LBrace) {
|
|
191
191
|
for (this.scanner.nextToken(); this.scanner.token !== n.RBrace && this.scanner.token !== n.EOF; ) {
|
|
192
192
|
const r = this.expectValue(n.Identifier);
|
|
193
193
|
this.expect(n.Colon);
|
|
194
|
-
let
|
|
195
|
-
this.scanner.token === n.OpMinus ? (this.scanner.nextToken(),
|
|
194
|
+
let a = "";
|
|
195
|
+
this.scanner.token === n.OpMinus ? (this.scanner.nextToken(), a = "-" + this.expectValue(n.Number)) : this.scanner.token === n.Number ? a = this.expectValue(n.Number) : a = this.expectValue(n.Identifier), r === "init" ? s.setAttribute("initial_value", a) : r === "interface" && s.setAttribute("interface", a), this.scanner.token === n.OpComma && this.scanner.nextToken();
|
|
196
196
|
}
|
|
197
197
|
this.expect(n.RBrace);
|
|
198
198
|
}
|
|
199
|
-
this.expect(n.SemiColon), e.appendChild(
|
|
199
|
+
this.expect(n.SemiColon), e.appendChild(s);
|
|
200
200
|
}
|
|
201
201
|
parseUnit(e) {
|
|
202
202
|
for (this.expect(n.KwUnit); this.scanner.token !== n.KwEndDef && this.scanner.token !== n.EOF; )
|
|
@@ -205,27 +205,27 @@ class $ {
|
|
|
205
205
|
}
|
|
206
206
|
// --- Math Parsing ---
|
|
207
207
|
parseMathEquation(e) {
|
|
208
|
-
const
|
|
208
|
+
const t = this.scanner.getLine();
|
|
209
209
|
let i = e.getElementsByTagNameNS(h, "math")[0];
|
|
210
210
|
i || (i = this.doc.createElementNS(h, "math"), e.appendChild(i));
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
const
|
|
211
|
+
const s = this.doc.createElementNS(h, "apply"), r = this.doc.createElementNS(h, "eq");
|
|
212
|
+
s.appendChild(r);
|
|
213
|
+
const a = this.parseExpression();
|
|
214
214
|
this.expect(n.OpAss);
|
|
215
|
-
const o = this.parseExpression(),
|
|
216
|
-
this.sourceLineAttr &&
|
|
215
|
+
const o = this.parseExpression(), l = this.scanner.getLine();
|
|
216
|
+
this.sourceLineAttr && s.setAttribute(
|
|
217
217
|
this.sourceLineAttr,
|
|
218
|
-
`${
|
|
219
|
-
),
|
|
218
|
+
`${t.toString()}` + (l !== t ? `-${l.toString()}` : "")
|
|
219
|
+
), s.appendChild(a), s.appendChild(o), i.appendChild(s), this.expect(n.SemiColon);
|
|
220
220
|
}
|
|
221
221
|
// Recursive Descent for Math: Condition -> Comparison -> Expression -> Term -> Factor
|
|
222
222
|
parseCondition() {
|
|
223
223
|
let e = this.parseComparison();
|
|
224
224
|
for (; this.scanner.token === n.OpAnd || this.scanner.token === n.OpOr; ) {
|
|
225
|
-
const
|
|
225
|
+
const t = this.scanner.token;
|
|
226
226
|
this.scanner.nextToken();
|
|
227
|
-
const i = this.parseComparison(),
|
|
228
|
-
|
|
227
|
+
const i = this.parseComparison(), s = this.doc.createElementNS(h, "apply"), r = this.doc.createElementNS(h, t === n.OpAnd ? "and" : "or");
|
|
228
|
+
s.appendChild(r), s.appendChild(e), s.appendChild(i), e = s;
|
|
229
229
|
}
|
|
230
230
|
return e;
|
|
231
231
|
}
|
|
@@ -236,11 +236,11 @@ class $ {
|
|
|
236
236
|
parseComparison() {
|
|
237
237
|
let e = this.parseExpression();
|
|
238
238
|
if (this.isComparisonToken(this.scanner.token)) {
|
|
239
|
-
const
|
|
239
|
+
const t = this.scanner.token;
|
|
240
240
|
this.scanner.nextToken();
|
|
241
|
-
const i = this.parseExpression(),
|
|
241
|
+
const i = this.parseExpression(), s = this.doc.createElementNS(h, "apply");
|
|
242
242
|
let r = "";
|
|
243
|
-
switch (
|
|
243
|
+
switch (t) {
|
|
244
244
|
case n.OpEq:
|
|
245
245
|
r = "eq";
|
|
246
246
|
break;
|
|
@@ -263,8 +263,8 @@ class $ {
|
|
|
263
263
|
r = "and";
|
|
264
264
|
break;
|
|
265
265
|
}
|
|
266
|
-
const
|
|
267
|
-
return
|
|
266
|
+
const a = this.doc.createElementNS(h, r);
|
|
267
|
+
return s.appendChild(a), s.appendChild(e), s.appendChild(i), s;
|
|
268
268
|
}
|
|
269
269
|
return e;
|
|
270
270
|
}
|
|
@@ -272,22 +272,22 @@ class $ {
|
|
|
272
272
|
* Checks if an element is an <apply> block for a specific operator.
|
|
273
273
|
* e.g. isMathMLApply(node, 'plus') returns true for <apply><plus/>...</apply>
|
|
274
274
|
*/
|
|
275
|
-
isMathMLApply(e,
|
|
275
|
+
isMathMLApply(e, t) {
|
|
276
276
|
if (e.localName !== "apply") return !1;
|
|
277
277
|
const i = e.firstElementChild;
|
|
278
|
-
return i ? i.localName ===
|
|
278
|
+
return i ? i.localName === t : !1;
|
|
279
279
|
}
|
|
280
280
|
parseExpression() {
|
|
281
281
|
let e = this.parseTerm();
|
|
282
282
|
for (; this.scanner.token === n.OpPlus || this.scanner.token === n.OpMinus; ) {
|
|
283
|
-
const
|
|
283
|
+
const t = this.scanner.token;
|
|
284
284
|
this.scanner.nextToken();
|
|
285
285
|
const i = this.parseTerm();
|
|
286
|
-
if (
|
|
286
|
+
if (t === n.OpPlus && this.isMathMLApply(e, "plus"))
|
|
287
287
|
e.appendChild(i);
|
|
288
288
|
else {
|
|
289
|
-
const
|
|
290
|
-
|
|
289
|
+
const s = this.doc.createElementNS(h, "apply"), r = this.doc.createElementNS(h, t === n.OpPlus ? "plus" : "minus");
|
|
290
|
+
s.appendChild(r), s.appendChild(e), s.appendChild(i), e = s;
|
|
291
291
|
}
|
|
292
292
|
}
|
|
293
293
|
return e;
|
|
@@ -295,14 +295,14 @@ class $ {
|
|
|
295
295
|
parseTerm() {
|
|
296
296
|
let e = this.parseFactor();
|
|
297
297
|
for (; this.scanner.token === n.OpTimes || this.scanner.token === n.OpDivide; ) {
|
|
298
|
-
const
|
|
298
|
+
const t = this.scanner.token;
|
|
299
299
|
this.scanner.nextToken();
|
|
300
300
|
const i = this.parseFactor();
|
|
301
|
-
if (
|
|
301
|
+
if (t === n.OpTimes && this.isMathMLApply(e, "times"))
|
|
302
302
|
e.appendChild(i);
|
|
303
303
|
else {
|
|
304
|
-
const
|
|
305
|
-
|
|
304
|
+
const s = this.doc.createElementNS(h, "apply"), r = this.doc.createElementNS(h, t === n.OpTimes ? "times" : "divide");
|
|
305
|
+
s.appendChild(r), s.appendChild(e), s.appendChild(i), e = s;
|
|
306
306
|
}
|
|
307
307
|
}
|
|
308
308
|
return e;
|
|
@@ -312,7 +312,7 @@ class $ {
|
|
|
312
312
|
* and returns the corresponding element, or null if it's a variable.
|
|
313
313
|
*/
|
|
314
314
|
createMathMLConstant(e) {
|
|
315
|
-
const
|
|
315
|
+
const t = {
|
|
316
316
|
pi: "pi",
|
|
317
317
|
e: "exponentiale",
|
|
318
318
|
// Standard math constant e
|
|
@@ -324,36 +324,42 @@ class $ {
|
|
|
324
324
|
// Boolean constants
|
|
325
325
|
false: "false"
|
|
326
326
|
};
|
|
327
|
-
return
|
|
327
|
+
return t.hasOwnProperty(e) ? this.doc.createElementNS(h, t[e] || "") : null;
|
|
328
328
|
}
|
|
329
329
|
parseFactor() {
|
|
330
330
|
if (this.scanner.token === n.OpMinus) {
|
|
331
331
|
this.scanner.nextToken();
|
|
332
|
-
const e = this.parseFactor(),
|
|
333
|
-
return
|
|
332
|
+
const e = this.parseFactor(), t = this.doc.createElementNS(h, "apply"), i = this.doc.createElementNS(h, "minus");
|
|
333
|
+
return t.appendChild(i), t.appendChild(e), t;
|
|
334
334
|
}
|
|
335
335
|
if (this.scanner.token === n.Number) {
|
|
336
336
|
const e = this.scanner.value;
|
|
337
337
|
this.scanner.nextToken();
|
|
338
|
-
const
|
|
339
|
-
if (
|
|
338
|
+
const t = this.doc.createElementNS(h, "cn");
|
|
339
|
+
if (this.scanner.token === n.LBrace) {
|
|
340
340
|
if (this.scanner.nextToken(), this.scanner.value === "units") {
|
|
341
341
|
this.scanner.nextToken(), this.expect(n.Colon);
|
|
342
342
|
const i = this.expectValue(n.Identifier);
|
|
343
|
-
|
|
343
|
+
t.setAttributeNS(m, "cellml:units", i);
|
|
344
344
|
}
|
|
345
345
|
for (; this.scanner.token !== n.RBrace && this.scanner.token !== n.EOF; )
|
|
346
346
|
this.scanner.nextToken();
|
|
347
347
|
this.expect(n.RBrace);
|
|
348
348
|
}
|
|
349
|
-
|
|
349
|
+
if (e.match(/^-?[\d.]+[eE][+-]?\d+$/)) {
|
|
350
|
+
t.setAttribute("type", "e-notation");
|
|
351
|
+
const i = this.doc.createElementNS(h, "sep"), [s, r] = e.split(/[eE]/);
|
|
352
|
+
t.appendChild(this.doc.createTextNode(s || "1")), t.appendChild(i), t.appendChild(this.doc.createTextNode(r || "0"));
|
|
353
|
+
} else
|
|
354
|
+
t.textContent = e;
|
|
355
|
+
return t;
|
|
350
356
|
} else if (this.scanner.token === n.Identifier) {
|
|
351
357
|
const e = this.scanner.value;
|
|
352
358
|
if (this.scanner.nextToken(), this.scanner.token === n.LParam)
|
|
353
359
|
return this.parseFunctionCall(e);
|
|
354
|
-
const
|
|
355
|
-
if (
|
|
356
|
-
return
|
|
360
|
+
const t = this.createMathMLConstant(e);
|
|
361
|
+
if (t)
|
|
362
|
+
return t;
|
|
357
363
|
const i = this.doc.createElementNS(h, "ci");
|
|
358
364
|
return i.textContent = e, i;
|
|
359
365
|
} else if (this.scanner.token === n.LParam) {
|
|
@@ -368,39 +374,39 @@ class $ {
|
|
|
368
374
|
const e = this.doc.createElementNS(h, "piecewise");
|
|
369
375
|
for (this.expect(n.KwSel); this.scanner.token === n.KwCase; ) {
|
|
370
376
|
this.expect(n.KwCase);
|
|
371
|
-
const
|
|
377
|
+
const t = this.parseCondition();
|
|
372
378
|
this.expect(n.Colon);
|
|
373
379
|
const i = this.parseExpression();
|
|
374
380
|
this.expect(n.SemiColon);
|
|
375
|
-
const
|
|
376
|
-
|
|
381
|
+
const s = this.doc.createElementNS(h, "piece");
|
|
382
|
+
s.appendChild(i), s.appendChild(t), e.appendChild(s);
|
|
377
383
|
}
|
|
378
384
|
if (this.scanner.token === n.KwOtherwise) {
|
|
379
385
|
this.expect(n.KwOtherwise), this.expect(n.Colon);
|
|
380
|
-
const
|
|
386
|
+
const t = this.parseExpression();
|
|
381
387
|
this.expect(n.SemiColon);
|
|
382
388
|
const i = this.doc.createElementNS(h, "otherwise");
|
|
383
|
-
i.appendChild(
|
|
389
|
+
i.appendChild(t), e.appendChild(i);
|
|
384
390
|
}
|
|
385
391
|
return this.expect(n.KwEndSel), e;
|
|
386
392
|
}
|
|
387
393
|
parseFunctionCall(e) {
|
|
388
394
|
if (this.expect(n.LParam), e === "ode") {
|
|
389
|
-
const
|
|
395
|
+
const s = this.parseExpression();
|
|
390
396
|
this.expect(n.OpComma);
|
|
391
397
|
const r = this.parseExpression();
|
|
392
398
|
this.expect(n.RParam);
|
|
393
|
-
const
|
|
394
|
-
|
|
399
|
+
const a = this.doc.createElementNS(h, "apply");
|
|
400
|
+
a.appendChild(this.doc.createElementNS(h, "diff"));
|
|
395
401
|
const o = this.doc.createElementNS(h, "bvar");
|
|
396
|
-
return o.appendChild(r),
|
|
402
|
+
return o.appendChild(r), a.appendChild(o), a.appendChild(s), a;
|
|
397
403
|
}
|
|
398
|
-
const
|
|
399
|
-
if (
|
|
404
|
+
const t = this.doc.createElementNS(h, "apply"), i = this.doc.createElementNS(h, e);
|
|
405
|
+
if (t.appendChild(i), this.scanner.token !== n.RParam)
|
|
400
406
|
do
|
|
401
|
-
this.scanner.token === n.OpComma && this.scanner.nextToken(),
|
|
407
|
+
this.scanner.token === n.OpComma && this.scanner.nextToken(), t.appendChild(this.parseExpression());
|
|
402
408
|
while (this.scanner.token === n.OpComma);
|
|
403
|
-
return this.expect(n.RParam),
|
|
409
|
+
return this.expect(n.RParam), t;
|
|
404
410
|
}
|
|
405
411
|
// --- Helpers ---
|
|
406
412
|
expect(e) {
|
|
@@ -411,20 +417,20 @@ class $ {
|
|
|
411
417
|
expectValue(e) {
|
|
412
418
|
if (this.scanner.token !== e)
|
|
413
419
|
throw new Error(`Expected value of type ${n[e]}, got ${this.scanner.token}`);
|
|
414
|
-
const
|
|
415
|
-
return this.scanner.nextToken(),
|
|
420
|
+
const t = this.scanner.value;
|
|
421
|
+
return this.scanner.nextToken(), t;
|
|
416
422
|
}
|
|
417
423
|
/**
|
|
418
424
|
* Checks if the element or any of its descendants use a CellML attribute
|
|
419
425
|
* (e.g. cellml:units).
|
|
420
426
|
*/
|
|
421
427
|
usesCellMLNamespace(e) {
|
|
422
|
-
const
|
|
423
|
-
for (let i = 0; i <
|
|
424
|
-
const
|
|
425
|
-
for (let r = 0;
|
|
426
|
-
const
|
|
427
|
-
if (
|
|
428
|
+
const t = e.getElementsByTagName("*");
|
|
429
|
+
for (let i = 0; i < t.length; i++) {
|
|
430
|
+
const s = t[i];
|
|
431
|
+
for (let r = 0; s && r < s.attributes.length; r++) {
|
|
432
|
+
const a = s.attributes[r];
|
|
433
|
+
if (a && a.namespaceURI === m)
|
|
428
434
|
return !0;
|
|
429
435
|
}
|
|
430
436
|
}
|
|
@@ -435,42 +441,44 @@ class $ {
|
|
|
435
441
|
* and returns the prefix used (e.g. 'cellml', 'cellml2', or '' for default).
|
|
436
442
|
* Returns null if not found.
|
|
437
443
|
*/
|
|
438
|
-
getPrefixForNamespace(e,
|
|
444
|
+
getPrefixForNamespace(e, t) {
|
|
439
445
|
const i = "http://www.w3.org/2000/xmlns/";
|
|
440
|
-
for (let
|
|
441
|
-
const r = e.attributes[
|
|
442
|
-
if (r && r.namespaceURI === i && r.value ===
|
|
446
|
+
for (let s = 0; s < e.attributes.length; s++) {
|
|
447
|
+
const r = e.attributes[s];
|
|
448
|
+
if (r && r.namespaceURI === i && r.value === t)
|
|
443
449
|
return r.localName === "xmlns" ? "" : r.localName;
|
|
444
450
|
}
|
|
445
451
|
return null;
|
|
446
452
|
}
|
|
447
|
-
serialize(e,
|
|
448
|
-
const i = " ".repeat(
|
|
449
|
-
let
|
|
450
|
-
r === "model" && !e.hasAttribute("xmlns") && (
|
|
453
|
+
serialize(e, t = 0) {
|
|
454
|
+
const i = " ".repeat(t), s = e.tagName, r = e.localName;
|
|
455
|
+
let a = "";
|
|
456
|
+
r === "model" && !e.hasAttribute("xmlns") && (a += ` xmlns="${m}"`), r === "math" && !e.hasAttribute("xmlns") && (a += ` xmlns="${h}"`, this.usesCellMLNamespace(e) && !e.hasAttribute("xmlns:cellml") && this.getPrefixForNamespace(e, m) === null && (a += ` xmlns:cellml="${m}"`));
|
|
451
457
|
for (let d = 0; d < e.attributes.length; d++) {
|
|
452
458
|
const f = e.attributes[d];
|
|
453
459
|
if (f) {
|
|
454
460
|
if (this.sourceLineAttr && f.name === this.sourceLineAttr)
|
|
455
461
|
continue;
|
|
456
|
-
|
|
462
|
+
a += ` ${f.name}="${f.value}"`;
|
|
457
463
|
}
|
|
458
464
|
}
|
|
459
|
-
const o = Array.from(e.childNodes),
|
|
460
|
-
if (o.length === 0 && !
|
|
461
|
-
return `${i}<${
|
|
462
|
-
if (
|
|
463
|
-
|
|
464
|
-
|
|
465
|
+
const o = Array.from(e.childNodes), l = o.some((d) => d.nodeType === 1), u = e.textContent?.trim();
|
|
466
|
+
if (o.length === 0 && !u)
|
|
467
|
+
return `${i}<${s}${a}/>`;
|
|
468
|
+
if (l) {
|
|
469
|
+
if (e.tagName === "cn" && o.length === 3)
|
|
470
|
+
return `${i}<${s}${a}>${o[0]?.textContent}<sep/>${o[2]?.textContent}</${s}>`;
|
|
471
|
+
} else return `${i}<${s}${a}>${u}</${s}>`;
|
|
472
|
+
let p = `${i}<${s}${a}>
|
|
465
473
|
`;
|
|
466
474
|
return o.forEach((d) => {
|
|
467
|
-
d.nodeType === 1 && (p += this.serialize(d,
|
|
475
|
+
d.nodeType === 1 && (p += this.serialize(d, t + 1) + `
|
|
468
476
|
`);
|
|
469
|
-
}), p += `${i}</${
|
|
477
|
+
}), p += `${i}</${s}>`, p;
|
|
470
478
|
}
|
|
471
479
|
}
|
|
472
|
-
const
|
|
473
|
-
class
|
|
480
|
+
const C = "http://www.cellml.org/cellml/2.0#";
|
|
481
|
+
class k {
|
|
474
482
|
output = "";
|
|
475
483
|
indentLevel = 0;
|
|
476
484
|
domParser;
|
|
@@ -482,72 +490,72 @@ class N {
|
|
|
482
490
|
indent() {
|
|
483
491
|
return this.standardIndent.repeat(this.indentLevel);
|
|
484
492
|
}
|
|
485
|
-
append(e,
|
|
486
|
-
this.output += (
|
|
493
|
+
append(e, t = !0) {
|
|
494
|
+
this.output += (t ? this.indent() : "") + e + (t ? `
|
|
487
495
|
` : "");
|
|
488
496
|
}
|
|
489
497
|
// --- Main Entry Point ---
|
|
490
498
|
generate(e) {
|
|
491
499
|
this.output = "", this.indentLevel = 0;
|
|
492
500
|
try {
|
|
493
|
-
const
|
|
494
|
-
if (
|
|
495
|
-
const
|
|
496
|
-
if (!
|
|
497
|
-
this.processModel(
|
|
498
|
-
} catch (
|
|
499
|
-
return `// Error generating text: ${
|
|
501
|
+
const t = this.domParser.parseFromString(e, "application/xml");
|
|
502
|
+
if (t.querySelector("parsererror")) throw new Error("XML Parsing Error");
|
|
503
|
+
const s = t.getElementsByTagNameNS("http://www.cellml.org/cellml/2.0#", "model")[0];
|
|
504
|
+
if (!s) throw new Error("No CellML 2.0 Model found");
|
|
505
|
+
this.processModel(s);
|
|
506
|
+
} catch (t) {
|
|
507
|
+
return `// Error generating text: ${t.message}`;
|
|
500
508
|
}
|
|
501
509
|
return this.output;
|
|
502
510
|
}
|
|
503
511
|
// --- Recursive Processors ---
|
|
504
512
|
processModel(e) {
|
|
505
|
-
const
|
|
506
|
-
this.append(`def model ${
|
|
513
|
+
const t = e.getAttribute("name") || "unnamed_model";
|
|
514
|
+
this.append(`def model ${t} as`), this.indentLevel++;
|
|
507
515
|
const i = e.getElementsByTagName("units");
|
|
508
516
|
for (let r = 0; r < i.length; r++)
|
|
509
517
|
i[r]?.parentElement === e && this.processUnits(i[r]);
|
|
510
|
-
const
|
|
511
|
-
for (let r = 0; r <
|
|
512
|
-
this.processComponent(
|
|
518
|
+
const s = e.getElementsByTagName("component");
|
|
519
|
+
for (let r = 0; r < s.length; r++)
|
|
520
|
+
this.processComponent(s[r]);
|
|
513
521
|
this.indentLevel--, this.append("enddef;");
|
|
514
522
|
}
|
|
515
523
|
processUnits(e) {
|
|
516
|
-
const
|
|
517
|
-
this.append(`def unit ${
|
|
524
|
+
const t = e?.getAttribute("name") || "unnamed_units";
|
|
525
|
+
this.append(`def unit ${t} as`), this.indentLevel++;
|
|
518
526
|
const i = e?.getElementsByTagName("unit") || [];
|
|
519
|
-
for (let
|
|
520
|
-
const r = i[
|
|
527
|
+
for (let s = 0; s < i.length; s++) {
|
|
528
|
+
const r = i[s];
|
|
521
529
|
if (!r) continue;
|
|
522
|
-
const
|
|
530
|
+
const a = r.getAttribute("prefix"), o = r.getAttribute("units"), l = r.getAttribute("exponent"), u = r.getAttribute("multiplier");
|
|
523
531
|
let p = `unit ${o}`;
|
|
524
|
-
|
|
532
|
+
a && (p += ` {prefix: ${a}}`), l && (p += ` {exponent: ${l}}`), u && (p += ` {multiplier: ${u}}`), p += ";", this.append(p);
|
|
525
533
|
}
|
|
526
534
|
this.indentLevel--, this.append("enddef;"), this.append("");
|
|
527
535
|
}
|
|
528
536
|
processComponent(e) {
|
|
529
|
-
const
|
|
530
|
-
this.append(`def comp ${
|
|
537
|
+
const t = e?.getAttribute("name") || "unnamed_component";
|
|
538
|
+
this.append(`def comp ${t} as`), this.indentLevel++;
|
|
531
539
|
const i = e?.getElementsByTagName("variable") || [];
|
|
532
540
|
for (let r = 0; r < i.length; r++)
|
|
533
541
|
this.processVariable(i[r]);
|
|
534
|
-
const
|
|
535
|
-
for (let r = 0; r <
|
|
536
|
-
this.processMath(
|
|
542
|
+
const s = e?.getElementsByTagNameNS("http://www.w3.org/1998/Math/MathML", "math") || [];
|
|
543
|
+
for (let r = 0; r < s.length; r++)
|
|
544
|
+
this.processMath(s[r]);
|
|
537
545
|
this.indentLevel--, this.append("enddef;"), this.append("");
|
|
538
546
|
}
|
|
539
547
|
processVariable(e) {
|
|
540
|
-
const
|
|
541
|
-
let
|
|
542
|
-
|
|
548
|
+
const t = e?.getAttribute("name"), i = e?.getAttribute("units"), s = e?.getAttribute("initial_value"), r = e?.getAttribute("interface");
|
|
549
|
+
let a = `var ${t}: ${i}`, o = [];
|
|
550
|
+
s && o.push(`init: ${s}`), r && o.push(`interface: ${r}`), o.length > 0 && (a += ` {${o.join(", ")}}`), a += ";", this.append(a);
|
|
543
551
|
}
|
|
544
552
|
// --- MathML Handling ---
|
|
545
553
|
processMath(e) {
|
|
546
|
-
const
|
|
547
|
-
for (const i of
|
|
554
|
+
const t = Array.from(e?.children || []);
|
|
555
|
+
for (const i of t)
|
|
548
556
|
if (i.localName === "apply" && i.firstElementChild?.localName === "eq") {
|
|
549
|
-
const r = Array.from(i.children).slice(1),
|
|
550
|
-
this.append(`${
|
|
557
|
+
const r = Array.from(i.children).slice(1), a = this.parseMathNode(r[0]), o = this.parseMathNode(r[1]);
|
|
558
|
+
this.append(`${a} = ${o};`);
|
|
551
559
|
} else {
|
|
552
560
|
const r = this.parseMathNode(i);
|
|
553
561
|
r && this.append(r + ";");
|
|
@@ -555,56 +563,64 @@ class N {
|
|
|
555
563
|
}
|
|
556
564
|
parseMathNode(e) {
|
|
557
565
|
if (!e) return "";
|
|
558
|
-
const
|
|
559
|
-
if (
|
|
566
|
+
const t = e.localName;
|
|
567
|
+
if (t === "apply")
|
|
560
568
|
return this.parseApply(e);
|
|
561
|
-
if (
|
|
569
|
+
if (t === "ci")
|
|
562
570
|
return e.textContent?.trim() || "";
|
|
563
|
-
if (
|
|
564
|
-
|
|
565
|
-
|
|
571
|
+
if (t === "cn") {
|
|
572
|
+
let i = e.textContent?.trim() || "0";
|
|
573
|
+
if (e.getAttribute("type") === "e-notation") {
|
|
574
|
+
const a = Array.from(e.childNodes), o = a.findIndex((l) => l.nodeType === 1 && l.localName === "sep");
|
|
575
|
+
if (o !== -1) {
|
|
576
|
+
const l = a.slice(0, o).map((p) => p.textContent).join("").trim(), u = a.slice(o + 1).map((p) => p.textContent).join("").trim();
|
|
577
|
+
i = `${l}e${u}`;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
const r = e.getAttributeNS(C, "units");
|
|
581
|
+
return r ? `${i} {units: ${r}}` : i;
|
|
566
582
|
} else {
|
|
567
|
-
if (
|
|
583
|
+
if (t === "piecewise")
|
|
568
584
|
return this.parsePiecewise(e);
|
|
569
|
-
if (
|
|
585
|
+
if (t === "pi")
|
|
570
586
|
return "pi";
|
|
571
|
-
if (
|
|
587
|
+
if (t === "bvar")
|
|
572
588
|
return "";
|
|
573
589
|
}
|
|
574
|
-
return console.log(`Unsupported MathML node: ${
|
|
590
|
+
return console.log(`Unsupported MathML node: ${t}`), `/* Unsupported MathML node: ${t} */`;
|
|
575
591
|
}
|
|
576
592
|
parseApply(e) {
|
|
577
|
-
const
|
|
578
|
-
if (
|
|
579
|
-
const i =
|
|
593
|
+
const t = Array.from(e.children);
|
|
594
|
+
if (t.length === 0) return "";
|
|
595
|
+
const i = t[0]?.localName, s = t.slice(1).map((r) => this.parseMathNode(r));
|
|
580
596
|
switch (i) {
|
|
581
597
|
case "plus":
|
|
582
|
-
return `(${
|
|
598
|
+
return `(${s.join(" + ")})`;
|
|
583
599
|
case "minus":
|
|
584
|
-
return
|
|
600
|
+
return s.length === 1 ? `-${s[0]}` : `(${s[0]} - ${s[1]})`;
|
|
585
601
|
case "times":
|
|
586
|
-
return `(${
|
|
602
|
+
return `(${s.join(" * ")})`;
|
|
587
603
|
case "divide":
|
|
588
|
-
return `(${
|
|
604
|
+
return `(${s[0]} / ${s[1]})`;
|
|
589
605
|
case "eq":
|
|
590
|
-
return `${
|
|
606
|
+
return `${s[0]} == ${s[1]}`;
|
|
591
607
|
case "neq":
|
|
592
|
-
return `${
|
|
608
|
+
return `${s[0]} != ${s[1]}`;
|
|
593
609
|
case "lt":
|
|
594
|
-
return `${
|
|
610
|
+
return `${s[0]} < ${s[1]}`;
|
|
595
611
|
case "leq":
|
|
596
|
-
return `${
|
|
612
|
+
return `${s[0]} <= ${s[1]}`;
|
|
597
613
|
case "gt":
|
|
598
|
-
return `${
|
|
614
|
+
return `${s[0]} > ${s[1]}`;
|
|
599
615
|
case "geq":
|
|
600
|
-
return `${
|
|
616
|
+
return `${s[0]} >= ${s[1]}`;
|
|
601
617
|
case "and":
|
|
602
|
-
return `${
|
|
618
|
+
return `${s.join(" and ")}`;
|
|
603
619
|
case "or":
|
|
604
|
-
return `${
|
|
620
|
+
return `${s.join(" or ")}`;
|
|
605
621
|
case "diff":
|
|
606
|
-
const r =
|
|
607
|
-
return `ode(${
|
|
622
|
+
const r = t.find((u) => u.localName === "bvar"), a = t.find((u) => u.localName !== "diff" && u.localName !== "bvar"), o = r?.children[0]?.textContent || "t";
|
|
623
|
+
return `ode(${a ? this.parseMathNode(a) : "unknown"}, ${o})`;
|
|
608
624
|
// Functions
|
|
609
625
|
case "sin":
|
|
610
626
|
case "cos":
|
|
@@ -612,48 +628,84 @@ class N {
|
|
|
612
628
|
case "exp":
|
|
613
629
|
case "ln":
|
|
614
630
|
case "log":
|
|
615
|
-
return `${i}(${
|
|
631
|
+
return `${i}(${s[0]})`;
|
|
616
632
|
case "root":
|
|
617
|
-
return `sqrt(${
|
|
633
|
+
return `sqrt(${s[0]})`;
|
|
618
634
|
default:
|
|
619
|
-
return `${i}(${
|
|
635
|
+
return `${i}(${s.join(", ")})`;
|
|
620
636
|
}
|
|
621
637
|
}
|
|
622
638
|
parsePiecewise(e) {
|
|
623
|
-
let
|
|
624
|
-
return Array.from(e?.children || []).forEach((
|
|
625
|
-
if (
|
|
626
|
-
const r = this.parseMathNode(
|
|
627
|
-
|
|
628
|
-
} else if (
|
|
629
|
-
const r = this.parseMathNode(
|
|
630
|
-
|
|
639
|
+
let t = [];
|
|
640
|
+
return Array.from(e?.children || []).forEach((s) => {
|
|
641
|
+
if (s.localName === "piece") {
|
|
642
|
+
const r = this.parseMathNode(s.children[0]), a = this.parseMathNode(s.children[1]);
|
|
643
|
+
t.push(`${this.standardIndent}case ${a}: ${r};`);
|
|
644
|
+
} else if (s.localName === "otherwise") {
|
|
645
|
+
const r = this.parseMathNode(s.children[0]);
|
|
646
|
+
t.push(`${this.standardIndent}otherwise: ${r};`);
|
|
631
647
|
}
|
|
632
648
|
}), `sel
|
|
633
|
-
${this.indent()}${
|
|
649
|
+
${this.indent()}${t.join(`
|
|
634
650
|
${this.indent()}`)}
|
|
635
651
|
${this.indent()}endsel`;
|
|
636
652
|
}
|
|
637
653
|
}
|
|
638
|
-
|
|
654
|
+
const $ = {
|
|
655
|
+
atomic: 100,
|
|
656
|
+
// Identifiers, numbers
|
|
657
|
+
func: 90,
|
|
658
|
+
// sin, cos, exp (visually self-contained)
|
|
659
|
+
power: 80,
|
|
660
|
+
// ^
|
|
661
|
+
times: 70,
|
|
662
|
+
// *
|
|
663
|
+
divide: 70,
|
|
664
|
+
// / (usually self-contained in \frac, but good to have)
|
|
665
|
+
plus: 60,
|
|
666
|
+
// +
|
|
667
|
+
minus: 60,
|
|
668
|
+
// -
|
|
669
|
+
rel: 50,
|
|
670
|
+
// =, <, >
|
|
671
|
+
unknown: 0
|
|
672
|
+
};
|
|
673
|
+
class O {
|
|
639
674
|
convert(e) {
|
|
640
675
|
if (!e) return "";
|
|
641
676
|
if (e.localName === "math")
|
|
642
|
-
return Array.from(e.children).map((
|
|
677
|
+
return Array.from(e.children).map((t) => this.convert(t)).join(`
|
|
643
678
|
`);
|
|
644
679
|
if (e.localName === "apply" && e.firstElementChild?.localName === "eq") {
|
|
645
|
-
const
|
|
646
|
-
return `${i} = ${
|
|
680
|
+
const t = Array.from(e.children), i = this.parseNode(t[1]), s = this.parseNode(t[2]);
|
|
681
|
+
return `${i} = ${s}`;
|
|
647
682
|
}
|
|
648
683
|
return this.parseNode(e);
|
|
649
684
|
}
|
|
650
685
|
ignoreTag(e) {
|
|
651
686
|
return ["bvar"].includes(e);
|
|
652
687
|
}
|
|
653
|
-
parseNode(e) {
|
|
688
|
+
parseNode(e, t = 0) {
|
|
654
689
|
if (!e) return "";
|
|
655
|
-
const
|
|
656
|
-
|
|
690
|
+
const i = e.localName;
|
|
691
|
+
if (i === "apply") return this.parseApply(e, t);
|
|
692
|
+
if (i === "ci") return this.parseIdentifier(e.textContent || "");
|
|
693
|
+
if (i === "cn") {
|
|
694
|
+
if (e.getAttribute("type") === "e-notation") {
|
|
695
|
+
const a = Array.from(e.childNodes), o = a.findIndex((l) => l.nodeType === 1 && l.localName === "sep");
|
|
696
|
+
if (o !== -1) {
|
|
697
|
+
const l = a.slice(0, o).map((p) => p.textContent).join("").trim(), u = a.slice(o + 1).map((p) => p.textContent).join("").trim();
|
|
698
|
+
return `${l} \\times 10^{${u}}`;
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
const r = e.textContent?.trim() || "0";
|
|
702
|
+
if (r.match(/^-?[\d.]+[eE][+-]?\d+$/)) {
|
|
703
|
+
const [a, o] = r.split(/[eE]/);
|
|
704
|
+
return `${a} \\times 10^{${o}}`;
|
|
705
|
+
}
|
|
706
|
+
return r;
|
|
707
|
+
}
|
|
708
|
+
return i === "piecewise" ? this.parsePiecewise(e) : i === "pi" ? "\\pi" : (this.ignoreTag(i) || console.warn(`Unsupported MathML node: ${i}`), "");
|
|
657
709
|
}
|
|
658
710
|
escapeGreek(e) {
|
|
659
711
|
return [
|
|
@@ -691,62 +743,84 @@ class C {
|
|
|
691
743
|
parseIdentifier(e) {
|
|
692
744
|
if (!e.includes("_"))
|
|
693
745
|
return this.escapeGreek(e);
|
|
694
|
-
const
|
|
695
|
-
|
|
746
|
+
const t = e.split("_"), i = this.escapeGreek(t[0] || ""), s = [];
|
|
747
|
+
t[1] && s.push(t[1]), t.length > 4 && s.push(...t.slice(4));
|
|
696
748
|
let r = "";
|
|
697
|
-
|
|
698
|
-
|
|
749
|
+
t.length === 3 && (t[2] || []).length === 1 ? s.push(this.escapeGreek(t[2] || "")) : t[2] && (r = this.escapeGreek(t[2]), t[3] && (r += `_{${this.escapeGreek(t[3])}}`)), s.forEach((l, u) => {
|
|
750
|
+
s[u] = this.escapeGreek(l);
|
|
699
751
|
});
|
|
700
|
-
const
|
|
752
|
+
const a = s.join(",");
|
|
701
753
|
let o = i;
|
|
702
|
-
return
|
|
754
|
+
return a && (o += `_{${a}}`), r && (o += `^{${r}}`), o;
|
|
703
755
|
}
|
|
704
|
-
parseApply(e) {
|
|
705
|
-
const
|
|
706
|
-
|
|
756
|
+
parseApply(e, t) {
|
|
757
|
+
const i = Array.from(e?.children || []), s = i[0]?.localName || "unknown", r = $[s] || $.func, a = i.slice(1).map((l, u) => {
|
|
758
|
+
let p = r;
|
|
759
|
+
return ["divide", "diff", "root", "sqrt", "sin", "cos", "tan", "exp", "ln", "log"].includes(s) ? p = 0 : s === "minus" && u === 1 && (p = r + 1), this.parseNode(l, p);
|
|
760
|
+
});
|
|
761
|
+
let o = "";
|
|
762
|
+
switch (s) {
|
|
707
763
|
case "plus":
|
|
708
|
-
|
|
764
|
+
o = a.join(" + ");
|
|
765
|
+
break;
|
|
709
766
|
case "minus":
|
|
710
|
-
|
|
767
|
+
o = a.length === 1 ? `-${a[0]}` : `${a[0]} - ${a[1]}`;
|
|
768
|
+
break;
|
|
711
769
|
case "times":
|
|
712
|
-
|
|
770
|
+
o = a.join(" \\cdot ");
|
|
771
|
+
break;
|
|
713
772
|
case "divide":
|
|
714
|
-
|
|
773
|
+
o = `\\frac{${a[0]}}{${a[1]}}`;
|
|
774
|
+
break;
|
|
715
775
|
case "eq":
|
|
716
|
-
|
|
776
|
+
o = `${a[0]} == ${a[1]}`;
|
|
777
|
+
break;
|
|
717
778
|
case "neq":
|
|
718
|
-
|
|
779
|
+
o = `${a[0]} \\neq ${a[1]}`;
|
|
780
|
+
break;
|
|
719
781
|
case "lt":
|
|
720
|
-
|
|
782
|
+
o = `${a[0]} < ${a[1]}`;
|
|
783
|
+
break;
|
|
721
784
|
case "leq":
|
|
722
|
-
|
|
785
|
+
o = `${a[0]} \\leq ${a[1]}`;
|
|
786
|
+
break;
|
|
723
787
|
case "gt":
|
|
724
|
-
|
|
788
|
+
o = `${a[0]} > ${a[1]}`;
|
|
789
|
+
break;
|
|
725
790
|
case "geq":
|
|
726
|
-
|
|
791
|
+
o = `${a[0]} \\geq ${a[1]}`;
|
|
792
|
+
break;
|
|
727
793
|
case "and":
|
|
728
|
-
|
|
794
|
+
o = a.join(" \\land ");
|
|
795
|
+
break;
|
|
729
796
|
case "or":
|
|
730
|
-
|
|
797
|
+
o = a.join(" \\lor ");
|
|
798
|
+
break;
|
|
731
799
|
case "power":
|
|
732
|
-
const
|
|
733
|
-
|
|
800
|
+
const l = i[1], u = a[0] || "", p = a[1];
|
|
801
|
+
o = l?.localName === "ci" || l?.localName === "cn" && !u.trim().startsWith("-") ? `{${u}}^{${p}}` : `\\left({${u}}\\right)^{${p}}`;
|
|
802
|
+
break;
|
|
734
803
|
case "root":
|
|
735
804
|
case "sqrt":
|
|
736
|
-
|
|
737
|
-
|
|
805
|
+
o = `\\sqrt{${a[0]}}`;
|
|
806
|
+
break;
|
|
738
807
|
case "diff":
|
|
739
|
-
const
|
|
740
|
-
|
|
808
|
+
const f = i.find((x) => x.localName === "bvar"), w = i.find((x) => x.localName !== "diff" && x.localName !== "bvar"), g = f ? this.parseNode(f.firstElementChild) : "x";
|
|
809
|
+
o = `\\frac{d${w ? this.parseNode(w) : "y"}}{d${g}}`;
|
|
810
|
+
break;
|
|
741
811
|
// Trig & Funcs
|
|
742
812
|
case "exp":
|
|
743
|
-
|
|
813
|
+
o = `e^{${a[0]}}`;
|
|
814
|
+
break;
|
|
744
815
|
case "abs":
|
|
745
|
-
|
|
816
|
+
o = `\\left|${a[0]}\\right|`;
|
|
817
|
+
break;
|
|
746
818
|
case "floor":
|
|
747
|
-
|
|
819
|
+
o = `\\lfloor ${a[0]} \\rfloor`;
|
|
820
|
+
break;
|
|
748
821
|
case "ceil":
|
|
749
|
-
|
|
822
|
+
o = `\\lceil ${a[0]} \\rceil`;
|
|
823
|
+
break;
|
|
750
824
|
case "cos":
|
|
751
825
|
case "cosh":
|
|
752
826
|
case "log10":
|
|
@@ -758,26 +832,29 @@ class C {
|
|
|
758
832
|
case "sinh":
|
|
759
833
|
case "tan":
|
|
760
834
|
case "tanh":
|
|
761
|
-
|
|
835
|
+
o = `\\${s}\\left(${a[0]}\\right)`;
|
|
836
|
+
break;
|
|
762
837
|
default:
|
|
763
|
-
|
|
838
|
+
console.log(`Unsupported MathML operator: ${s}`), o = `\\text{${s}}(${a.join(", ")})`;
|
|
839
|
+
break;
|
|
764
840
|
}
|
|
841
|
+
return r < t && (o = `\\left(${o}\\right)`), o;
|
|
765
842
|
}
|
|
766
843
|
parsePiecewise(e) {
|
|
767
|
-
let
|
|
768
|
-
return Array.from(e.children).forEach((
|
|
769
|
-
if (
|
|
770
|
-
const r = this.parseNode(
|
|
771
|
-
|
|
772
|
-
} else if (
|
|
773
|
-
const r = this.parseNode(
|
|
774
|
-
|
|
844
|
+
let t = "";
|
|
845
|
+
return Array.from(e.children).forEach((s) => {
|
|
846
|
+
if (s.localName === "piece") {
|
|
847
|
+
const r = this.parseNode(s.children[0]), a = this.parseNode(s.children[1]);
|
|
848
|
+
t += `${r} & \\text{if } ${a} \\\\ `;
|
|
849
|
+
} else if (s.localName === "otherwise") {
|
|
850
|
+
const r = this.parseNode(s.children[0]);
|
|
851
|
+
t += `${r} & \\text{otherwise}`;
|
|
775
852
|
}
|
|
776
|
-
}), `\\begin{cases} ${
|
|
853
|
+
}), `\\begin{cases} ${t} \\end{cases}`;
|
|
777
854
|
}
|
|
778
855
|
}
|
|
779
856
|
export {
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
857
|
+
O as CellMLLatexGenerator,
|
|
858
|
+
k as CellMLTextGenerator,
|
|
859
|
+
E as CellMLTextParser
|
|
783
860
|
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
(function(m,n){typeof exports=="object"&&typeof module<"u"?n(exports):typeof define=="function"&&define.amd?define(["exports"],n):(m=typeof globalThis<"u"?globalThis:m||self,n(m.CellMLTextEditor={}))})(this,(function(m){"use strict";var n=(
|
|
2
|
-
`&&e++,this.pos++;else if(
|
|
3
|
-
`;)this.pos++;else break}return e}getKeywordType(e){switch(e){case"def":return 5;case"model":return 6;case"comp":return 7;case"enddef":return 8;case"as":return 9;case"var":return 10;case"unit":return 11;case"sel":return 12;case"case":return 13;case"otherwise":return 14;case"endsel":return 15;case"and":return 34;case"or":return 35;default:return 2}}}const f="http://www.cellml.org/cellml/2.0#",
|
|
4
|
-
`+this.serialize(
|
|
5
|
-
`;return
|
|
6
|
-
`)}),p+=`${i}</${
|
|
7
|
-
`:"")}generate(e){this.output="",this.indentLevel=0;try{const
|
|
8
|
-
${this.indent()}${
|
|
1
|
+
(function(m,n){typeof exports=="object"&&typeof module<"u"?n(exports):typeof define=="function"&&define.amd?define(["exports"],n):(m=typeof globalThis<"u"?globalThis:m||self,n(m.CellMLTextEditor={}))})(this,(function(m){"use strict";var n=(c=>(c[c.Unknown=0]="Unknown",c[c.EOF=1]="EOF",c[c.Identifier=2]="Identifier",c[c.Number=3]="Number",c[c.String=4]="String",c[c.KwDef=5]="KwDef",c[c.KwModel=6]="KwModel",c[c.KwComp=7]="KwComp",c[c.KwEndDef=8]="KwEndDef",c[c.KwAs=9]="KwAs",c[c.KwVar=10]="KwVar",c[c.KwUnit=11]="KwUnit",c[c.KwSel=12]="KwSel",c[c.KwCase=13]="KwCase",c[c.KwOtherwise=14]="KwOtherwise",c[c.KwEndSel=15]="KwEndSel",c[c.OpAss=16]="OpAss",c[c.OpPlus=17]="OpPlus",c[c.OpMinus=18]="OpMinus",c[c.OpTimes=19]="OpTimes",c[c.OpDivide=20]="OpDivide",c[c.OpComma=21]="OpComma",c[c.Colon=22]="Colon",c[c.SemiColon=23]="SemiColon",c[c.LParam=24]="LParam",c[c.RParam=25]="RParam",c[c.LBrace=26]="LBrace",c[c.RBrace=27]="RBrace",c[c.OpEq=28]="OpEq",c[c.OpNe=29]="OpNe",c[c.OpLt=30]="OpLt",c[c.OpLe=31]="OpLe",c[c.OpGt=32]="OpGt",c[c.OpGe=33]="OpGe",c[c.OpAnd=34]="OpAnd",c[c.OpOr=35]="OpOr",c))(n||{});class N{input;pos=0;line=1;length;currentToken=1;currentValue="";constructor(e){this.input=e,this.length=e.length,this.nextToken()}get token(){return this.currentToken}get value(){return this.currentValue}nextToken(){const e=this.skipWhitespace();if(this.line+=e,this.pos>=this.length){this.currentToken=1;return}const t=this.input[this.pos];if(/[a-zA-Z_]/.test(t||"")){let i=this.pos;for(;this.pos<this.length&&/[a-zA-Z0-9_]/.test(this.input[this.pos]||"");)this.pos++;const s=this.input.slice(i,this.pos);this.currentValue=s,this.currentToken=this.getKeywordType(s);return}if(/[0-9]/.test(t||"")||t==="."&&/[0-9]/.test(this.input[this.pos+1]||"")){let i=this.pos;for(;this.pos<this.length&&/[0-9]/.test(this.input[this.pos]||"");)this.pos++;if(this.input[this.pos]===".")for(this.pos++;this.pos<this.length&&/[0-9]/.test(this.input[this.pos]||"");)this.pos++;if(this.input[this.pos]==="e"||this.input[this.pos]==="E")for(this.pos++,(this.input[this.pos]==="+"||this.input[this.pos]==="-")&&this.pos++;this.pos<this.length&&/[0-9]/.test(this.input[this.pos]||"");)this.pos++;this.currentValue=this.input.slice(i,this.pos),this.currentToken=3;return}switch(this.pos++,this.currentValue=t||"",t){case"=":this.input[this.pos]==="="?(this.pos++,this.currentValue="==",this.currentToken=28):this.currentToken=16;break;case"!":this.input[this.pos]==="="?(this.pos++,this.currentValue="!=",this.currentToken=29):(console.warn(`Unexpected character '!' at pos ${this.pos}`),this.currentToken=0);break;case"<":this.input[this.pos]==="="?(this.pos++,this.currentValue="<=",this.currentToken=31):this.currentToken=30;break;case">":this.input[this.pos]==="="?(this.pos++,this.currentValue=">=",this.currentToken=33):this.currentToken=32;break;case"+":this.currentToken=17;break;case"-":this.currentToken=18;break;case"*":this.currentToken=19;break;case"/":this.currentToken=20;break;case"(":this.currentToken=24;break;case")":this.currentToken=25;break;case"{":this.currentToken=26;break;case"}":this.currentToken=27;break;case":":this.currentToken=22;break;case";":this.currentToken=23;break;case",":this.currentToken=21;break;default:console.warn("Unknown char:",t),this.currentToken=0}}getLine(){return this.line}skipWhitespace(){let e=0;for(;this.pos<this.length;){const t=this.input[this.pos];if(/\s/.test(t||""))t===`
|
|
2
|
+
`&&e++,this.pos++;else if(t==="/"&&this.input[this.pos+1]==="/")for(this.pos+=2;this.pos<this.length&&this.input[this.pos]!==`
|
|
3
|
+
`;)this.pos++;else break}return e}getKeywordType(e){switch(e){case"def":return 5;case"model":return 6;case"comp":return 7;case"enddef":return 8;case"as":return 9;case"var":return 10;case"unit":return 11;case"sel":return 12;case"case":return 13;case"otherwise":return 14;case"endsel":return 15;case"and":return 34;case"or":return 35;default:return 2}}}const f="http://www.cellml.org/cellml/2.0#",l="http://www.w3.org/1998/Math/MathML";class C{scanner;doc;sourceLineAttr;constructor(e={}){this.sourceLineAttr=e.sourceLineAttribute===void 0?"data-source-location":e.sourceLineAttribute}parse(e){this.scanner=new N(e),this.doc=document.implementation.createDocument(f,"model",null);try{const t=this.doc.documentElement;for(this.expect(n.KwDef),this.expect(n.KwModel),this.scanner.token===n.Identifier&&(t.setAttribute("name",this.scanner.value),this.scanner.nextToken()),this.expect(n.KwAs);this.scanner.token!==n.KwEndDef&&this.scanner.token!==n.EOF;)this.scanner.token===n.KwDef?this.parseBlock(t):this.scanner.nextToken();return this.expect(n.KwEndDef),this.expect(n.SemiColon),{xml:`<?xml version="1.0" encoding="UTF-8"?>
|
|
4
|
+
`+this.serialize(t),errors:[]}}catch(t){return{xml:null,errors:[{line:this.scanner.getLine(),message:t.message||"Unknown parsing error"}]}}}parseBlock(e){if(this.expect(n.KwDef),this.scanner.token===n.KwComp)this.parseComponent(e);else if(this.scanner.token===n.KwUnit)this.parseUnit(e);else throw new Error("Expected 'comp' or 'unit' after 'def'")}parseComponent(e){this.expect(n.KwComp);const t=this.expectValue(n.Identifier);this.expect(n.KwAs);const i=this.doc.createElementNS(f,"component");for(i.setAttribute("name",t),e.appendChild(i);this.scanner.token!==n.KwEndDef&&this.scanner.token!==n.EOF;)this.scanner.token===n.KwVar?this.parseVariable(i):this.scanner.token===n.Identifier||this.scanner.token===n.KwSel?this.parseMathEquation(i):this.scanner.nextToken();this.expect(n.KwEndDef),this.expect(n.SemiColon)}parseVariable(e){this.expect(n.KwVar);const t=this.expectValue(n.Identifier);this.expect(n.Colon);const i=this.expectValue(n.Identifier),s=this.doc.createElementNS(f,"variable");if(s.setAttribute("name",t),s.setAttribute("units",i),this.scanner.token===n.LBrace){for(this.scanner.nextToken();this.scanner.token!==n.RBrace&&this.scanner.token!==n.EOF;){const r=this.expectValue(n.Identifier);this.expect(n.Colon);let a="";this.scanner.token===n.OpMinus?(this.scanner.nextToken(),a="-"+this.expectValue(n.Number)):this.scanner.token===n.Number?a=this.expectValue(n.Number):a=this.expectValue(n.Identifier),r==="init"?s.setAttribute("initial_value",a):r==="interface"&&s.setAttribute("interface",a),this.scanner.token===n.OpComma&&this.scanner.nextToken()}this.expect(n.RBrace)}this.expect(n.SemiColon),e.appendChild(s)}parseUnit(e){for(this.expect(n.KwUnit);this.scanner.token!==n.KwEndDef&&this.scanner.token!==n.EOF;)this.scanner.nextToken();this.expect(n.KwEndDef),this.expect(n.SemiColon)}parseMathEquation(e){const t=this.scanner.getLine();let i=e.getElementsByTagNameNS(l,"math")[0];i||(i=this.doc.createElementNS(l,"math"),e.appendChild(i));const s=this.doc.createElementNS(l,"apply"),r=this.doc.createElementNS(l,"eq");s.appendChild(r);const a=this.parseExpression();this.expect(n.OpAss);const o=this.parseExpression(),h=this.scanner.getLine();this.sourceLineAttr&&s.setAttribute(this.sourceLineAttr,`${t.toString()}`+(h!==t?`-${h.toString()}`:"")),s.appendChild(a),s.appendChild(o),i.appendChild(s),this.expect(n.SemiColon)}parseCondition(){let e=this.parseComparison();for(;this.scanner.token===n.OpAnd||this.scanner.token===n.OpOr;){const t=this.scanner.token;this.scanner.nextToken();const i=this.parseComparison(),s=this.doc.createElementNS(l,"apply"),r=this.doc.createElementNS(l,t===n.OpAnd?"and":"or");s.appendChild(r),s.appendChild(e),s.appendChild(i),e=s}return e}isComparisonToken(e){return[n.OpEq,n.OpNe,n.OpLt,n.OpLe,n.OpGt,n.OpGe].includes(e)}parseComparison(){let e=this.parseExpression();if(this.isComparisonToken(this.scanner.token)){const t=this.scanner.token;this.scanner.nextToken();const i=this.parseExpression(),s=this.doc.createElementNS(l,"apply");let r="";switch(t){case n.OpEq:r="eq";break;case n.OpNe:r="neq";break;case n.OpLt:r="lt";break;case n.OpLe:r="leq";break;case n.OpGt:r="gt";break;case n.OpGe:r="geq";break;case n.OpAnd:r="and";break}const a=this.doc.createElementNS(l,r);return s.appendChild(a),s.appendChild(e),s.appendChild(i),s}return e}isMathMLApply(e,t){if(e.localName!=="apply")return!1;const i=e.firstElementChild;return i?i.localName===t:!1}parseExpression(){let e=this.parseTerm();for(;this.scanner.token===n.OpPlus||this.scanner.token===n.OpMinus;){const t=this.scanner.token;this.scanner.nextToken();const i=this.parseTerm();if(t===n.OpPlus&&this.isMathMLApply(e,"plus"))e.appendChild(i);else{const s=this.doc.createElementNS(l,"apply"),r=this.doc.createElementNS(l,t===n.OpPlus?"plus":"minus");s.appendChild(r),s.appendChild(e),s.appendChild(i),e=s}}return e}parseTerm(){let e=this.parseFactor();for(;this.scanner.token===n.OpTimes||this.scanner.token===n.OpDivide;){const t=this.scanner.token;this.scanner.nextToken();const i=this.parseFactor();if(t===n.OpTimes&&this.isMathMLApply(e,"times"))e.appendChild(i);else{const s=this.doc.createElementNS(l,"apply"),r=this.doc.createElementNS(l,t===n.OpTimes?"times":"divide");s.appendChild(r),s.appendChild(e),s.appendChild(i),e=s}}return e}createMathMLConstant(e){const t={pi:"pi",e:"exponentiale",inf:"infinity",infinity:"infinity",NaN:"notanumber",true:"true",false:"false"};return t.hasOwnProperty(e)?this.doc.createElementNS(l,t[e]||""):null}parseFactor(){if(this.scanner.token===n.OpMinus){this.scanner.nextToken();const e=this.parseFactor(),t=this.doc.createElementNS(l,"apply"),i=this.doc.createElementNS(l,"minus");return t.appendChild(i),t.appendChild(e),t}if(this.scanner.token===n.Number){const e=this.scanner.value;this.scanner.nextToken();const t=this.doc.createElementNS(l,"cn");if(this.scanner.token===n.LBrace){if(this.scanner.nextToken(),this.scanner.value==="units"){this.scanner.nextToken(),this.expect(n.Colon);const i=this.expectValue(n.Identifier);t.setAttributeNS(f,"cellml:units",i)}for(;this.scanner.token!==n.RBrace&&this.scanner.token!==n.EOF;)this.scanner.nextToken();this.expect(n.RBrace)}if(e.match(/^-?[\d.]+[eE][+-]?\d+$/)){t.setAttribute("type","e-notation");const i=this.doc.createElementNS(l,"sep"),[s,r]=e.split(/[eE]/);t.appendChild(this.doc.createTextNode(s||"1")),t.appendChild(i),t.appendChild(this.doc.createTextNode(r||"0"))}else t.textContent=e;return t}else if(this.scanner.token===n.Identifier){const e=this.scanner.value;if(this.scanner.nextToken(),this.scanner.token===n.LParam)return this.parseFunctionCall(e);const t=this.createMathMLConstant(e);if(t)return t;const i=this.doc.createElementNS(l,"ci");return i.textContent=e,i}else if(this.scanner.token===n.LParam){this.scanner.nextToken();const e=this.parseExpression();return this.expect(n.RParam),e}else if(this.scanner.token===n.KwSel)return this.parsePiecewise();throw new Error(`Unexpected token in math: ${this.scanner.value}`)}parsePiecewise(){const e=this.doc.createElementNS(l,"piecewise");for(this.expect(n.KwSel);this.scanner.token===n.KwCase;){this.expect(n.KwCase);const t=this.parseCondition();this.expect(n.Colon);const i=this.parseExpression();this.expect(n.SemiColon);const s=this.doc.createElementNS(l,"piece");s.appendChild(i),s.appendChild(t),e.appendChild(s)}if(this.scanner.token===n.KwOtherwise){this.expect(n.KwOtherwise),this.expect(n.Colon);const t=this.parseExpression();this.expect(n.SemiColon);const i=this.doc.createElementNS(l,"otherwise");i.appendChild(t),e.appendChild(i)}return this.expect(n.KwEndSel),e}parseFunctionCall(e){if(this.expect(n.LParam),e==="ode"){const s=this.parseExpression();this.expect(n.OpComma);const r=this.parseExpression();this.expect(n.RParam);const a=this.doc.createElementNS(l,"apply");a.appendChild(this.doc.createElementNS(l,"diff"));const o=this.doc.createElementNS(l,"bvar");return o.appendChild(r),a.appendChild(o),a.appendChild(s),a}const t=this.doc.createElementNS(l,"apply"),i=this.doc.createElementNS(l,e);if(t.appendChild(i),this.scanner.token!==n.RParam)do this.scanner.token===n.OpComma&&this.scanner.nextToken(),t.appendChild(this.parseExpression());while(this.scanner.token===n.OpComma);return this.expect(n.RParam),t}expect(e){if(this.scanner.token!==e)throw new Error(`Syntax Error: Expected ${n[e]} but found '${this.scanner.value}'`);this.scanner.nextToken()}expectValue(e){if(this.scanner.token!==e)throw new Error(`Expected value of type ${n[e]}, got ${this.scanner.token}`);const t=this.scanner.value;return this.scanner.nextToken(),t}usesCellMLNamespace(e){const t=e.getElementsByTagName("*");for(let i=0;i<t.length;i++){const s=t[i];for(let r=0;s&&r<s.attributes.length;r++){const a=s.attributes[r];if(a&&a.namespaceURI===f)return!0}}return!1}getPrefixForNamespace(e,t){const i="http://www.w3.org/2000/xmlns/";for(let s=0;s<e.attributes.length;s++){const r=e.attributes[s];if(r&&r.namespaceURI===i&&r.value===t)return r.localName==="xmlns"?"":r.localName}return null}serialize(e,t=0){const i=" ".repeat(t),s=e.tagName,r=e.localName;let a="";r==="model"&&!e.hasAttribute("xmlns")&&(a+=` xmlns="${f}"`),r==="math"&&!e.hasAttribute("xmlns")&&(a+=` xmlns="${l}"`,this.usesCellMLNamespace(e)&&!e.hasAttribute("xmlns:cellml")&&this.getPrefixForNamespace(e,f)===null&&(a+=` xmlns:cellml="${f}"`));for(let d=0;d<e.attributes.length;d++){const x=e.attributes[d];if(x){if(this.sourceLineAttr&&x.name===this.sourceLineAttr)continue;a+=` ${x.name}="${x.value}"`}}const o=Array.from(e.childNodes),h=o.some(d=>d.nodeType===1),u=e.textContent?.trim();if(o.length===0&&!u)return`${i}<${s}${a}/>`;if(h){if(e.tagName==="cn"&&o.length===3)return`${i}<${s}${a}>${o[0]?.textContent}<sep/>${o[2]?.textContent}</${s}>`}else return`${i}<${s}${a}>${u}</${s}>`;let p=`${i}<${s}${a}>
|
|
5
|
+
`;return o.forEach(d=>{d.nodeType===1&&(p+=this.serialize(d,t+1)+`
|
|
6
|
+
`)}),p+=`${i}</${s}>`,p}}const b="http://www.cellml.org/cellml/2.0#";class E{output="";indentLevel=0;domParser;standardIndent=" ";constructor(){this.domParser=new DOMParser}indent(){return this.standardIndent.repeat(this.indentLevel)}append(e,t=!0){this.output+=(t?this.indent():"")+e+(t?`
|
|
7
|
+
`:"")}generate(e){this.output="",this.indentLevel=0;try{const t=this.domParser.parseFromString(e,"application/xml");if(t.querySelector("parsererror"))throw new Error("XML Parsing Error");const s=t.getElementsByTagNameNS("http://www.cellml.org/cellml/2.0#","model")[0];if(!s)throw new Error("No CellML 2.0 Model found");this.processModel(s)}catch(t){return`// Error generating text: ${t.message}`}return this.output}processModel(e){const t=e.getAttribute("name")||"unnamed_model";this.append(`def model ${t} as`),this.indentLevel++;const i=e.getElementsByTagName("units");for(let r=0;r<i.length;r++)i[r]?.parentElement===e&&this.processUnits(i[r]);const s=e.getElementsByTagName("component");for(let r=0;r<s.length;r++)this.processComponent(s[r]);this.indentLevel--,this.append("enddef;")}processUnits(e){const t=e?.getAttribute("name")||"unnamed_units";this.append(`def unit ${t} as`),this.indentLevel++;const i=e?.getElementsByTagName("unit")||[];for(let s=0;s<i.length;s++){const r=i[s];if(!r)continue;const a=r.getAttribute("prefix"),o=r.getAttribute("units"),h=r.getAttribute("exponent"),u=r.getAttribute("multiplier");let p=`unit ${o}`;a&&(p+=` {prefix: ${a}}`),h&&(p+=` {exponent: ${h}}`),u&&(p+=` {multiplier: ${u}}`),p+=";",this.append(p)}this.indentLevel--,this.append("enddef;"),this.append("")}processComponent(e){const t=e?.getAttribute("name")||"unnamed_component";this.append(`def comp ${t} as`),this.indentLevel++;const i=e?.getElementsByTagName("variable")||[];for(let r=0;r<i.length;r++)this.processVariable(i[r]);const s=e?.getElementsByTagNameNS("http://www.w3.org/1998/Math/MathML","math")||[];for(let r=0;r<s.length;r++)this.processMath(s[r]);this.indentLevel--,this.append("enddef;"),this.append("")}processVariable(e){const t=e?.getAttribute("name"),i=e?.getAttribute("units"),s=e?.getAttribute("initial_value"),r=e?.getAttribute("interface");let a=`var ${t}: ${i}`,o=[];s&&o.push(`init: ${s}`),r&&o.push(`interface: ${r}`),o.length>0&&(a+=` {${o.join(", ")}}`),a+=";",this.append(a)}processMath(e){const t=Array.from(e?.children||[]);for(const i of t)if(i.localName==="apply"&&i.firstElementChild?.localName==="eq"){const r=Array.from(i.children).slice(1),a=this.parseMathNode(r[0]),o=this.parseMathNode(r[1]);this.append(`${a} = ${o};`)}else{const r=this.parseMathNode(i);r&&this.append(r+";")}}parseMathNode(e){if(!e)return"";const t=e.localName;if(t==="apply")return this.parseApply(e);if(t==="ci")return e.textContent?.trim()||"";if(t==="cn"){let i=e.textContent?.trim()||"0";if(e.getAttribute("type")==="e-notation"){const a=Array.from(e.childNodes),o=a.findIndex(h=>h.nodeType===1&&h.localName==="sep");if(o!==-1){const h=a.slice(0,o).map(p=>p.textContent).join("").trim(),u=a.slice(o+1).map(p=>p.textContent).join("").trim();i=`${h}e${u}`}}const r=e.getAttributeNS(b,"units");return r?`${i} {units: ${r}}`:i}else{if(t==="piecewise")return this.parsePiecewise(e);if(t==="pi")return"pi";if(t==="bvar")return""}return console.log(`Unsupported MathML node: ${t}`),`/* Unsupported MathML node: ${t} */`}parseApply(e){const t=Array.from(e.children);if(t.length===0)return"";const i=t[0]?.localName,s=t.slice(1).map(r=>this.parseMathNode(r));switch(i){case"plus":return`(${s.join(" + ")})`;case"minus":return s.length===1?`-${s[0]}`:`(${s[0]} - ${s[1]})`;case"times":return`(${s.join(" * ")})`;case"divide":return`(${s[0]} / ${s[1]})`;case"eq":return`${s[0]} == ${s[1]}`;case"neq":return`${s[0]} != ${s[1]}`;case"lt":return`${s[0]} < ${s[1]}`;case"leq":return`${s[0]} <= ${s[1]}`;case"gt":return`${s[0]} > ${s[1]}`;case"geq":return`${s[0]} >= ${s[1]}`;case"and":return`${s.join(" and ")}`;case"or":return`${s.join(" or ")}`;case"diff":const r=t.find(u=>u.localName==="bvar"),a=t.find(u=>u.localName!=="diff"&&u.localName!=="bvar"),o=r?.children[0]?.textContent||"t";return`ode(${a?this.parseMathNode(a):"unknown"}, ${o})`;case"sin":case"cos":case"tan":case"exp":case"ln":case"log":return`${i}(${s[0]})`;case"root":return`sqrt(${s[0]})`;default:return`${i}(${s.join(", ")})`}}parsePiecewise(e){let t=[];return Array.from(e?.children||[]).forEach(s=>{if(s.localName==="piece"){const r=this.parseMathNode(s.children[0]),a=this.parseMathNode(s.children[1]);t.push(`${this.standardIndent}case ${a}: ${r};`)}else if(s.localName==="otherwise"){const r=this.parseMathNode(s.children[0]);t.push(`${this.standardIndent}otherwise: ${r};`)}}),`sel
|
|
8
|
+
${this.indent()}${t.join(`
|
|
9
9
|
${this.indent()}`)}
|
|
10
|
-
${this.indent()}endsel`}}class
|
|
11
|
-
`);if(e.localName==="apply"&&e.firstElementChild?.localName==="eq"){const
|
|
10
|
+
${this.indent()}endsel`}}const $={atomic:100,func:90,power:80,times:70,divide:70,plus:60,minus:60,rel:50,unknown:0};class k{convert(e){if(!e)return"";if(e.localName==="math")return Array.from(e.children).map(t=>this.convert(t)).join(`
|
|
11
|
+
`);if(e.localName==="apply"&&e.firstElementChild?.localName==="eq"){const t=Array.from(e.children),i=this.parseNode(t[1]),s=this.parseNode(t[2]);return`${i} = ${s}`}return this.parseNode(e)}ignoreTag(e){return["bvar"].includes(e)}parseNode(e,t=0){if(!e)return"";const i=e.localName;if(i==="apply")return this.parseApply(e,t);if(i==="ci")return this.parseIdentifier(e.textContent||"");if(i==="cn"){if(e.getAttribute("type")==="e-notation"){const a=Array.from(e.childNodes),o=a.findIndex(h=>h.nodeType===1&&h.localName==="sep");if(o!==-1){const h=a.slice(0,o).map(p=>p.textContent).join("").trim(),u=a.slice(o+1).map(p=>p.textContent).join("").trim();return`${h} \\times 10^{${u}}`}}const r=e.textContent?.trim()||"0";if(r.match(/^-?[\d.]+[eE][+-]?\d+$/)){const[a,o]=r.split(/[eE]/);return`${a} \\times 10^{${o}}`}return r}return i==="piecewise"?this.parsePiecewise(e):i==="pi"?"\\pi":(this.ignoreTag(i)||console.warn(`Unsupported MathML node: ${i}`),"")}escapeGreek(e){return["alpha","beta","gamma","delta","epsilon","zeta","eta","theta","iota","kappa","lambda","mu","nu","xi","omicron","pi","rho","sigma","tau","upsilon","phi","chi","psi","omega"].includes(e.toLowerCase())?`\\${e}`:e}parseIdentifier(e){if(!e.includes("_"))return this.escapeGreek(e);const t=e.split("_"),i=this.escapeGreek(t[0]||""),s=[];t[1]&&s.push(t[1]),t.length>4&&s.push(...t.slice(4));let r="";t.length===3&&(t[2]||[]).length===1?s.push(this.escapeGreek(t[2]||"")):t[2]&&(r=this.escapeGreek(t[2]),t[3]&&(r+=`_{${this.escapeGreek(t[3])}}`)),s.forEach((h,u)=>{s[u]=this.escapeGreek(h)});const a=s.join(",");let o=i;return a&&(o+=`_{${a}}`),r&&(o+=`^{${r}}`),o}parseApply(e,t){const i=Array.from(e?.children||[]),s=i[0]?.localName||"unknown",r=$[s]||$.func,a=i.slice(1).map((h,u)=>{let p=r;return["divide","diff","root","sqrt","sin","cos","tan","exp","ln","log"].includes(s)?p=0:s==="minus"&&u===1&&(p=r+1),this.parseNode(h,p)});let o="";switch(s){case"plus":o=a.join(" + ");break;case"minus":o=a.length===1?`-${a[0]}`:`${a[0]} - ${a[1]}`;break;case"times":o=a.join(" \\cdot ");break;case"divide":o=`\\frac{${a[0]}}{${a[1]}}`;break;case"eq":o=`${a[0]} == ${a[1]}`;break;case"neq":o=`${a[0]} \\neq ${a[1]}`;break;case"lt":o=`${a[0]} < ${a[1]}`;break;case"leq":o=`${a[0]} \\leq ${a[1]}`;break;case"gt":o=`${a[0]} > ${a[1]}`;break;case"geq":o=`${a[0]} \\geq ${a[1]}`;break;case"and":o=a.join(" \\land ");break;case"or":o=a.join(" \\lor ");break;case"power":const h=i[1],u=a[0]||"",p=a[1];o=h?.localName==="ci"||h?.localName==="cn"&&!u.trim().startsWith("-")?`{${u}}^{${p}}`:`\\left({${u}}\\right)^{${p}}`;break;case"root":case"sqrt":o=`\\sqrt{${a[0]}}`;break;case"diff":const x=i.find(w=>w.localName==="bvar"),g=i.find(w=>w.localName!=="diff"&&w.localName!=="bvar"),O=x?this.parseNode(x.firstElementChild):"x";o=`\\frac{d${g?this.parseNode(g):"y"}}{d${O}}`;break;case"exp":o=`e^{${a[0]}}`;break;case"abs":o=`\\left|${a[0]}\\right|`;break;case"floor":o=`\\lfloor ${a[0]} \\rfloor`;break;case"ceil":o=`\\lceil ${a[0]} \\rceil`;break;case"cos":case"cosh":case"log10":case"log":case"ln":case"max":case"min":case"sin":case"sinh":case"tan":case"tanh":o=`\\${s}\\left(${a[0]}\\right)`;break;default:console.log(`Unsupported MathML operator: ${s}`),o=`\\text{${s}}(${a.join(", ")})`;break}return r<t&&(o=`\\left(${o}\\right)`),o}parsePiecewise(e){let t="";return Array.from(e.children).forEach(s=>{if(s.localName==="piece"){const r=this.parseNode(s.children[0]),a=this.parseNode(s.children[1]);t+=`${r} & \\text{if } ${a} \\\\ `}else if(s.localName==="otherwise"){const r=this.parseNode(s.children[0]);t+=`${r} & \\text{otherwise}`}}),`\\begin{cases} ${t} \\end{cases}`}}m.CellMLLatexGenerator=k,m.CellMLTextGenerator=E,m.CellMLTextParser=C,Object.defineProperty(m,Symbol.toStringTag,{value:"Module"})}));
|