/
macro.ts
70 lines (58 loc) · 1.99 KB
/
macro.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
import { string, regexp, alt, seq, sepBy, seqMap, takeWhile, Parser } from 'parsimmon';
// First phase is a rapid scanner and macro substitution phase.
// Should take < 10 ms.
const optLineSpace = regexp(/[ \t]*/);
const lineSpace = regexp(/[ \t]+/);
const token = regexp(/[^ \t\n,;\[\]+*\/]+|\[|]|,|\+|\*|\//);
// const macro; // TODO
const eol = seq(
optLineSpace,
alt(
seq(string(';'), takeWhile(c => c !== '\n'), string('\n')),
string('\n')
)
);
type Macro = { kind: 'macro', name: string; body: string; };
const equ: Parser<Macro> = seqMap(
optLineSpace.then(token).skip(lineSpace), string('EQU').skip(lineSpace),
takeWhile(c => c !== ';' && c !== '\n'), eol,
(name, _, body, _2) => ({ kind: 'macro', name, body } as Macro)
);
const equs: Parser<Macro> = seqMap(
optLineSpace.then(token).skip(lineSpace), string('EQUS').skip(lineSpace),
string('"').then(takeWhile(c => c !== '"')).skip(string('"')), eol,
(name, _, body, _2) => ({ kind: 'macro', name, body } as Macro)
);
// This parser needs to be information-preserving.
type Statement = { kind: 'statement', tokens: string[] };
const statement: Parser<Statement> =
optLineSpace.then(
alt(token, lineSpace)
.many()
.map((tokens) => ({ kind: 'statement', tokens } as Statement))
).skip(eol);
const file: Parser<(Macro|Statement)[]> = alt(
equs,
equ,
statement,
eol.result(null)
).many().map(r => r.filter(x => x));
export function macroPass(s: string, macroTable: {[name: string]: string} = {}): string {
const lines = file.tryParse(s + '\n');
// Go through.
// Build macro table and simultaneously pull in to replace.
const newFile = [];
for (const line of lines) {
if (line.kind === 'macro') {
macroTable[line.name] = macroPass(line.body, macroTable);
} else if (line.kind === 'statement') {
newFile.push(line.tokens.map(s => {
if (s in macroTable) {
return macroTable[s];
}
return s;
}).join(''));
}
}
return newFile.join('\n');
}