tex2typst 0.6.0 → 0.6.2
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/bun.lock +282 -0
- package/dist/index.js +209 -264
- package/dist/tex2typst.min.js +10 -11
- package/package.json +1 -1
- package/src/convert.ts +7 -22
- package/src/index.ts +3 -1
- package/src/lex.ts +189 -0
- package/src/map.ts +0 -2
- package/src/tex-semantic-analysis.ts +39 -37
- package/src/tex-tokenizer.ts +30 -35
- package/src/typst-semantic-analyais.ts +38 -0
- package/src/typst-tokenizer.ts +44 -40
- package/src/typst-types.ts +55 -0
- package/dist/parser.js +0 -23
- package/src/jslex.ts +0 -311
package/dist/index.js
CHANGED
|
@@ -323,8 +323,8 @@ function array_intersperse(array, sep) {
|
|
|
323
323
|
return array.flatMap((x, i) => i !== array.length - 1 ? [x, sep] : [x]);
|
|
324
324
|
}
|
|
325
325
|
|
|
326
|
-
// src/
|
|
327
|
-
var EOF =
|
|
326
|
+
// src/lex.ts
|
|
327
|
+
var EOF = null;
|
|
328
328
|
function matchcompare(m1, m2) {
|
|
329
329
|
const m1_len = m1.reMatchArray[0].length;
|
|
330
330
|
const m2_len = m2.reMatchArray[0].length;
|
|
@@ -334,114 +334,31 @@ function matchcompare(m1, m2) {
|
|
|
334
334
|
return m1.index - m2.index;
|
|
335
335
|
}
|
|
336
336
|
}
|
|
337
|
+
var ScanResult = class _ScanResult {
|
|
338
|
+
result;
|
|
339
|
+
status;
|
|
340
|
+
constructor(status, result) {
|
|
341
|
+
this.result = result;
|
|
342
|
+
this.status = status;
|
|
343
|
+
}
|
|
344
|
+
static Accepted(result) {
|
|
345
|
+
return new _ScanResult(0 /* ACCEPTED */, result);
|
|
346
|
+
}
|
|
347
|
+
static Rejected() {
|
|
348
|
+
return new _ScanResult(1 /* REJECTED */, []);
|
|
349
|
+
}
|
|
350
|
+
static Error(message) {
|
|
351
|
+
return new _ScanResult(2 /* ERROR */, []);
|
|
352
|
+
}
|
|
353
|
+
};
|
|
337
354
|
var Scanner = class {
|
|
338
355
|
_input;
|
|
339
|
-
|
|
356
|
+
rules;
|
|
340
357
|
// position within input stream
|
|
341
358
|
_pos = 0;
|
|
342
|
-
|
|
343
|
-
_line = 0;
|
|
344
|
-
// current column number
|
|
345
|
-
_col = 0;
|
|
346
|
-
_offset = 0;
|
|
347
|
-
_less = null;
|
|
348
|
-
_go = false;
|
|
349
|
-
_newstate = null;
|
|
350
|
-
_state;
|
|
351
|
-
_text = null;
|
|
352
|
-
_leng = null;
|
|
353
|
-
_reMatchArray = null;
|
|
354
|
-
constructor(input, lexer) {
|
|
359
|
+
constructor(input, rules) {
|
|
355
360
|
this._input = input;
|
|
356
|
-
this.
|
|
357
|
-
this._state = lexer.states[0];
|
|
358
|
-
}
|
|
359
|
-
/**
|
|
360
|
-
* Analogous to yytext and yyleng in lex - will be set during scan.
|
|
361
|
-
*/
|
|
362
|
-
text() {
|
|
363
|
-
return this._text;
|
|
364
|
-
}
|
|
365
|
-
leng() {
|
|
366
|
-
return this._leng;
|
|
367
|
-
}
|
|
368
|
-
reMatchArray() {
|
|
369
|
-
return this._reMatchArray;
|
|
370
|
-
}
|
|
371
|
-
/**
|
|
372
|
-
* Position of in stream, line number and column number of match.
|
|
373
|
-
*/
|
|
374
|
-
pos() {
|
|
375
|
-
return this._pos;
|
|
376
|
-
}
|
|
377
|
-
line() {
|
|
378
|
-
return this._line;
|
|
379
|
-
}
|
|
380
|
-
column() {
|
|
381
|
-
return this._col;
|
|
382
|
-
}
|
|
383
|
-
/**
|
|
384
|
-
* Analogous to input() in lex.
|
|
385
|
-
* @return {string} The next character in the stream.
|
|
386
|
-
*/
|
|
387
|
-
input() {
|
|
388
|
-
return this._input.charAt(this._pos + this._leng + this._offset++);
|
|
389
|
-
}
|
|
390
|
-
/**
|
|
391
|
-
* Similar to unput() in lex, but does not allow modifying the stream.
|
|
392
|
-
* @return {int} The offset position after the operation.
|
|
393
|
-
*/
|
|
394
|
-
unput() {
|
|
395
|
-
return this._offset = this._offset > 0 ? this._offset-- : 0;
|
|
396
|
-
}
|
|
397
|
-
/**
|
|
398
|
-
* Analogous to yyless(n) in lex - retains the first n characters from this pattern, and returns
|
|
399
|
-
* the rest to the input stream, such that they will be used in the next pattern-matching operation.
|
|
400
|
-
* @param {int} n Number of characters to retain.
|
|
401
|
-
* @return {int} Length of the stream after the operation has completed.
|
|
402
|
-
*/
|
|
403
|
-
less(n) {
|
|
404
|
-
this._less = n;
|
|
405
|
-
this._offset = 0;
|
|
406
|
-
this._text = this._text.substring(0, n);
|
|
407
|
-
return this._leng = this._text.length;
|
|
408
|
-
}
|
|
409
|
-
/**
|
|
410
|
-
* Like less(), but instead of retaining the first n characters, it chops off the last n.
|
|
411
|
-
* @param {int} n Number of characters to chop.
|
|
412
|
-
* @return {int} Length of the stream after the operation has completed.
|
|
413
|
-
*/
|
|
414
|
-
pushback(n) {
|
|
415
|
-
return this.less(this._leng - n);
|
|
416
|
-
}
|
|
417
|
-
/**
|
|
418
|
-
* Similar to REJECT in lex, except it doesn't break the current execution context.
|
|
419
|
-
* TIP: reject() should be the last instruction in a spec callback.
|
|
420
|
-
*/
|
|
421
|
-
reject() {
|
|
422
|
-
this._go = true;
|
|
423
|
-
}
|
|
424
|
-
/**
|
|
425
|
-
* Analogous to BEGIN in lex - sets the named state (start condition).
|
|
426
|
-
* @param {string|int} state Name of state to switch to, or ordinal number (0 is first, etc).
|
|
427
|
-
* @return {string} The new state on successful switch, throws exception on failure.
|
|
428
|
-
*/
|
|
429
|
-
begin(state) {
|
|
430
|
-
if (this._lexer.specification[state]) {
|
|
431
|
-
return this._newstate = state;
|
|
432
|
-
}
|
|
433
|
-
const s = this._lexer.states[parseInt(state)];
|
|
434
|
-
if (s) {
|
|
435
|
-
return this._newstate = s;
|
|
436
|
-
}
|
|
437
|
-
throw "Unknown state '" + state + "' requested";
|
|
438
|
-
}
|
|
439
|
-
/**
|
|
440
|
-
* Simple accessor for reading in the current state.
|
|
441
|
-
* @return {string} The current state.
|
|
442
|
-
*/
|
|
443
|
-
state() {
|
|
444
|
-
return this._state;
|
|
361
|
+
this.rules = rules;
|
|
445
362
|
}
|
|
446
363
|
/**
|
|
447
364
|
* Scan method to be returned to caller - grabs the next token and fires appropriate calback.
|
|
@@ -452,7 +369,7 @@ var Scanner = class {
|
|
|
452
369
|
return EOF;
|
|
453
370
|
}
|
|
454
371
|
const str = this._input.substring(this._pos);
|
|
455
|
-
const rules = this.
|
|
372
|
+
const rules = this.rules;
|
|
456
373
|
const matches = [];
|
|
457
374
|
for (let i = 0; i < rules.length; i++) {
|
|
458
375
|
const rule = rules[i];
|
|
@@ -469,87 +386,50 @@ var Scanner = class {
|
|
|
469
386
|
throw new Error("No match found for input '" + str + "'");
|
|
470
387
|
}
|
|
471
388
|
matches.sort(matchcompare);
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
this._text = matched_text;
|
|
483
|
-
this._leng = matched_text.length;
|
|
484
|
-
this._reMatchArray = m.reMatchArray;
|
|
485
|
-
result = m.rule.action(this);
|
|
486
|
-
if (this._newstate && this._newstate != this._state) {
|
|
487
|
-
this._state = this._newstate;
|
|
488
|
-
break;
|
|
389
|
+
for (const m of matches) {
|
|
390
|
+
const matched_text = m.reMatchArray[0];
|
|
391
|
+
const result = m.rule.action({
|
|
392
|
+
pos: this._pos,
|
|
393
|
+
text: matched_text,
|
|
394
|
+
reMatchArray: m.reMatchArray
|
|
395
|
+
});
|
|
396
|
+
if (result.status === 0 /* ACCEPTED */) {
|
|
397
|
+
this._pos += matched_text.length;
|
|
398
|
+
return result.result;
|
|
489
399
|
}
|
|
490
400
|
}
|
|
491
|
-
|
|
492
|
-
const len = text.length;
|
|
493
|
-
this._pos += len + this._offset;
|
|
494
|
-
const nlm = text.match(/\n/g);
|
|
495
|
-
if (nlm !== null) {
|
|
496
|
-
this._line += nlm.length;
|
|
497
|
-
this._col = len - text.lastIndexOf("\n") - 1;
|
|
498
|
-
} else {
|
|
499
|
-
this._col += len;
|
|
500
|
-
}
|
|
501
|
-
return result;
|
|
401
|
+
throw new Error("No match found for input '" + str + "'");
|
|
502
402
|
}
|
|
503
403
|
};
|
|
504
404
|
var JSLex = class {
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
throw "Duplicate state declaration encountered for state '" + s + "'";
|
|
514
|
-
}
|
|
515
|
-
this.specification[s] = [];
|
|
516
|
-
for (const [k, v] of rule_map.entries()) {
|
|
517
|
-
let re;
|
|
518
|
-
try {
|
|
519
|
-
re = new RegExp("^" + k);
|
|
520
|
-
} catch (err) {
|
|
521
|
-
throw "Invalid regexp '" + k + "' in state '" + s + "' (" + err.message + ")";
|
|
522
|
-
}
|
|
523
|
-
this.specification[s].push({
|
|
524
|
-
re,
|
|
525
|
-
action: v
|
|
526
|
-
});
|
|
405
|
+
rules = [];
|
|
406
|
+
constructor(ruleMap) {
|
|
407
|
+
for (const [k, v] of ruleMap.entries()) {
|
|
408
|
+
let re;
|
|
409
|
+
try {
|
|
410
|
+
re = new RegExp("^" + k);
|
|
411
|
+
} catch (err) {
|
|
412
|
+
throw "Invalid regexp '" + k + "' (" + err.message + ")";
|
|
527
413
|
}
|
|
414
|
+
this.rules.push({
|
|
415
|
+
re,
|
|
416
|
+
action: v
|
|
417
|
+
});
|
|
528
418
|
}
|
|
529
419
|
}
|
|
530
|
-
/**
|
|
531
|
-
* Scanner function - makes a new scanner object which is used to get tokens one at a time.
|
|
532
|
-
* @param {string} input Input text to tokenize.
|
|
533
|
-
* @return {function} Scanner function.
|
|
534
|
-
*/
|
|
535
|
-
scanner(input) {
|
|
536
|
-
return new Scanner(input, this);
|
|
537
|
-
}
|
|
538
420
|
/**
|
|
539
421
|
* Similar to lex's yylex() function, consumes all input, calling calback for each token.
|
|
540
422
|
* @param {string} input Text to lex.
|
|
541
423
|
* @param {function} callback Function to execute for each token.
|
|
542
424
|
*/
|
|
543
425
|
lex(input, callback) {
|
|
544
|
-
const scanner = this.
|
|
426
|
+
const scanner = new Scanner(input, this.rules);
|
|
545
427
|
while (true) {
|
|
546
428
|
const token = scanner.scan();
|
|
547
429
|
if (token === EOF) {
|
|
548
|
-
|
|
549
|
-
}
|
|
550
|
-
if (token !== void 0) {
|
|
551
|
-
callback(token);
|
|
430
|
+
break;
|
|
552
431
|
}
|
|
432
|
+
callback(token);
|
|
553
433
|
}
|
|
554
434
|
}
|
|
555
435
|
/**
|
|
@@ -647,8 +527,8 @@ var rules_map = /* @__PURE__ */ new Map([
|
|
|
647
527
|
[
|
|
648
528
|
String.raw`\\begin{(array|subarry)}{(.+?)}`,
|
|
649
529
|
(s) => {
|
|
650
|
-
const match = s.reMatchArray
|
|
651
|
-
return [
|
|
530
|
+
const match = s.reMatchArray;
|
|
531
|
+
return ScanResult.Accepted([
|
|
652
532
|
new TexToken(2 /* COMMAND */, "\\begin"),
|
|
653
533
|
new TexToken(7 /* CONTROL */, "{"),
|
|
654
534
|
new TexToken(3 /* LITERAL */, match[1]),
|
|
@@ -656,74 +536,69 @@ var rules_map = /* @__PURE__ */ new Map([
|
|
|
656
536
|
new TexToken(7 /* CONTROL */, "{"),
|
|
657
537
|
new TexToken(3 /* LITERAL */, match[2]),
|
|
658
538
|
new TexToken(7 /* CONTROL */, "}")
|
|
659
|
-
];
|
|
539
|
+
]);
|
|
660
540
|
}
|
|
661
541
|
],
|
|
662
542
|
[
|
|
663
543
|
String.raw`\\(text|operatorname\*?|textcolor|begin|end|hspace|array)\s*{(.+?)}`,
|
|
664
544
|
(s) => {
|
|
665
|
-
const match = s.reMatchArray
|
|
666
|
-
return [
|
|
545
|
+
const match = s.reMatchArray;
|
|
546
|
+
return ScanResult.Accepted([
|
|
667
547
|
new TexToken(2 /* COMMAND */, "\\" + match[1]),
|
|
668
548
|
new TexToken(7 /* CONTROL */, "{"),
|
|
669
549
|
new TexToken(3 /* LITERAL */, unescape(match[2])),
|
|
670
550
|
new TexToken(7 /* CONTROL */, "}")
|
|
671
|
-
];
|
|
551
|
+
]);
|
|
672
552
|
}
|
|
673
553
|
],
|
|
674
|
-
[String.raw`%[^\n]*`, (s) => new TexToken(4 /* COMMENT */, s.text
|
|
675
|
-
[String.raw`[{}_^&]`, (s) => new TexToken(7 /* CONTROL */, s.text
|
|
676
|
-
[String.raw`\\[\\,:;!> ]`, (s) => new TexToken(7 /* CONTROL */, s.text
|
|
677
|
-
[String.raw`~`, (s) => new TexToken(7 /* CONTROL */, s.text
|
|
678
|
-
[String.raw`\r?\n`, (_s) => new TexToken(6 /* NEWLINE */, "\n")],
|
|
679
|
-
[String.raw`\s+`, (s) => new TexToken(5 /* SPACE */, s.text
|
|
680
|
-
[String.raw`\\[{}%$&#_|]`, (s) => new TexToken(1 /* ELEMENT */, s.text
|
|
554
|
+
[String.raw`%[^\n]*`, (s) => ScanResult.Accepted(new TexToken(4 /* COMMENT */, s.text.substring(1)))],
|
|
555
|
+
[String.raw`[{}_^&]`, (s) => ScanResult.Accepted([new TexToken(7 /* CONTROL */, s.text)])],
|
|
556
|
+
[String.raw`\\[\\,:;!> ]`, (s) => ScanResult.Accepted([new TexToken(7 /* CONTROL */, s.text)])],
|
|
557
|
+
[String.raw`~`, (s) => ScanResult.Accepted([new TexToken(7 /* CONTROL */, s.text)])],
|
|
558
|
+
[String.raw`\r?\n`, (_s) => ScanResult.Accepted([new TexToken(6 /* NEWLINE */, "\n")])],
|
|
559
|
+
[String.raw`\s+`, (s) => ScanResult.Accepted([new TexToken(5 /* SPACE */, s.text)])],
|
|
560
|
+
[String.raw`\\[{}%$&#_|]`, (s) => ScanResult.Accepted([new TexToken(1 /* ELEMENT */, s.text)])],
|
|
681
561
|
// e.g. match `\frac13`, `\frac1 b`, `\frac a b`
|
|
682
562
|
[String.raw`(\\[a-zA-Z]+)(\s*\d|\s+[a-zA-Z])\s*([0-9a-zA-Z])`, (s) => {
|
|
683
|
-
const match = s.reMatchArray
|
|
563
|
+
const match = s.reMatchArray;
|
|
684
564
|
const command = match[1];
|
|
685
565
|
if (TEX_BINARY_COMMANDS.includes(command.substring(1))) {
|
|
686
566
|
const arg1 = match[2].trimStart();
|
|
687
567
|
const arg2 = match[3];
|
|
688
|
-
return [
|
|
568
|
+
return ScanResult.Accepted([
|
|
689
569
|
new TexToken(2 /* COMMAND */, command),
|
|
690
570
|
new TexToken(1 /* ELEMENT */, arg1),
|
|
691
571
|
new TexToken(1 /* ELEMENT */, arg2)
|
|
692
|
-
];
|
|
572
|
+
]);
|
|
693
573
|
} else {
|
|
694
|
-
|
|
695
|
-
return [];
|
|
574
|
+
return ScanResult.Rejected();
|
|
696
575
|
}
|
|
697
576
|
}],
|
|
698
577
|
// e.g. match `\sqrt3`, `\sqrt a`
|
|
699
578
|
[String.raw`(\\[a-zA-Z]+)(\s*\d|\s+[a-zA-Z])`, (s) => {
|
|
700
|
-
const match = s.reMatchArray
|
|
579
|
+
const match = s.reMatchArray;
|
|
701
580
|
const command = match[1];
|
|
702
581
|
if (TEX_UNARY_COMMANDS.includes(command.substring(1))) {
|
|
703
582
|
const arg1 = match[2].trimStart();
|
|
704
|
-
return [
|
|
583
|
+
return ScanResult.Accepted([
|
|
705
584
|
new TexToken(2 /* COMMAND */, command),
|
|
706
585
|
new TexToken(1 /* ELEMENT */, arg1)
|
|
707
|
-
];
|
|
586
|
+
]);
|
|
708
587
|
} else {
|
|
709
|
-
|
|
710
|
-
return [];
|
|
588
|
+
return ScanResult.Rejected();
|
|
711
589
|
}
|
|
712
590
|
}],
|
|
713
|
-
[String.raw`\\[a-zA-Z]+`, (s) => new TexToken(2 /* COMMAND */, s.text
|
|
591
|
+
[String.raw`\\[a-zA-Z]+`, (s) => ScanResult.Accepted(new TexToken(2 /* COMMAND */, s.text))],
|
|
714
592
|
// Numbers like "123", "3.14"
|
|
715
|
-
[String.raw`[0-9]+(\.[0-9]+)?`, (s) => new TexToken(1 /* ELEMENT */, s.text
|
|
716
|
-
[String.raw`[a-zA-Z]`, (s) => new TexToken(1 /* ELEMENT */, s.text
|
|
717
|
-
[String.raw`[+\-*/='<>!.,;:?()\[\]|]`, (s) => new TexToken(1 /* ELEMENT */, s.text
|
|
593
|
+
[String.raw`[0-9]+(\.[0-9]+)?`, (s) => ScanResult.Accepted(new TexToken(1 /* ELEMENT */, s.text))],
|
|
594
|
+
[String.raw`[a-zA-Z]`, (s) => ScanResult.Accepted(new TexToken(1 /* ELEMENT */, s.text))],
|
|
595
|
+
[String.raw`[+\-*/='<>!.,;:?()\[\]|]`, (s) => ScanResult.Accepted(new TexToken(1 /* ELEMENT */, s.text))],
|
|
718
596
|
// non-ASCII characters
|
|
719
|
-
[String.raw`[^\x00-\x7F]`, (s) => new TexToken(1 /* ELEMENT */, s.text
|
|
720
|
-
[String.raw`.`, (s) => new TexToken(8 /* UNKNOWN */, s.text
|
|
597
|
+
[String.raw`[^\x00-\x7F]`, (s) => ScanResult.Accepted(new TexToken(1 /* ELEMENT */, s.text))],
|
|
598
|
+
[String.raw`.`, (s) => ScanResult.Accepted([new TexToken(8 /* UNKNOWN */, s.text)])]
|
|
721
599
|
]);
|
|
722
|
-
var spec = {
|
|
723
|
-
"start": rules_map
|
|
724
|
-
};
|
|
725
600
|
function tokenize_tex(input) {
|
|
726
|
-
const lexer = new JSLex(
|
|
601
|
+
const lexer = new JSLex(rules_map);
|
|
727
602
|
return lexer.collect(input);
|
|
728
603
|
}
|
|
729
604
|
|
|
@@ -1398,6 +1273,9 @@ var TypstTerminal = class extends TypstNode {
|
|
|
1398
1273
|
}
|
|
1399
1274
|
return [this.head];
|
|
1400
1275
|
}
|
|
1276
|
+
bottomTopTraversalTransform(transform) {
|
|
1277
|
+
return transform(this);
|
|
1278
|
+
}
|
|
1401
1279
|
};
|
|
1402
1280
|
var TypstTokenQueue = class {
|
|
1403
1281
|
queue = [];
|
|
@@ -1433,7 +1311,7 @@ var TypstTokenQueue = class {
|
|
|
1433
1311
|
return res;
|
|
1434
1312
|
}
|
|
1435
1313
|
};
|
|
1436
|
-
var TypstGroup = class extends TypstNode {
|
|
1314
|
+
var TypstGroup = class _TypstGroup extends TypstNode {
|
|
1437
1315
|
items;
|
|
1438
1316
|
constructor(items) {
|
|
1439
1317
|
super("group", TypstToken.NONE);
|
|
@@ -1478,8 +1356,12 @@ var TypstGroup = class extends TypstNode {
|
|
|
1478
1356
|
}
|
|
1479
1357
|
return queue;
|
|
1480
1358
|
}
|
|
1359
|
+
bottomTopTraversalTransform(transform) {
|
|
1360
|
+
const g = new _TypstGroup(this.items.map((n) => n.bottomTopTraversalTransform(transform)));
|
|
1361
|
+
return transform(g);
|
|
1362
|
+
}
|
|
1481
1363
|
};
|
|
1482
|
-
var TypstSupsub = class extends TypstNode {
|
|
1364
|
+
var TypstSupsub = class _TypstSupsub extends TypstNode {
|
|
1483
1365
|
base;
|
|
1484
1366
|
sup;
|
|
1485
1367
|
sub;
|
|
@@ -1516,8 +1398,16 @@ var TypstSupsub = class extends TypstNode {
|
|
|
1516
1398
|
}
|
|
1517
1399
|
return queue;
|
|
1518
1400
|
}
|
|
1401
|
+
bottomTopTraversalTransform(transform) {
|
|
1402
|
+
const s = new _TypstSupsub({
|
|
1403
|
+
base: this.base.bottomTopTraversalTransform(transform),
|
|
1404
|
+
sup: this.sup?.bottomTopTraversalTransform(transform) || null,
|
|
1405
|
+
sub: this.sub?.bottomTopTraversalTransform(transform) || null
|
|
1406
|
+
});
|
|
1407
|
+
return transform(s);
|
|
1408
|
+
}
|
|
1519
1409
|
};
|
|
1520
|
-
var TypstFuncCall = class extends TypstNode {
|
|
1410
|
+
var TypstFuncCall = class _TypstFuncCall extends TypstNode {
|
|
1521
1411
|
args;
|
|
1522
1412
|
constructor(head, args) {
|
|
1523
1413
|
super("funcCall", head);
|
|
@@ -1557,8 +1447,13 @@ var TypstFuncCall = class extends TypstNode {
|
|
|
1557
1447
|
env.insideFunctionDepth--;
|
|
1558
1448
|
return queue;
|
|
1559
1449
|
}
|
|
1450
|
+
bottomTopTraversalTransform(transform) {
|
|
1451
|
+
const f = new _TypstFuncCall(this.head, this.args.map((n) => n.bottomTopTraversalTransform(transform)));
|
|
1452
|
+
f.options = this.options;
|
|
1453
|
+
return transform(f);
|
|
1454
|
+
}
|
|
1560
1455
|
};
|
|
1561
|
-
var TypstFraction = class extends TypstNode {
|
|
1456
|
+
var TypstFraction = class _TypstFraction extends TypstNode {
|
|
1562
1457
|
args;
|
|
1563
1458
|
constructor(args) {
|
|
1564
1459
|
super("fraction", TypstToken.NONE);
|
|
@@ -1581,10 +1476,14 @@ var TypstFraction = class extends TypstNode {
|
|
|
1581
1476
|
queue.push(...denominator.serialize(env, options));
|
|
1582
1477
|
return queue;
|
|
1583
1478
|
}
|
|
1479
|
+
bottomTopTraversalTransform(transform) {
|
|
1480
|
+
const f = new _TypstFraction(this.args.map((n) => n.bottomTopTraversalTransform(transform)));
|
|
1481
|
+
return transform(f);
|
|
1482
|
+
}
|
|
1584
1483
|
};
|
|
1585
1484
|
var TYPST_LEFT_PARENTHESIS = new TypstToken(2 /* ELEMENT */, "(");
|
|
1586
1485
|
var TYPST_RIGHT_PARENTHESIS = new TypstToken(2 /* ELEMENT */, ")");
|
|
1587
|
-
var TypstLeftright = class extends TypstNode {
|
|
1486
|
+
var TypstLeftright = class _TypstLeftright extends TypstNode {
|
|
1588
1487
|
body;
|
|
1589
1488
|
left;
|
|
1590
1489
|
right;
|
|
@@ -1630,6 +1529,14 @@ var TypstLeftright = class extends TypstNode {
|
|
|
1630
1529
|
}
|
|
1631
1530
|
return queue;
|
|
1632
1531
|
}
|
|
1532
|
+
bottomTopTraversalTransform(transform) {
|
|
1533
|
+
const l = new _TypstLeftright(this.head, {
|
|
1534
|
+
body: this.body.bottomTopTraversalTransform(transform),
|
|
1535
|
+
left: this.left,
|
|
1536
|
+
right: this.right
|
|
1537
|
+
});
|
|
1538
|
+
return transform(l);
|
|
1539
|
+
}
|
|
1633
1540
|
};
|
|
1634
1541
|
var TypstMatrixLike = class _TypstMatrixLike extends TypstNode {
|
|
1635
1542
|
matrix;
|
|
@@ -1697,10 +1604,16 @@ var TypstMatrixLike = class _TypstMatrixLike extends TypstNode {
|
|
|
1697
1604
|
}
|
|
1698
1605
|
return queue;
|
|
1699
1606
|
}
|
|
1607
|
+
bottomTopTraversalTransform(transform) {
|
|
1608
|
+
const m = this.matrix.map((row) => row.map((cell) => cell.bottomTopTraversalTransform(transform)));
|
|
1609
|
+
const ml = new _TypstMatrixLike(this.head, m);
|
|
1610
|
+
ml.options = this.options;
|
|
1611
|
+
return transform(ml);
|
|
1612
|
+
}
|
|
1700
1613
|
static MAT = new TypstToken(1 /* SYMBOL */, "mat");
|
|
1701
1614
|
static CASES = new TypstToken(1 /* SYMBOL */, "cases");
|
|
1702
1615
|
};
|
|
1703
|
-
var TypstMarkupFunc = class extends TypstNode {
|
|
1616
|
+
var TypstMarkupFunc = class _TypstMarkupFunc extends TypstNode {
|
|
1704
1617
|
/*
|
|
1705
1618
|
In idealized situations, for `#heading([some text and math $x + y$ example])`,
|
|
1706
1619
|
fragments would be [TypstMarkup{"some text and math "}, TypstNode{"x + y"}, TypstMarkup{" example"}]
|
|
@@ -1747,6 +1660,11 @@ var TypstMarkupFunc = class extends TypstNode {
|
|
|
1747
1660
|
queue.push(new TypstToken(3 /* LITERAL */, "]"));
|
|
1748
1661
|
return queue;
|
|
1749
1662
|
}
|
|
1663
|
+
bottomTopTraversalTransform(transform) {
|
|
1664
|
+
const mf = new _TypstMarkupFunc(this.head, this.fragments.map((n) => n.bottomTopTraversalTransform(transform)));
|
|
1665
|
+
mf.options = this.options;
|
|
1666
|
+
return transform(mf);
|
|
1667
|
+
}
|
|
1750
1668
|
};
|
|
1751
1669
|
|
|
1752
1670
|
// src/typst-writer.ts
|
|
@@ -1866,7 +1784,6 @@ var symbolMap = /* @__PURE__ */ new Map([
|
|
|
1866
1784
|
["neq", "eq.not"],
|
|
1867
1785
|
["dot", "dot"],
|
|
1868
1786
|
["ddot", "dot.double"],
|
|
1869
|
-
["doteq", "dot(eq)"],
|
|
1870
1787
|
["dots", "dots.h"],
|
|
1871
1788
|
["vdots", "dots.v"],
|
|
1872
1789
|
["ddots", "dots.down"],
|
|
@@ -2939,7 +2856,6 @@ var reverseSymbolMap = /* @__PURE__ */ new Map();
|
|
|
2939
2856
|
for (const [key, value] of Array.from(symbolMap.entries()).reverse()) {
|
|
2940
2857
|
reverseSymbolMap.set(value, key);
|
|
2941
2858
|
}
|
|
2942
|
-
reverseSymbolMap.set("oo", "infty");
|
|
2943
2859
|
var typst_to_tex_map = /* @__PURE__ */ new Map([
|
|
2944
2860
|
["top", "top"],
|
|
2945
2861
|
["frac", "frac"],
|
|
@@ -3024,8 +2940,6 @@ function tex_token_to_typst(token, options) {
|
|
|
3024
2940
|
case 7 /* CONTROL */: {
|
|
3025
2941
|
if (token.value === "\\\\") {
|
|
3026
2942
|
return new TypstToken(7 /* CONTROL */, "\\");
|
|
3027
|
-
} else if (token.value === "\\!") {
|
|
3028
|
-
return new TypstToken(1 /* SYMBOL */, "#h(-math.thin.amount)");
|
|
3029
2943
|
} else if (token.value === "~") {
|
|
3030
2944
|
const typst_symbol = symbolMap.get("~");
|
|
3031
2945
|
return new TypstToken(1 /* SYMBOL */, typst_symbol);
|
|
@@ -3125,6 +3039,12 @@ function convert_tex_node_to_typst(abstractNode, options) {
|
|
|
3125
3039
|
switch (abstractNode.type) {
|
|
3126
3040
|
case "terminal": {
|
|
3127
3041
|
const node2 = abstractNode;
|
|
3042
|
+
if (node2.head.eq(new TexToken(7 /* CONTROL */, "\\!"))) {
|
|
3043
|
+
return new TypstFuncCall(
|
|
3044
|
+
new TypstToken(1 /* SYMBOL */, "#h"),
|
|
3045
|
+
[new TypstToken(3 /* LITERAL */, "-math.thin.amount").toNode()]
|
|
3046
|
+
);
|
|
3047
|
+
}
|
|
3128
3048
|
return tex_token_to_typst(node2.head, options).toNode();
|
|
3129
3049
|
}
|
|
3130
3050
|
case "text": {
|
|
@@ -3550,21 +3470,6 @@ function convert_typst_node_to_tex(abstractNode, options) {
|
|
|
3550
3470
|
case "terminal": {
|
|
3551
3471
|
const node = abstractNode;
|
|
3552
3472
|
if (node.head.type === 1 /* SYMBOL */) {
|
|
3553
|
-
if (node.head.value === "eq.def") {
|
|
3554
|
-
return new TexFuncCall(new TexToken(2 /* COMMAND */, "\\overset"), [
|
|
3555
|
-
new TexText(new TexToken(3 /* LITERAL */, "def")),
|
|
3556
|
-
new TexToken(1 /* ELEMENT */, "=").toNode()
|
|
3557
|
-
]);
|
|
3558
|
-
}
|
|
3559
|
-
if (node.head.value === "comma") {
|
|
3560
|
-
return new TexToken(1 /* ELEMENT */, ",").toNode();
|
|
3561
|
-
}
|
|
3562
|
-
if (node.head.value === "dif") {
|
|
3563
|
-
return new TexFuncCall(new TexToken(2 /* COMMAND */, "\\mathrm"), [new TexToken(1 /* ELEMENT */, "d").toNode()]);
|
|
3564
|
-
}
|
|
3565
|
-
if (node.head.value === "hyph" || node.head.value === "hyph.minus") {
|
|
3566
|
-
return new TexText(new TexToken(3 /* LITERAL */, "-"));
|
|
3567
|
-
}
|
|
3568
3473
|
if (/^([A-Z])\1$/.test(node.head.value)) {
|
|
3569
3474
|
return new TexFuncCall(new TexToken(2 /* COMMAND */, "\\mathbb"), [
|
|
3570
3475
|
new TexToken(1 /* ELEMENT */, node.head.value[0]).toNode()
|
|
@@ -3854,64 +3759,69 @@ function generate_regex_for_shorthands() {
|
|
|
3854
3759
|
}
|
|
3855
3760
|
var REGEX_SHORTHANDS = generate_regex_for_shorthands();
|
|
3856
3761
|
var rules_map2 = /* @__PURE__ */ new Map([
|
|
3857
|
-
[String.raw`//[^\n]*`, (s) => new TypstToken(5 /* COMMENT */, s.text
|
|
3858
|
-
[String.raw`/`, (s) => new TypstToken(2 /* ELEMENT */, s.text
|
|
3859
|
-
[String.raw`[_^&]`, (s) => new TypstToken(7 /* CONTROL */, s.text
|
|
3860
|
-
[String.raw`\r?\n`, (_s) => new TypstToken(8 /* NEWLINE */, "\n")],
|
|
3861
|
-
[String.raw`\s+`, (s) => new TypstToken(6 /* SPACE */, s.text
|
|
3862
|
-
[String.raw`\\[$&#_]`, (s) => new TypstToken(2 /* ELEMENT */, s.text
|
|
3863
|
-
[
|
|
3864
|
-
|
|
3762
|
+
[String.raw`//[^\n]*`, (s) => ScanResult.Accepted(new TypstToken(5 /* COMMENT */, s.text.substring(2)))],
|
|
3763
|
+
[String.raw`/`, (s) => ScanResult.Accepted(new TypstToken(2 /* ELEMENT */, s.text))],
|
|
3764
|
+
[String.raw`[_^&]`, (s) => ScanResult.Accepted(new TypstToken(7 /* CONTROL */, s.text))],
|
|
3765
|
+
[String.raw`\r?\n`, (_s) => ScanResult.Accepted(new TypstToken(8 /* NEWLINE */, "\n"))],
|
|
3766
|
+
[String.raw`\s+`, (s) => ScanResult.Accepted(new TypstToken(6 /* SPACE */, s.text))],
|
|
3767
|
+
[String.raw`\\[$&#_]`, (s) => ScanResult.Accepted(new TypstToken(2 /* ELEMENT */, s.text))],
|
|
3768
|
+
[
|
|
3769
|
+
String.raw`\\\n`,
|
|
3770
|
+
(s) => ScanResult.Accepted([
|
|
3865
3771
|
new TypstToken(7 /* CONTROL */, "\\"),
|
|
3866
3772
|
new TypstToken(8 /* NEWLINE */, "\n")
|
|
3867
|
-
]
|
|
3868
|
-
|
|
3773
|
+
])
|
|
3774
|
+
],
|
|
3869
3775
|
[String.raw`\\\s`, (s) => {
|
|
3870
|
-
return [
|
|
3776
|
+
return ScanResult.Accepted([
|
|
3871
3777
|
new TypstToken(7 /* CONTROL */, "\\"),
|
|
3872
3778
|
new TypstToken(6 /* SPACE */, " ")
|
|
3873
|
-
];
|
|
3779
|
+
]);
|
|
3874
3780
|
}],
|
|
3875
3781
|
// this backslash is dummy and will be ignored in later stages
|
|
3876
|
-
[String.raw`\\\S`, (_s) => new TypstToken(7 /* CONTROL */, "")],
|
|
3782
|
+
[String.raw`\\\S`, (_s) => ScanResult.Accepted(new TypstToken(7 /* CONTROL */, ""))],
|
|
3877
3783
|
[
|
|
3878
3784
|
String.raw`"([^"]|(\\"))*"`,
|
|
3879
3785
|
(s) => {
|
|
3880
|
-
const text = s.text
|
|
3786
|
+
const text = s.text.substring(1, s.text.length - 1);
|
|
3881
3787
|
text.replaceAll('\\"', '"');
|
|
3882
|
-
return new TypstToken(4 /* TEXT */, text);
|
|
3788
|
+
return ScanResult.Accepted(new TypstToken(4 /* TEXT */, text));
|
|
3883
3789
|
}
|
|
3884
3790
|
],
|
|
3885
3791
|
[
|
|
3886
3792
|
REGEX_SHORTHANDS,
|
|
3887
3793
|
(s) => {
|
|
3888
|
-
const shorthand = s.text
|
|
3794
|
+
const shorthand = s.text;
|
|
3889
3795
|
const symbol = reverseShorthandMap.get(shorthand);
|
|
3890
|
-
return new TypstToken(1 /* SYMBOL */, symbol);
|
|
3796
|
+
return ScanResult.Accepted(new TypstToken(1 /* SYMBOL */, symbol));
|
|
3891
3797
|
}
|
|
3892
3798
|
],
|
|
3893
|
-
[String.raw`[0-9]+(\.[0-9]+)?`, (s) => new TypstToken(2 /* ELEMENT */, s.text
|
|
3894
|
-
[String.raw`[+\-*/=\'<>!.,;?()\[\]|]`, (s) => new TypstToken(2 /* ELEMENT */, s.text
|
|
3895
|
-
[
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3799
|
+
[String.raw`[0-9]+(\.[0-9]+)?`, (s) => ScanResult.Accepted(new TypstToken(2 /* ELEMENT */, s.text))],
|
|
3800
|
+
[String.raw`[+\-*/=\'<>!.,;?()\[\]|]`, (s) => ScanResult.Accepted(new TypstToken(2 /* ELEMENT */, s.text))],
|
|
3801
|
+
[
|
|
3802
|
+
String.raw`#h\((.+?)\)`,
|
|
3803
|
+
(s) => {
|
|
3804
|
+
const match = s.reMatchArray;
|
|
3805
|
+
return ScanResult.Accepted([
|
|
3806
|
+
new TypstToken(1 /* SYMBOL */, "#h"),
|
|
3807
|
+
new TypstToken(2 /* ELEMENT */, "("),
|
|
3808
|
+
new TypstToken(3 /* LITERAL */, match[1]),
|
|
3809
|
+
new TypstToken(2 /* ELEMENT */, ")")
|
|
3810
|
+
]);
|
|
3811
|
+
}
|
|
3812
|
+
],
|
|
3813
|
+
[String.raw`#none`, (s) => ScanResult.Accepted(new TypstToken(0 /* NONE */, s.text))],
|
|
3814
|
+
[
|
|
3815
|
+
String.raw`#none`,
|
|
3816
|
+
(s) => ScanResult.Accepted(new TypstToken(0 /* NONE */, s.text))
|
|
3817
|
+
],
|
|
3905
3818
|
[String.raw`#?[a-zA-Z\.]+`, (s) => {
|
|
3906
|
-
return new TypstToken(s.text
|
|
3819
|
+
return ScanResult.Accepted(new TypstToken(s.text.length === 1 ? 2 /* ELEMENT */ : 1 /* SYMBOL */, s.text));
|
|
3907
3820
|
}],
|
|
3908
|
-
[String.raw`.`, (s) => new TypstToken(2 /* ELEMENT */, s.text
|
|
3821
|
+
[String.raw`.`, (s) => ScanResult.Accepted(new TypstToken(2 /* ELEMENT */, s.text))]
|
|
3909
3822
|
]);
|
|
3910
|
-
var spec2 = {
|
|
3911
|
-
"start": rules_map2
|
|
3912
|
-
};
|
|
3913
3823
|
function tokenize_typst(input) {
|
|
3914
|
-
const lexer = new JSLex(
|
|
3824
|
+
const lexer = new JSLex(rules_map2);
|
|
3915
3825
|
return lexer.collect(input);
|
|
3916
3826
|
}
|
|
3917
3827
|
|
|
@@ -4324,7 +4234,8 @@ var TEX_PREDEFINED_MACROS = /* @__PURE__ */ new Map([
|
|
|
4324
4234
|
["\\varUpsilon", "\\mathit{\\Upsilon}"],
|
|
4325
4235
|
["\\varPhi", "\\mathit{\\Phi}"],
|
|
4326
4236
|
["\\varPsi", "\\mathit{\\Psi}"],
|
|
4327
|
-
["\\varOmega", "\\mathit{\\Omega}"]
|
|
4237
|
+
["\\varOmega", "\\mathit{\\Omega}"],
|
|
4238
|
+
["\\doteq", "\\dot{=}"]
|
|
4328
4239
|
]);
|
|
4329
4240
|
function _expand_tex_predefined_macros(node) {
|
|
4330
4241
|
switch (node.type) {
|
|
@@ -4345,6 +4256,39 @@ function expand_tex_predefined_macros(node) {
|
|
|
4345
4256
|
return node.bottomTopTraversalTransform(_expand_tex_predefined_macros);
|
|
4346
4257
|
}
|
|
4347
4258
|
|
|
4259
|
+
// src/typst-semantic-analyais.ts
|
|
4260
|
+
var TEX_PREDEFINED_VARIABLES = /* @__PURE__ */ new Map([
|
|
4261
|
+
["dif", "upright(d)"],
|
|
4262
|
+
["eq.def", 'limits(=)^"def"'],
|
|
4263
|
+
["oo", "infinity"],
|
|
4264
|
+
["comma", ","],
|
|
4265
|
+
["hyph", '"-"'],
|
|
4266
|
+
["hyph.minus", '"-"']
|
|
4267
|
+
/*
|
|
4268
|
+
["AA", "bb(A)"],
|
|
4269
|
+
["BB", "bb(B)"],
|
|
4270
|
+
["CC", "bb(C)"],
|
|
4271
|
+
*/
|
|
4272
|
+
]);
|
|
4273
|
+
function _expand_typst_predefined_variables(node) {
|
|
4274
|
+
switch (node.type) {
|
|
4275
|
+
case "terminal": {
|
|
4276
|
+
if (node.head.type === 1 /* SYMBOL */) {
|
|
4277
|
+
if (TEX_PREDEFINED_VARIABLES.has(node.head.value)) {
|
|
4278
|
+
const target_str = TEX_PREDEFINED_VARIABLES.get(node.head.value);
|
|
4279
|
+
return parseTypst(target_str);
|
|
4280
|
+
}
|
|
4281
|
+
}
|
|
4282
|
+
}
|
|
4283
|
+
case "funcCall":
|
|
4284
|
+
default:
|
|
4285
|
+
return node;
|
|
4286
|
+
}
|
|
4287
|
+
}
|
|
4288
|
+
function expand_typst_predefined_variables(node) {
|
|
4289
|
+
return node.bottomTopTraversalTransform(_expand_typst_predefined_variables);
|
|
4290
|
+
}
|
|
4291
|
+
|
|
4348
4292
|
// src/index.ts
|
|
4349
4293
|
function tex2typst(tex, options = {}) {
|
|
4350
4294
|
const opt = {
|
|
@@ -4384,7 +4328,8 @@ function typst2tex(typst, options = {}) {
|
|
|
4384
4328
|
}
|
|
4385
4329
|
}
|
|
4386
4330
|
const typstTree = parseTypst(typst);
|
|
4387
|
-
const
|
|
4331
|
+
const preprocessedTypstTree = expand_typst_predefined_variables(typstTree);
|
|
4332
|
+
const texTree = convert_typst_node_to_tex(preprocessedTypstTree, opt);
|
|
4388
4333
|
const writer = new TexWriter();
|
|
4389
4334
|
writer.append(texTree);
|
|
4390
4335
|
return writer.finalize();
|