-
Notifications
You must be signed in to change notification settings - Fork 0
/
seq.ts
74 lines (61 loc) 路 1.89 KB
/
seq.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import {Binding, Code, CodeBindings, Var} from 'codedegen';
import {createVar} from '../utils';
import {never} from './never';
import {none} from './none';
import {Reader, ReaderCodegen} from './reader-types';
import {createCodeBindings, createReaderCallCode} from './reader-utils';
/**
* Creates a reader that applies readers one after another.
*
* @param readers Readers that are called.
*
* @template Context The context passed by tokenizer.
*/
export function seq<Context = any>(...readers: Reader<Context>[]): Reader<Context> {
const children: Reader<Context>[] = [];
for (const reader of readers) {
if (reader instanceof SeqReader) {
children.push(...reader.readers);
continue;
}
if (reader !== none) {
children.push(reader);
}
}
if (children.includes(never)) {
return never;
}
if (children.length === 0) {
return none;
}
if (children.length === 1) {
return children[0];
}
return new SeqReader(children);
}
export class SeqReader<Context> implements ReaderCodegen {
constructor(public readers: Reader<Context>[]) {
}
factory(inputVar: Var, offsetVar: Var, contextVar: Var, resultVar: Var): CodeBindings {
const {readers} = this;
const indexVar = createVar();
const readerResultVar = createVar();
const readersLength = readers.length;
const bindings: Binding[] = [];
const code: Code[] = [
resultVar, '=-1;',
'var ',
indexVar, '=', offsetVar, ',',
readerResultVar, ';',
];
for (let i = 0; i < readersLength; ++i) {
code.push(
createReaderCallCode(readers[i], inputVar, indexVar, contextVar, readerResultVar, bindings),
'if(', readerResultVar, '>=', indexVar, '){',
i < readersLength - 1 ? indexVar : resultVar, '=', readerResultVar, ';',
);
}
code.push('}'.repeat(readersLength));
return createCodeBindings(code, bindings);
}
}