forked from ucsd-cse231-s22/lecture3
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtc.ts
78 lines (70 loc) · 2.25 KB
/
tc.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
import { Expr, Stmt, Type } from "./ast";
type FunctionsEnv = Map<string, [Type[], Type]>;
type BodyEnv = Map<string, Type>;
export function tcExpr(e : Expr, functions : FunctionsEnv, variables : BodyEnv) : Type {
switch(e.tag) {
case "number": return "int";
case "id": return variables.get(e.name);
case "call":
if(!functions.has(e.name)) {
throw new Error(`function ${e.name} not found`);
}
const [args, ret] = functions.get(e.name);
if(args.length !== e.arguments.length) {
throw new Error(`Expected ${args.length} arguments but got ${e.arguments.length}`);
}
args.forEach((a, i) => {
const argtyp = tcExpr(e.arguments[i], functions, variables);
if(a !== argtyp) { throw new Error(`Got ${argtyp} as argument ${i + 1}, expected ${a}`); }
});
return ret;
}
}
export function tcStmt(s : Stmt, functions : FunctionsEnv, variables : BodyEnv, currentReturn : Type) {
switch(s.tag) {
case "assign": {
const rhs = tcExpr(s.value, functions, variables);
if(variables.has(s.name) && variables.get(s.name) !== rhs) {
throw new Error(`Cannot assign ${rhs} to ${variables.get(s.name)}`);
}
else {
variables.set(s.name, rhs);
}
return;
}
case "define": {
const bodyvars = new Map<string, Type>(variables.entries());
s.parameters.forEach(p => { bodyvars.set(p.name, p.typ)});
s.body.forEach(bs => tcStmt(bs, functions, bodyvars, s.ret));
return;
}
case "expr": {
tcExpr(s.expr, functions, variables);
return;
}
case "return": {
const valTyp = tcExpr(s.value, functions, variables);
if(valTyp !== currentReturn) {
throw new Error(`${valTyp} returned but ${currentReturn} expected.`);
}
return;
}
}
}
export function tcProgram(p : Stmt[]) {
const functions = new Map<string, [Type[], Type]>();
p.forEach(s => {
if(s.tag === "define") {
functions.set(s.name, [s.parameters.map(p => p.typ), s.ret]);
}
});
const globals = new Map<string, Type>();
p.forEach(s => {
if(s.tag === "assign") {
globals.set(s.name, tcExpr(s.value, functions, globals));
}
else {
tcStmt(s, functions, globals, "none");
}
});
}