/
header.ts
103 lines (81 loc) · 2.03 KB
/
header.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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
export interface Context {
// write string to stdout, no newline
write: (s: string) => void;
// like console.log();
log: (s: any) => void;
}
// Most stages can have errors
// Errors can be thrown (not checked by TypeScript), or put in an array
export interface Error {
tag: 'Error';
message: string;
loc: number;
}
export const ShouldNotGetHere = { tag: 'Assert' };
// [String] -> Lexer -> [Token]
export type Id =
| 'BAD'
| 'lparen'
| 'rparen'
| 'lbrack'
| 'rbrack'
| 'bool'
| 'int'
| 'name'
| 'eof';
export interface Token {
id: Id;
start: number; // 3
len: number; // 1
source: string; // Use the whole program for now
// Avoid string allocations unless we need them
}
// [Token] -> Parser -> [Node]
export interface Bool {
tag: 'Bool';
value: boolean;
loc: number;
}
export interface Num {
tag: 'Num';
value: number;
loc: number;
}
// TODO: Name -> Symbol
export interface Name {
tag: 'Name';
value: string;
loc: number;
}
// (== 5 (+ 2 3))
export interface List {
tag: 'List';
name: string; // TODO: should be Node, which can be Name with its own loc
// ((fn [x] (+ x 1)) 42) => 43
loc: number; // TODO: should be location of (
args: Node[];
}
export type Node = Bool | Num | Name | List;
// [Node] -> Transformer -> [Expr]
export interface If {
tag: 'If';
loc: number; // index of Token for if
cond: Expr;
then: Expr;
else: Expr;
}
export interface Binary {
tag: 'Binary';
op: '+' | '-' | '/' | '*' | '==' | '!=' | '<' | '>' | 'and' | 'or';
loc: number; // index of Token for op
left: Expr;
right: Expr;
}
// It would be nice if Error wasn't a valid Expr, but transform() can report
// multiple errors, and having the first one as the return value simplifies the
// code. The main run() function should not type check or eval with errors.
export type Expr = Bool | Num | Name | If | Binary | Error;
// [Expr] -> Type Checker -> Map<Expr, Type>
export type Type = 'Bool' | 'Num';
// [Expr] -> Evaluator -> [Value]
export type Value = Bool | Num;