tex2typst 0.3.7 → 0.3.9
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/generic.d.ts +1 -0
- package/dist/index.js +148 -69
- package/dist/tex2typst.min.js +13 -13
- package/dist/types.d.ts +7 -3
- package/dist/typst-parser.d.ts +2 -1
- package/package.json +1 -1
- package/src/convert.ts +39 -9
- package/src/generic.ts +13 -0
- package/src/tex-parser.ts +23 -13
- package/src/types.ts +32 -39
- package/src/typst-parser.ts +65 -15
package/src/convert.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import { TexNode, TypstNode, TexSupsubData, TypstSupsubData, TexSqrtData, Tex2TypstOptions, TYPST_NONE, TYPST_TRUE, TypstPrimitiveValue, TypstToken, TypstTokenType } from "./types";
|
|
1
|
+
import { TexNode, TypstNode, TexSupsubData, TypstSupsubData, TexSqrtData, Tex2TypstOptions, TYPST_NONE, TYPST_TRUE, TypstPrimitiveValue, TypstToken, TypstTokenType, TypstLrData } from "./types";
|
|
2
2
|
import { TypstWriterError } from "./typst-writer";
|
|
3
3
|
import { symbolMap, reverseSymbolMap } from "./map";
|
|
4
|
+
import { array_join } from "./generic";
|
|
5
|
+
import { assert } from "./util";
|
|
6
|
+
|
|
4
7
|
|
|
5
8
|
// symbols that are supported by Typst but not by KaTeX
|
|
6
9
|
const TYPST_INTRINSIC_SYMBOLS = [
|
|
@@ -344,6 +347,8 @@ const TYPST_UNARY_FUNCTIONS: string[] = [
|
|
|
344
347
|
'bb',
|
|
345
348
|
'cal',
|
|
346
349
|
'frak',
|
|
350
|
+
'floor',
|
|
351
|
+
'ceil',
|
|
347
352
|
];
|
|
348
353
|
|
|
349
354
|
const TYPST_BINARY_FUNCTIONS: string[] = [
|
|
@@ -372,6 +377,7 @@ function typst_token_to_tex(token: string): string {
|
|
|
372
377
|
}
|
|
373
378
|
|
|
374
379
|
|
|
380
|
+
const TEX_NODE_COMMA = new TexNode('element', ',');
|
|
375
381
|
|
|
376
382
|
export function convert_typst_node_to_tex(node: TypstNode): TexNode {
|
|
377
383
|
// special hook for eq.def
|
|
@@ -406,24 +412,48 @@ export function convert_typst_node_to_tex(node: TypstNode): TexNode {
|
|
|
406
412
|
return new TexNode('comment', node.content);
|
|
407
413
|
case 'group': {
|
|
408
414
|
const args = node.args!.map(convert_typst_node_to_tex);
|
|
415
|
+
if (node.content === 'parenthesis') {
|
|
416
|
+
const is_over_high = node.isOverHigh();
|
|
417
|
+
const left_delim = is_over_high ? '\\left(' : '(';
|
|
418
|
+
const right_delim = is_over_high ? '\\right)' : ')';
|
|
419
|
+
args.unshift(new TexNode('element', left_delim));
|
|
420
|
+
args.push(new TexNode('element', right_delim));
|
|
421
|
+
}
|
|
409
422
|
return new TexNode('ordgroup', node.content, args);
|
|
410
423
|
}
|
|
411
424
|
case 'funcCall': {
|
|
412
425
|
if (TYPST_UNARY_FUNCTIONS.includes(node.content)) {
|
|
413
426
|
// special hook for lr
|
|
414
427
|
if (node.content === 'lr') {
|
|
415
|
-
const
|
|
416
|
-
if (
|
|
417
|
-
let left_delim =
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
right_delim = apply_escape_if_needed(right_delim);
|
|
428
|
+
const data = node.data as TypstLrData;
|
|
429
|
+
if (data.leftDelim !== null) {
|
|
430
|
+
let left_delim = apply_escape_if_needed(data.leftDelim);
|
|
431
|
+
assert(data.rightDelim !== null, "leftDelim has value but rightDelim not");
|
|
432
|
+
let right_delim = apply_escape_if_needed(data.rightDelim!);
|
|
421
433
|
return new TexNode('ordgroup', '', [
|
|
422
434
|
new TexNode('element', '\\left' + left_delim),
|
|
423
|
-
...
|
|
435
|
+
...node.args!.map(convert_typst_node_to_tex),
|
|
424
436
|
new TexNode('element', '\\right' + right_delim)
|
|
425
437
|
]);
|
|
438
|
+
} else {
|
|
439
|
+
return new TexNode('ordgroup', '', node.args!.map(convert_typst_node_to_tex));
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
// special hook for floor, ceil
|
|
443
|
+
// Typst "floor(a) + ceil(b)" should converts to Tex "\lfloor a \rfloor + \lceil b \rceil"
|
|
444
|
+
if (node.content === 'floor' || node.content === 'ceil') {
|
|
445
|
+
let left = "\\l" + node.content;
|
|
446
|
+
let right = "\\r" + node.content;
|
|
447
|
+
const arg0 = node.args![0];
|
|
448
|
+
if (arg0.isOverHigh()) {
|
|
449
|
+
left = "\\left" + left;
|
|
450
|
+
right = "\\right" + right;
|
|
426
451
|
}
|
|
452
|
+
return new TexNode('ordgroup', '', [
|
|
453
|
+
new TexNode('symbol', left),
|
|
454
|
+
convert_typst_node_to_tex(arg0),
|
|
455
|
+
new TexNode('symbol', right)
|
|
456
|
+
]);
|
|
427
457
|
}
|
|
428
458
|
const command = typst_token_to_tex(node.content);
|
|
429
459
|
return new TexNode('unaryFunc', command, node.args!.map(convert_typst_node_to_tex));
|
|
@@ -448,7 +478,7 @@ export function convert_typst_node_to_tex(node: TypstNode): TexNode {
|
|
|
448
478
|
return new TexNode('ordgroup', '', [
|
|
449
479
|
new TexNode('symbol', typst_token_to_tex(node.content)),
|
|
450
480
|
new TexNode('element', '('),
|
|
451
|
-
...node.args!.map(convert_typst_node_to_tex),
|
|
481
|
+
...array_join(node.args!.map(convert_typst_node_to_tex), TEX_NODE_COMMA),
|
|
452
482
|
new TexNode('element', ')')
|
|
453
483
|
]);
|
|
454
484
|
}
|
package/src/generic.ts
CHANGED
|
@@ -34,4 +34,17 @@ export function array_split<T extends IEquatable>(array: T[], sep: T): T[][] {
|
|
|
34
34
|
}
|
|
35
35
|
res.push(current_slice);
|
|
36
36
|
return res;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// e.g. input array=['a', 'b', 'c'], sep = '+'
|
|
40
|
+
// return ['a','+', 'b', '+','c']
|
|
41
|
+
export function array_join<T>(array: T[], sep: T): T[] {
|
|
42
|
+
const res: T[] = [];
|
|
43
|
+
for (let i = 0; i < array.length; i++) {
|
|
44
|
+
res.push(array[i]);
|
|
45
|
+
if (i != array.length - 1) {
|
|
46
|
+
res.push(sep);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return res;
|
|
37
50
|
}
|
package/src/tex-parser.ts
CHANGED
|
@@ -175,25 +175,35 @@ const rules_map = new Map<string, (a: Scanner<TexToken>) => TexToken | TexToken[
|
|
|
175
175
|
const match = text.match(regex);
|
|
176
176
|
assert(match !== null);
|
|
177
177
|
const command = match![1];
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
178
|
+
if (BINARY_COMMANDS.includes(command.substring(1))) {
|
|
179
|
+
const arg1 = match![2].trimStart();
|
|
180
|
+
const arg2 = match![3];
|
|
181
|
+
return [
|
|
182
|
+
new TexToken(TexTokenType.COMMAND, command),
|
|
183
|
+
new TexToken(TexTokenType.ELEMENT, arg1),
|
|
184
|
+
new TexToken(TexTokenType.ELEMENT, arg2),
|
|
185
|
+
];
|
|
186
|
+
} else {
|
|
187
|
+
s.reject();
|
|
188
|
+
return [];
|
|
189
|
+
}
|
|
190
|
+
}],
|
|
186
191
|
[String.raw`(\\[a-zA-Z]+)(\s*\d|\s+[a-zA-Z])`, (s) => {
|
|
187
192
|
const text = s.text()!;
|
|
188
193
|
const regex = RegExp(String.raw`(\\[a-zA-Z]+)(\s*\d|\s+[a-zA-Z])`);
|
|
189
194
|
const match = text.match(regex);
|
|
190
195
|
assert(match !== null);
|
|
191
196
|
const command = match![1];
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
+
if (UNARY_COMMANDS.includes(command.substring(1))) {
|
|
198
|
+
const arg1 = match![2].trimStart();
|
|
199
|
+
return [
|
|
200
|
+
new TexToken(TexTokenType.COMMAND, command),
|
|
201
|
+
new TexToken(TexTokenType.ELEMENT, arg1),
|
|
202
|
+
];
|
|
203
|
+
} else {
|
|
204
|
+
s.reject();
|
|
205
|
+
return [];
|
|
206
|
+
}
|
|
197
207
|
}],
|
|
198
208
|
[String.raw`\\[a-zA-Z]+`, (s) => {
|
|
199
209
|
const command = s.text()!;
|
package/src/types.ts
CHANGED
|
@@ -123,15 +123,7 @@ export class TexNode {
|
|
|
123
123
|
return tokens;
|
|
124
124
|
}
|
|
125
125
|
case 'ordgroup': {
|
|
126
|
-
|
|
127
|
-
if(this.content === 'parenthesis') {
|
|
128
|
-
const is_over_high = this.isOverHigh();
|
|
129
|
-
const left_delim = is_over_high ? '\\left(' : '(';
|
|
130
|
-
const right_delim = is_over_high ? '\\right)' : ')';
|
|
131
|
-
tokens.unshift(new TexToken(TexTokenType.ELEMENT, left_delim));
|
|
132
|
-
tokens.push(new TexToken(TexTokenType.ELEMENT, right_delim));
|
|
133
|
-
}
|
|
134
|
-
return tokens;
|
|
126
|
+
return this.args!.map((n) => n.serialize()).flat();
|
|
135
127
|
}
|
|
136
128
|
case 'unaryFunc': {
|
|
137
129
|
let tokens: TexToken[] = [];
|
|
@@ -238,34 +230,6 @@ export class TexNode {
|
|
|
238
230
|
throw new Error('[TexNode.serialize] Unimplemented type: ' + this.type);
|
|
239
231
|
}
|
|
240
232
|
}
|
|
241
|
-
|
|
242
|
-
// whether the node is over high so that if it's wrapped in braces, \left and \right should be used.
|
|
243
|
-
// e.g. \frac{1}{2} is over high, "2" is not.
|
|
244
|
-
public isOverHigh(): boolean {
|
|
245
|
-
switch (this.type) {
|
|
246
|
-
case 'element':
|
|
247
|
-
case 'symbol':
|
|
248
|
-
case 'text':
|
|
249
|
-
case 'control':
|
|
250
|
-
case 'empty':
|
|
251
|
-
return false;
|
|
252
|
-
case 'binaryFunc':
|
|
253
|
-
if(this.content === '\\frac') {
|
|
254
|
-
return true;
|
|
255
|
-
}
|
|
256
|
-
// fall through
|
|
257
|
-
case 'unaryFunc':
|
|
258
|
-
case 'ordgroup':
|
|
259
|
-
return this.args!.some((n) => n.isOverHigh());
|
|
260
|
-
case 'supsub': {
|
|
261
|
-
return (this.data as TexSupsubData).base.isOverHigh();
|
|
262
|
-
}
|
|
263
|
-
case 'beginend':
|
|
264
|
-
return true;
|
|
265
|
-
default:
|
|
266
|
-
return false;
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
233
|
}
|
|
270
234
|
|
|
271
235
|
export enum TypstTokenType {
|
|
@@ -348,6 +312,10 @@ export interface TypstSupsubData {
|
|
|
348
312
|
}
|
|
349
313
|
|
|
350
314
|
export type TypstArrayData = TypstNode[][];
|
|
315
|
+
export interface TypstLrData {
|
|
316
|
+
leftDelim: string | null;
|
|
317
|
+
rightDelim: string | null;
|
|
318
|
+
}
|
|
351
319
|
|
|
352
320
|
type TypstNodeType = 'atom' | 'symbol' | 'text' | 'control' | 'comment' | 'whitespace'
|
|
353
321
|
| 'empty' | 'group' | 'supsub' | 'funcCall' | 'fraction' | 'align' | 'matrix' | 'cases' | 'unknown';
|
|
@@ -364,12 +332,12 @@ export class TypstNode {
|
|
|
364
332
|
type: TypstNodeType;
|
|
365
333
|
content: string;
|
|
366
334
|
args?: TypstNode[];
|
|
367
|
-
data?: TypstSupsubData | TypstArrayData;
|
|
335
|
+
data?: TypstSupsubData | TypstArrayData | TypstLrData;
|
|
368
336
|
// Some Typst functions accept additional options. e.g. mat() has option "delim", op() has option "limits"
|
|
369
337
|
options?: TypstNamedParams;
|
|
370
338
|
|
|
371
339
|
constructor(type: TypstNodeType, content: string, args?: TypstNode[],
|
|
372
|
-
data?: TypstSupsubData | TypstArrayData) {
|
|
340
|
+
data?: TypstSupsubData | TypstArrayData| TypstLrData) {
|
|
373
341
|
this.type = type;
|
|
374
342
|
this.content = content;
|
|
375
343
|
this.args = args;
|
|
@@ -384,6 +352,31 @@ export class TypstNode {
|
|
|
384
352
|
public eq(other: TypstNode): boolean {
|
|
385
353
|
return this.type === other.type && this.content === other.content;
|
|
386
354
|
}
|
|
355
|
+
|
|
356
|
+
// whether the node is over high so that if it's wrapped in braces, \left and \right should be used in its TeX form
|
|
357
|
+
// e.g. 1/2 is over high, "2" is not.
|
|
358
|
+
public isOverHigh(): boolean {
|
|
359
|
+
switch (this.type) {
|
|
360
|
+
case 'fraction':
|
|
361
|
+
return true;
|
|
362
|
+
case 'funcCall': {
|
|
363
|
+
if (this.content === 'frac') {
|
|
364
|
+
return true;
|
|
365
|
+
}
|
|
366
|
+
return this.args!.some((n) => n.isOverHigh());
|
|
367
|
+
}
|
|
368
|
+
case 'group':
|
|
369
|
+
return this.args!.some((n) => n.isOverHigh());
|
|
370
|
+
case 'supsub':
|
|
371
|
+
return (this.data as TypstSupsubData).base.isOverHigh();
|
|
372
|
+
case 'align':
|
|
373
|
+
case 'cases':
|
|
374
|
+
case 'matrix':
|
|
375
|
+
return true;
|
|
376
|
+
default:
|
|
377
|
+
return false;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
387
380
|
}
|
|
388
381
|
|
|
389
382
|
export interface Tex2TypstOptions {
|
package/src/typst-parser.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
import { array_find } from "./generic";
|
|
3
|
-
import { TYPST_NONE, TypstNamedParams, TypstNode, TypstSupsubData, TypstToken, TypstTokenType } from "./types";
|
|
3
|
+
import { TYPST_NONE, TypstLrData, TypstNamedParams, TypstNode, TypstSupsubData, TypstToken, TypstTokenType } from "./types";
|
|
4
4
|
import { assert, isalpha } from "./util";
|
|
5
5
|
import { reverseShorthandMap } from "./typst-shorthands";
|
|
6
6
|
import { JSLex, Scanner } from "./jslex";
|
|
@@ -91,8 +91,9 @@ export function tokenize_typst(input: string): TypstToken[] {
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
|
|
94
|
-
function
|
|
95
|
-
|
|
94
|
+
function _find_closing_match(tokens: TypstToken[], start: number,
|
|
95
|
+
leftBrackets: TypstToken[], rightBrackets: TypstToken[]): number {
|
|
96
|
+
assert(tokens[start].isOneOf(leftBrackets));
|
|
96
97
|
let count = 1;
|
|
97
98
|
let pos = start + 1;
|
|
98
99
|
|
|
@@ -100,10 +101,10 @@ function find_closing_match(tokens: TypstToken[], start: number): number {
|
|
|
100
101
|
if (pos >= tokens.length) {
|
|
101
102
|
throw new Error('Unmatched brackets');
|
|
102
103
|
}
|
|
103
|
-
if (tokens[pos].isOneOf(
|
|
104
|
-
count += 1;
|
|
105
|
-
} else if (tokens[pos].isOneOf([RIGHT_PARENTHESES, RIGHT_BRACKET, RIGHT_CURLY_BRACKET])) {
|
|
104
|
+
if (tokens[pos].isOneOf(rightBrackets)) {
|
|
106
105
|
count -= 1;
|
|
106
|
+
}else if (tokens[pos].isOneOf(leftBrackets)) {
|
|
107
|
+
count += 1;
|
|
107
108
|
}
|
|
108
109
|
pos += 1;
|
|
109
110
|
}
|
|
@@ -111,6 +112,25 @@ function find_closing_match(tokens: TypstToken[], start: number): number {
|
|
|
111
112
|
return pos - 1;
|
|
112
113
|
}
|
|
113
114
|
|
|
115
|
+
function find_closing_match(tokens: TypstToken[], start: number): number {
|
|
116
|
+
return _find_closing_match(
|
|
117
|
+
tokens,
|
|
118
|
+
start,
|
|
119
|
+
[LEFT_PARENTHESES, LEFT_BRACKET, LEFT_CURLY_BRACKET],
|
|
120
|
+
[RIGHT_PARENTHESES, RIGHT_BRACKET, RIGHT_CURLY_BRACKET]
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function find_closing_delim(tokens: TypstToken[], start: number): number {
|
|
125
|
+
return _find_closing_match(
|
|
126
|
+
tokens,
|
|
127
|
+
start,
|
|
128
|
+
[LEFT_PARENTHESES, LEFT_BRACKET, LEFT_CURLY_BRACKET, VERTICAL_BAR],
|
|
129
|
+
[RIGHT_PARENTHESES, RIGHT_BRACKET, RIGHT_CURLY_BRACKET, VERTICAL_BAR]
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
|
|
114
134
|
|
|
115
135
|
function find_closing_parenthesis(nodes: TypstNode[], start: number): number {
|
|
116
136
|
const left_parenthesis = new TypstNode('atom', '(');
|
|
@@ -261,6 +281,7 @@ const LEFT_BRACKET: TypstToken = new TypstToken(TypstTokenType.ELEMENT, '[');
|
|
|
261
281
|
const RIGHT_BRACKET: TypstToken = new TypstToken(TypstTokenType.ELEMENT, ']');
|
|
262
282
|
const LEFT_CURLY_BRACKET: TypstToken = new TypstToken(TypstTokenType.ELEMENT, '{');
|
|
263
283
|
const RIGHT_CURLY_BRACKET: TypstToken = new TypstToken(TypstTokenType.ELEMENT, '}');
|
|
284
|
+
const VERTICAL_BAR = new TypstToken(TypstTokenType.ELEMENT, '|');
|
|
264
285
|
const COMMA = new TypstToken(TypstTokenType.ELEMENT, ',');
|
|
265
286
|
const SEMICOLON = new TypstToken(TypstTokenType.ELEMENT, ';');
|
|
266
287
|
const SINGLE_SPACE = new TypstToken(TypstTokenType.SPACE, ' ');
|
|
@@ -389,9 +410,13 @@ export class TypstParser {
|
|
|
389
410
|
casesNode.setOptions(named_params);
|
|
390
411
|
return [casesNode, newPos];
|
|
391
412
|
}
|
|
413
|
+
if (firstToken.value === 'lr') {
|
|
414
|
+
const [args, newPos, lrData] = this.parseLrArguments(tokens, start + 1);
|
|
415
|
+
const func_call = new TypstNode('funcCall', firstToken.value, args, lrData);
|
|
416
|
+
return [func_call, newPos];
|
|
417
|
+
}
|
|
392
418
|
const [args, newPos] = this.parseArguments(tokens, start + 1);
|
|
393
|
-
const func_call = new TypstNode('funcCall', firstToken.value);
|
|
394
|
-
func_call.args = args;
|
|
419
|
+
const func_call = new TypstNode('funcCall', firstToken.value, args);
|
|
395
420
|
return [func_call, newPos];
|
|
396
421
|
}
|
|
397
422
|
}
|
|
@@ -405,6 +430,28 @@ export class TypstParser {
|
|
|
405
430
|
return [this.parseCommaSeparatedArguments(tokens, start + 1, end), end + 1];
|
|
406
431
|
}
|
|
407
432
|
|
|
433
|
+
// start: the position of the left parentheses
|
|
434
|
+
parseLrArguments(tokens: TypstToken[], start: number): [TypstNode[], number, TypstLrData] {
|
|
435
|
+
if (tokens[start + 1].isOneOf([LEFT_PARENTHESES, LEFT_BRACKET, LEFT_CURLY_BRACKET, VERTICAL_BAR])) {
|
|
436
|
+
const end = find_closing_match(tokens, start);
|
|
437
|
+
const inner_start = start + 1;
|
|
438
|
+
const inner_end = find_closing_delim(tokens, inner_start);
|
|
439
|
+
const inner_args= this.parseCommaSeparatedArguments(tokens, inner_start + 1, inner_end);
|
|
440
|
+
return [
|
|
441
|
+
inner_args,
|
|
442
|
+
end + 1,
|
|
443
|
+
{leftDelim: tokens[inner_start].value, rightDelim: tokens[inner_end].value} as TypstLrData
|
|
444
|
+
];
|
|
445
|
+
} else {
|
|
446
|
+
const [args, end] = this.parseArguments(tokens, start);
|
|
447
|
+
return [
|
|
448
|
+
args,
|
|
449
|
+
end,
|
|
450
|
+
{leftDelim: null, rightDelim: null} as TypstLrData,
|
|
451
|
+
];
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
408
455
|
// start: the position of the left parentheses
|
|
409
456
|
parseGroupsOfArguments(tokens: TypstToken[], start: number, newline_token = SEMICOLON): [TypstNode[][], TypstNamedParams, number] {
|
|
410
457
|
const end = find_closing_match(tokens, start);
|
|
@@ -472,7 +519,7 @@ export class TypstParser {
|
|
|
472
519
|
pos = next_stop + 1;
|
|
473
520
|
}
|
|
474
521
|
}
|
|
475
|
-
|
|
522
|
+
|
|
476
523
|
return [matrix, named_params, end + 1];
|
|
477
524
|
}
|
|
478
525
|
|
|
@@ -481,8 +528,7 @@ export class TypstParser {
|
|
|
481
528
|
const args: TypstNode[] = [];
|
|
482
529
|
let pos = start;
|
|
483
530
|
while (pos < end) {
|
|
484
|
-
let
|
|
485
|
-
|
|
531
|
+
let nodes: TypstNode[] = [];
|
|
486
532
|
while(pos < end) {
|
|
487
533
|
if(tokens[pos].eq(COMMA)) {
|
|
488
534
|
pos += 1;
|
|
@@ -493,14 +539,18 @@ export class TypstParser {
|
|
|
493
539
|
}
|
|
494
540
|
const [argItem, newPos] = this.parseNextExpr(tokens, pos);
|
|
495
541
|
pos = newPos;
|
|
496
|
-
|
|
542
|
+
nodes.push(argItem);
|
|
497
543
|
}
|
|
498
544
|
|
|
499
|
-
|
|
545
|
+
let arg: TypstNode;
|
|
546
|
+
if (nodes.length === 0) {
|
|
500
547
|
arg = TYPST_EMPTY_NODE;
|
|
501
|
-
} else if (
|
|
502
|
-
arg =
|
|
548
|
+
} else if (nodes.length === 1) {
|
|
549
|
+
arg = nodes[0];
|
|
550
|
+
} else {
|
|
551
|
+
arg = process_operators(nodes);
|
|
503
552
|
}
|
|
553
|
+
|
|
504
554
|
args.push(arg);
|
|
505
555
|
}
|
|
506
556
|
return args;
|