tex2typst 0.3.23 → 0.3.24
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/convert.d.ts +9 -3
- package/dist/generic.d.ts +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2092 -2009
- package/dist/tex-parser.d.ts +1 -1
- package/dist/tex-tokenizer.d.ts +1 -1
- package/dist/tex-types.d.ts +103 -0
- package/dist/tex-writer.d.ts +1 -2
- package/dist/tex2typst.min.js +13 -13
- package/dist/typst-parser.d.ts +6 -4
- package/dist/typst-tokenizer.d.ts +1 -1
- package/dist/typst-types.d.ts +95 -0
- package/dist/typst-writer.d.ts +4 -2
- package/package.json +1 -1
- package/src/convert.ts +455 -393
- package/src/generic.ts +28 -2
- package/src/index.ts +1 -1
- package/src/map.ts +5 -0
- package/src/tex-parser.ts +45 -54
- package/src/tex-tokenizer.ts +1 -1
- package/src/tex-types.ts +358 -0
- package/src/tex-writer.ts +3 -51
- package/src/typst-parser.ts +53 -55
- package/src/typst-tokenizer.ts +86 -85
- package/src/typst-types.ts +221 -0
- package/src/typst-writer.ts +79 -65
- package/src/util.ts +1 -1
- package/dist/types.d.ts +0 -109
- package/src/types.ts +0 -414
package/src/typst-parser.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
|
|
2
2
|
import { array_find } from "./generic";
|
|
3
|
-
import {
|
|
3
|
+
import { TypstCases, TypstFraction, TypstFuncCall, TypstGroup, TypstLeftright, TypstLeftRightData, TypstMatrix, TypstNode, TypstSupsub } from "./typst-types";
|
|
4
|
+
import { TypstNamedParams } from "./typst-types";
|
|
5
|
+
import { TypstSupsubData } from "./typst-types";
|
|
6
|
+
import { TypstToken } from "./typst-types";
|
|
7
|
+
import { TypstTokenType } from "./typst-types";
|
|
4
8
|
import { tokenize_typst } from "./typst-tokenizer";
|
|
5
9
|
import { assert, isalpha } from "./util";
|
|
6
10
|
|
|
@@ -24,7 +28,7 @@ function _find_closing_match(tokens: TypstToken[], start: number,
|
|
|
24
28
|
|
|
25
29
|
while (count > 0) {
|
|
26
30
|
if (pos >= tokens.length) {
|
|
27
|
-
throw new Error('Unmatched brackets');
|
|
31
|
+
throw new Error('Unmatched brackets or parentheses');
|
|
28
32
|
}
|
|
29
33
|
if (tokens[pos].isOneOf(rightBrackets)) {
|
|
30
34
|
count -= 1;
|
|
@@ -58,8 +62,10 @@ function find_closing_delim(tokens: TypstToken[], start: number): number {
|
|
|
58
62
|
|
|
59
63
|
|
|
60
64
|
function find_closing_parenthesis(nodes: TypstNode[], start: number): number {
|
|
61
|
-
const left_parenthesis = new
|
|
62
|
-
const right_parenthesis = new
|
|
65
|
+
const left_parenthesis = new TypstToken(TypstTokenType.ELEMENT, '(').toNode();
|
|
66
|
+
const right_parenthesis = new TypstToken(TypstTokenType.ELEMENT, ')').toNode();
|
|
67
|
+
|
|
68
|
+
|
|
63
69
|
|
|
64
70
|
assert(nodes[start].eq(left_parenthesis));
|
|
65
71
|
|
|
@@ -68,7 +74,7 @@ function find_closing_parenthesis(nodes: TypstNode[], start: number): number {
|
|
|
68
74
|
|
|
69
75
|
while (count > 0) {
|
|
70
76
|
if (pos >= nodes.length) {
|
|
71
|
-
throw new Error(
|
|
77
|
+
throw new Error("Unmatched '('");
|
|
72
78
|
}
|
|
73
79
|
if (nodes[pos].eq(left_parenthesis)) {
|
|
74
80
|
count += 1;
|
|
@@ -84,18 +90,18 @@ function find_closing_parenthesis(nodes: TypstNode[], start: number): number {
|
|
|
84
90
|
function primes(num: number): TypstNode[] {
|
|
85
91
|
const res: TypstNode[] = [];
|
|
86
92
|
for (let i = 0; i < num; i++) {
|
|
87
|
-
res.push(new
|
|
93
|
+
res.push(new TypstToken(TypstTokenType.ELEMENT, "'").toNode());
|
|
88
94
|
}
|
|
89
95
|
return res;
|
|
90
96
|
}
|
|
91
97
|
|
|
92
|
-
const DIV = new
|
|
98
|
+
const DIV = new TypstToken(TypstTokenType.ELEMENT, '/').toNode();
|
|
93
99
|
|
|
94
100
|
|
|
95
101
|
|
|
96
102
|
function next_non_whitespace(nodes: TypstNode[], start: number): TypstNode | null {
|
|
97
103
|
let pos = start;
|
|
98
|
-
while (pos < nodes.length && nodes[pos].type ===
|
|
104
|
+
while (pos < nodes.length && (nodes[pos].head.type === TypstTokenType.SPACE || nodes[pos].head.type === TypstTokenType.NEWLINE)) {
|
|
99
105
|
pos++;
|
|
100
106
|
}
|
|
101
107
|
return pos === nodes.length ? null : nodes[pos];
|
|
@@ -106,7 +112,7 @@ function trim_whitespace_around_operators(nodes: TypstNode[]): TypstNode[] {
|
|
|
106
112
|
const res: TypstNode[] = [];
|
|
107
113
|
for (let i = 0; i < nodes.length; i++) {
|
|
108
114
|
const current = nodes[i];
|
|
109
|
-
if (current.type ===
|
|
115
|
+
if (current.head.type === TypstTokenType.SPACE || current.head.type === TypstTokenType.NEWLINE) {
|
|
110
116
|
if(after_operator) {
|
|
111
117
|
continue;
|
|
112
118
|
}
|
|
@@ -127,8 +133,8 @@ function trim_whitespace_around_operators(nodes: TypstNode[]): TypstNode[] {
|
|
|
127
133
|
function process_operators(nodes: TypstNode[], parenthesis = false): TypstNode {
|
|
128
134
|
nodes = trim_whitespace_around_operators(nodes);
|
|
129
135
|
|
|
130
|
-
const opening_bracket =
|
|
131
|
-
const closing_bracket =
|
|
136
|
+
const opening_bracket = LEFT_PARENTHESES.toNode();
|
|
137
|
+
const closing_bracket = RIGHT_PARENTHESES.toNode();
|
|
132
138
|
|
|
133
139
|
const stack: TypstNode[] = [];
|
|
134
140
|
|
|
@@ -155,20 +161,20 @@ function process_operators(nodes: TypstNode[], parenthesis = false): TypstNode {
|
|
|
155
161
|
}
|
|
156
162
|
|
|
157
163
|
if(stack.length > 0 && stack[stack.length-1].eq(DIV)) {
|
|
158
|
-
|
|
164
|
+
let denominator = current_tree;
|
|
159
165
|
if(args.length === 0) {
|
|
160
166
|
throw new TypstParserError("Unexpected '/' operator, no numerator before it");
|
|
161
167
|
}
|
|
162
|
-
|
|
168
|
+
let numerator = args.pop()!;
|
|
163
169
|
|
|
164
|
-
if(denominator.type === '
|
|
165
|
-
denominator
|
|
170
|
+
if(denominator.type === 'leftright') {
|
|
171
|
+
denominator = new TypstGroup(denominator.args!);
|
|
166
172
|
}
|
|
167
|
-
if(numerator.type === '
|
|
168
|
-
numerator
|
|
173
|
+
if(numerator.type === 'leftright') {
|
|
174
|
+
numerator = new TypstGroup(numerator.args!);
|
|
169
175
|
}
|
|
170
176
|
|
|
171
|
-
args.push(new
|
|
177
|
+
args.push(new TypstFraction([numerator, denominator]));
|
|
172
178
|
stack.pop(); // drop the '/' operator
|
|
173
179
|
} else {
|
|
174
180
|
args.push(current_tree);
|
|
@@ -176,12 +182,12 @@ function process_operators(nodes: TypstNode[], parenthesis = false): TypstNode {
|
|
|
176
182
|
}
|
|
177
183
|
}
|
|
178
184
|
if(parenthesis) {
|
|
179
|
-
return new
|
|
185
|
+
return new TypstLeftright(null, args, { left: LEFT_PARENTHESES, right: RIGHT_PARENTHESES } as TypstLeftRightData);
|
|
180
186
|
} else {
|
|
181
187
|
if(args.length === 1) {
|
|
182
188
|
return args[0];
|
|
183
189
|
} else {
|
|
184
|
-
return new
|
|
190
|
+
return new TypstGroup(args);
|
|
185
191
|
}
|
|
186
192
|
}
|
|
187
193
|
}
|
|
@@ -208,6 +214,7 @@ const VERTICAL_BAR = new TypstToken(TypstTokenType.ELEMENT, '|');
|
|
|
208
214
|
const COMMA = new TypstToken(TypstTokenType.ELEMENT, ',');
|
|
209
215
|
const SEMICOLON = new TypstToken(TypstTokenType.ELEMENT, ';');
|
|
210
216
|
const SINGLE_SPACE = new TypstToken(TypstTokenType.SPACE, ' ');
|
|
217
|
+
const CONTROL_AND = new TypstToken(TypstTokenType.CONTROL, '&');
|
|
211
218
|
|
|
212
219
|
export class TypstParser {
|
|
213
220
|
space_sensitive: boolean;
|
|
@@ -230,11 +237,11 @@ export class TypstParser {
|
|
|
230
237
|
while (pos < end) {
|
|
231
238
|
const [res, newPos] = this.parseNextExpr(tokens, pos);
|
|
232
239
|
pos = newPos;
|
|
233
|
-
if (res.type ===
|
|
234
|
-
if (!this.space_sensitive && res.
|
|
240
|
+
if (res.head.type === TypstTokenType.SPACE || res.head.type === TypstTokenType.NEWLINE) {
|
|
241
|
+
if (!this.space_sensitive && res.head.value.replace(/ /g, '').length === 0) {
|
|
235
242
|
continue;
|
|
236
243
|
}
|
|
237
|
-
if (!this.newline_sensitive && res.
|
|
244
|
+
if (!this.newline_sensitive && res.head.value === '\n') {
|
|
238
245
|
continue;
|
|
239
246
|
}
|
|
240
247
|
}
|
|
@@ -261,7 +268,7 @@ export class TypstParser {
|
|
|
261
268
|
|
|
262
269
|
const num_base_prime = eat_primes(tokens, pos);
|
|
263
270
|
if (num_base_prime > 0) {
|
|
264
|
-
base = new
|
|
271
|
+
base = new TypstGroup([base].concat(primes(num_base_prime)));
|
|
265
272
|
pos += num_base_prime;
|
|
266
273
|
}
|
|
267
274
|
if (pos < tokens.length && tokens[pos].eq(SUB_SYMBOL)) {
|
|
@@ -277,14 +284,8 @@ export class TypstParser {
|
|
|
277
284
|
}
|
|
278
285
|
|
|
279
286
|
if (sub !== null || sup !== null) {
|
|
280
|
-
const res: TypstSupsubData = { base };
|
|
281
|
-
|
|
282
|
-
res.sub = sub;
|
|
283
|
-
}
|
|
284
|
-
if (sup) {
|
|
285
|
-
res.sup = sup;
|
|
286
|
-
}
|
|
287
|
-
return [new TypstNode('supsub', '', [], res), pos];
|
|
287
|
+
const res: TypstSupsubData = { base, sup, sub };
|
|
288
|
+
return [new TypstSupsub(res), pos];
|
|
288
289
|
} else {
|
|
289
290
|
return [base, pos];
|
|
290
291
|
}
|
|
@@ -301,7 +302,7 @@ export class TypstParser {
|
|
|
301
302
|
}
|
|
302
303
|
const num_prime = eat_primes(tokens, end);
|
|
303
304
|
if (num_prime > 0) {
|
|
304
|
-
node = new
|
|
305
|
+
node = new TypstGroup([node].concat(primes(num_prime)));
|
|
305
306
|
end += num_prime;
|
|
306
307
|
}
|
|
307
308
|
return [node, end];
|
|
@@ -320,24 +321,22 @@ export class TypstParser {
|
|
|
320
321
|
if ([TypstTokenType.ELEMENT, TypstTokenType.SYMBOL].includes(firstToken.type)) {
|
|
321
322
|
if (start + 1 < tokens.length && tokens[start + 1].eq(LEFT_PARENTHESES)) {
|
|
322
323
|
if(firstToken.value === 'mat') {
|
|
323
|
-
const [matrix, named_params, newPos] = this.
|
|
324
|
-
const mat = new
|
|
324
|
+
const [matrix, named_params, newPos] = this.parseMatrix(tokens, start + 1, SEMICOLON, COMMA);
|
|
325
|
+
const mat = new TypstMatrix(matrix);
|
|
325
326
|
mat.setOptions(named_params);
|
|
326
327
|
return [mat, newPos];
|
|
327
328
|
}
|
|
328
329
|
if(firstToken.value === 'cases') {
|
|
329
|
-
const [cases, named_params, newPos] = this.
|
|
330
|
-
const casesNode = new
|
|
330
|
+
const [cases, named_params, newPos] = this.parseMatrix(tokens, start + 1, COMMA, CONTROL_AND);
|
|
331
|
+
const casesNode = new TypstCases(cases);
|
|
331
332
|
casesNode.setOptions(named_params);
|
|
332
333
|
return [casesNode, newPos];
|
|
333
334
|
}
|
|
334
335
|
if (firstToken.value === 'lr') {
|
|
335
|
-
|
|
336
|
-
const func_call = new TypstNode('funcCall', firstToken.value, args, lrData);
|
|
337
|
-
return [func_call, newPos];
|
|
336
|
+
return this.parseLrArguments(tokens, start + 1);
|
|
338
337
|
}
|
|
339
338
|
const [args, newPos] = this.parseArguments(tokens, start + 1);
|
|
340
|
-
const func_call = new
|
|
339
|
+
const func_call = new TypstFuncCall(firstToken, args);
|
|
341
340
|
return [func_call, newPos];
|
|
342
341
|
}
|
|
343
342
|
}
|
|
@@ -348,33 +347,32 @@ export class TypstParser {
|
|
|
348
347
|
// start: the position of the left parentheses
|
|
349
348
|
parseArguments(tokens: TypstToken[], start: number): [TypstNode[], number] {
|
|
350
349
|
const end = find_closing_match(tokens, start);
|
|
351
|
-
return [this.
|
|
350
|
+
return [this.parseArgumentsWithSeparator(tokens, start + 1, end, COMMA), end + 1];
|
|
352
351
|
}
|
|
353
352
|
|
|
354
353
|
// start: the position of the left parentheses
|
|
355
|
-
parseLrArguments(tokens: TypstToken[], start: number): [TypstNode
|
|
354
|
+
parseLrArguments(tokens: TypstToken[], start: number): [TypstNode, number] {
|
|
355
|
+
const lr_token = tokens[start];
|
|
356
356
|
if (tokens[start + 1].isOneOf([LEFT_PARENTHESES, LEFT_BRACKET, LEFT_CURLY_BRACKET, VERTICAL_BAR])) {
|
|
357
357
|
const end = find_closing_match(tokens, start);
|
|
358
358
|
const inner_start = start + 1;
|
|
359
359
|
const inner_end = find_closing_delim(tokens, inner_start);
|
|
360
|
-
const inner_args= this.
|
|
360
|
+
const inner_args= this.parseArgumentsWithSeparator(tokens, inner_start + 1, inner_end, COMMA);
|
|
361
361
|
return [
|
|
362
|
-
inner_args,
|
|
362
|
+
new TypstLeftright(lr_token, inner_args, {left: tokens[inner_start], right: tokens[inner_end]}),
|
|
363
363
|
end + 1,
|
|
364
|
-
{leftDelim: tokens[inner_start].value, rightDelim: tokens[inner_end].value} as TypstLrData
|
|
365
364
|
];
|
|
366
365
|
} else {
|
|
367
366
|
const [args, end] = this.parseArguments(tokens, start);
|
|
368
367
|
return [
|
|
369
|
-
args,
|
|
368
|
+
new TypstLeftright(lr_token, args, { left: null, right: null }),
|
|
370
369
|
end,
|
|
371
|
-
{leftDelim: null, rightDelim: null} as TypstLrData,
|
|
372
370
|
];
|
|
373
371
|
}
|
|
374
372
|
}
|
|
375
373
|
|
|
376
374
|
// start: the position of the left parentheses
|
|
377
|
-
|
|
375
|
+
parseMatrix(tokens: TypstToken[], start: number, rowSepToken: TypstToken, cellSepToken: TypstToken): [TypstNode[][], TypstNamedParams, number] {
|
|
378
376
|
const end = find_closing_match(tokens, start);
|
|
379
377
|
tokens = tokens.slice(0, end);
|
|
380
378
|
|
|
@@ -384,16 +382,16 @@ export class TypstParser {
|
|
|
384
382
|
let pos = start + 1;
|
|
385
383
|
while (pos < end) {
|
|
386
384
|
while(pos < end) {
|
|
387
|
-
let next_stop = array_find(tokens,
|
|
385
|
+
let next_stop = array_find(tokens, rowSepToken, pos);
|
|
388
386
|
if (next_stop === -1) {
|
|
389
387
|
next_stop = end;
|
|
390
388
|
}
|
|
391
389
|
|
|
392
|
-
let row = this.
|
|
390
|
+
let row = this.parseArgumentsWithSeparator(tokens, pos, next_stop, cellSepToken);
|
|
393
391
|
let np: TypstNamedParams = {};
|
|
394
392
|
|
|
395
393
|
function extract_named_params(arr: TypstNode[]): [TypstNode[], TypstNamedParams] {
|
|
396
|
-
const COLON = new
|
|
394
|
+
const COLON = new TypstToken(TypstTokenType.ELEMENT, ':').toNode();
|
|
397
395
|
const np: TypstNamedParams = {};
|
|
398
396
|
|
|
399
397
|
const to_delete: number[] = [];
|
|
@@ -409,7 +407,7 @@ export class TypstParser {
|
|
|
409
407
|
}
|
|
410
408
|
to_delete.push(i);
|
|
411
409
|
const param_name = g.args![pos_colon - 1];
|
|
412
|
-
if(param_name.eq(new
|
|
410
|
+
if(param_name.eq(new TypstToken(TypstTokenType.SYMBOL, 'delim').toNode())) {
|
|
413
411
|
if(g.args!.length !== 3) {
|
|
414
412
|
throw new TypstParserError('Invalid number of arguments for delim');
|
|
415
413
|
}
|
|
@@ -435,13 +433,13 @@ export class TypstParser {
|
|
|
435
433
|
}
|
|
436
434
|
|
|
437
435
|
// start: the position of the first token of arguments
|
|
438
|
-
|
|
436
|
+
parseArgumentsWithSeparator(tokens: TypstToken[], start: number, end: number, sepToken: TypstToken): TypstNode[] {
|
|
439
437
|
const args: TypstNode[] = [];
|
|
440
438
|
let pos = start;
|
|
441
439
|
while (pos < end) {
|
|
442
440
|
let nodes: TypstNode[] = [];
|
|
443
441
|
while(pos < end) {
|
|
444
|
-
if(tokens[pos].eq(
|
|
442
|
+
if(tokens[pos].eq(sepToken)) {
|
|
445
443
|
pos += 1;
|
|
446
444
|
break;
|
|
447
445
|
} else if(tokens[pos].eq(SINGLE_SPACE)) {
|
package/src/typst-tokenizer.ts
CHANGED
|
@@ -1,85 +1,86 @@
|
|
|
1
|
-
import { TypstToken
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
s = s.replaceAll('
|
|
12
|
-
s = s.replaceAll('
|
|
13
|
-
s = s.replaceAll('
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
[String.raw
|
|
25
|
-
[String.raw
|
|
26
|
-
[String.raw
|
|
27
|
-
[String.raw`\
|
|
28
|
-
[String.raw
|
|
29
|
-
[String.raw
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
new TypstToken(TypstTokenType.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
new TypstToken(TypstTokenType.
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
[
|
|
44
|
-
|
|
45
|
-
(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
[String.raw`[
|
|
62
|
-
[String.raw
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
new TypstToken(TypstTokenType.
|
|
67
|
-
new TypstToken(TypstTokenType.
|
|
68
|
-
new TypstToken(TypstTokenType.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
[String.raw
|
|
76
|
-
]
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
1
|
+
import { TypstToken } from "./typst-types";
|
|
2
|
+
import { TypstTokenType } from "./typst-types";
|
|
3
|
+
import { reverseShorthandMap } from "./typst-shorthands";
|
|
4
|
+
import { JSLex, Scanner } from "./jslex";
|
|
5
|
+
|
|
6
|
+
const TYPST_SHORTHANDS = Array.from(reverseShorthandMap.keys());
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
function generate_regex_for_shorthands(): string {
|
|
10
|
+
const regex_list = TYPST_SHORTHANDS.map((s) => {
|
|
11
|
+
s = s.replaceAll('|', '\\|');
|
|
12
|
+
s = s.replaceAll('.', '\\.');
|
|
13
|
+
s = s.replaceAll('[', '\\[');
|
|
14
|
+
s = s.replaceAll(']', '\\]');
|
|
15
|
+
return s;
|
|
16
|
+
});
|
|
17
|
+
return `(${regex_list.join('|')})`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
const REGEX_SHORTHANDS = generate_regex_for_shorthands();
|
|
22
|
+
|
|
23
|
+
const rules_map = new Map<string, (a: Scanner<TypstToken>) => TypstToken | TypstToken[]>([
|
|
24
|
+
[String.raw`//[^\n]*`, (s) => new TypstToken(TypstTokenType.COMMENT, s.text()!.substring(2))],
|
|
25
|
+
[String.raw`/`, (s) => new TypstToken(TypstTokenType.ELEMENT, s.text()!)],
|
|
26
|
+
[String.raw`[_^&]`, (s) => new TypstToken(TypstTokenType.CONTROL, s.text()!)],
|
|
27
|
+
[String.raw`\r?\n`, (_s) => new TypstToken(TypstTokenType.NEWLINE, "\n")],
|
|
28
|
+
[String.raw`\s+`, (s) => new TypstToken(TypstTokenType.SPACE, s.text()!)],
|
|
29
|
+
[String.raw`\\[$&#_]`, (s) => new TypstToken(TypstTokenType.ELEMENT, s.text()!)],
|
|
30
|
+
[String.raw`\\\n`, (s) => {
|
|
31
|
+
return [
|
|
32
|
+
new TypstToken(TypstTokenType.CONTROL, "\\"),
|
|
33
|
+
new TypstToken(TypstTokenType.NEWLINE, "\n"),
|
|
34
|
+
]
|
|
35
|
+
}],
|
|
36
|
+
[String.raw`\\\s`, (s) => {
|
|
37
|
+
return [
|
|
38
|
+
new TypstToken(TypstTokenType.CONTROL, "\\"),
|
|
39
|
+
new TypstToken(TypstTokenType.SPACE, " "),
|
|
40
|
+
]
|
|
41
|
+
}],
|
|
42
|
+
// this backslash is dummy and will be ignored in later stages
|
|
43
|
+
[String.raw`\\\S`, (_s) => new TypstToken(TypstTokenType.CONTROL, "")],
|
|
44
|
+
[
|
|
45
|
+
String.raw`"([^"]|(\\"))*"`,
|
|
46
|
+
(s) => {
|
|
47
|
+
const text = s.text()!.substring(1, s.text()!.length - 1);
|
|
48
|
+
// replace all escape characters with their actual characters
|
|
49
|
+
text.replaceAll('\\"', '"');
|
|
50
|
+
return new TypstToken(TypstTokenType.TEXT, text);
|
|
51
|
+
}
|
|
52
|
+
],
|
|
53
|
+
[
|
|
54
|
+
REGEX_SHORTHANDS,
|
|
55
|
+
(s) => {
|
|
56
|
+
const shorthand = s.text()!;
|
|
57
|
+
const symbol = reverseShorthandMap.get(shorthand)!;
|
|
58
|
+
return new TypstToken(TypstTokenType.SYMBOL, symbol);
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
[String.raw`[0-9]+(\.[0-9]+)?`, (s) => new TypstToken(TypstTokenType.ELEMENT, s.text()!)],
|
|
62
|
+
[String.raw`[+\-*/=\'<>!.,;?()\[\]|]`, (s) => new TypstToken(TypstTokenType.ELEMENT, s.text()!)],
|
|
63
|
+
[String.raw`#h\((.+?)\)`, (s) => {
|
|
64
|
+
const match = s.reMatchArray()!;
|
|
65
|
+
return [
|
|
66
|
+
new TypstToken(TypstTokenType.SYMBOL, "#h"),
|
|
67
|
+
new TypstToken(TypstTokenType.ELEMENT, "("),
|
|
68
|
+
new TypstToken(TypstTokenType.LITERAL, match[1]),
|
|
69
|
+
new TypstToken(TypstTokenType.ELEMENT, ")"),
|
|
70
|
+
];
|
|
71
|
+
}],
|
|
72
|
+
[String.raw`[a-zA-Z\.]+`, (s) => {
|
|
73
|
+
return new TypstToken(s.text()!.length === 1? TypstTokenType.ELEMENT: TypstTokenType.SYMBOL, s.text()!);
|
|
74
|
+
}],
|
|
75
|
+
[String.raw`#none`, (s) => new TypstToken(TypstTokenType.NONE, s.text()!)],
|
|
76
|
+
[String.raw`.`, (s) => new TypstToken(TypstTokenType.ELEMENT, s.text()!)],
|
|
77
|
+
]);
|
|
78
|
+
|
|
79
|
+
const spec = {
|
|
80
|
+
"start": rules_map
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export function tokenize_typst(input: string): TypstToken[] {
|
|
84
|
+
const lexer = new JSLex<TypstToken>(spec);
|
|
85
|
+
return lexer.collect(input);
|
|
86
|
+
}
|