-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathASTLet.java
More file actions
106 lines (92 loc) · 3.58 KB
/
Copy pathASTLet.java
File metadata and controls
106 lines (92 loc) · 3.58 KB
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
104
105
106
import java.util.List;
public class ASTLet implements ASTNode {
public List<Bind> decls;
public ASTNode body;
public static MemoryManager mem = new MemoryManager();
public ASTLet(List<Bind> decls, ASTNode body) throws InterpreterError {
// Safe recursion check
if (decls != null) {
for (Bind b : decls) {
if (b.getExp().isFreeOutsideLambda(b.getId())) {
throw new InterpreterError("recursion unsafe: '" + b.getId() + "' is directly accessible from itself");
}
}
}
this.decls = decls;
this.body = body;
}
@Override
public IValue eval(Environment<IValue> e) throws InterpreterError {
Environment<IValue> en = e.beginScope();
int mutCount = 0;
try {
for (Bind b : decls) {
IValue v = b.getExp().eval(en);
if (b.mut) {
MemoryManager.VAddress addr = mem.push(v);
en.assoc(b.getId(), new VMut(addr));
mutCount++;
} else {
en.assoc(b.getId(), v);
}
}
try {
return body.eval(en);
} finally {
for (int i = 0; i < mutCount; i++) {
mem.pop();
}
en.endScope();
}
} catch (MemoryPanicError ex) {
throw new InterpreterError("mut: memory panic: " + ex.getMessage());
}
}
@Override
public ASTType typecheck(Environment<ASTType> e) throws TypeCheckError, InterpreterError {
Environment<ASTType> en = e.beginScope();
for (Bind b : decls) {
ASTType annotated = b.getType();
if (annotated != null) {
if (b.mut) {
en.assoc(b.getId(), new ASTTMut(annotated));
} else {
en.assoc(b.getId(), annotated);
}
}
ASTType inferred = b.getExp().typecheck(en);
ASTType typeToAssociate = inferred;
if (annotated != null) {
if (inferred instanceof ASTTRef exprCell && annotated instanceof ASTTRef declCell) {
if (!exprCell.getType().subtypeOf(declCell.getType(), en)) {
throw new TypeCheckError("let: cell content mismatch for '" + b.getId() + "': expected " + annotated.toStr() + " but got " + inferred.toStr());
}
} else if (!inferred.subtypeOf(annotated, en)) {
throw new TypeCheckError("let: type mismatch for '" + b.getId() + "': expected " + annotated.toStr() + " but got " + inferred.toStr());
}
typeToAssociate = annotated;
}
if (annotated == null) {
if (b.mut) {
en.assoc(b.getId(), new ASTTMut(typeToAssociate));
} else {
en.assoc(b.getId(), typeToAssociate);
}
}
}
ASTType result = body.typecheck(en);
en.endScope();
if (result instanceof ASTTMut) {
throw new TypeCheckError("mut: mut variable cannot escape its scope");
}
return result;
}
@Override
public boolean isFreeOutsideLambda(String id) {
for (Bind b : decls) {
if (b.getExp().isFreeOutsideLambda(id)) return true;
if (b.getId().equals(id)) return false;
}
return body.isFreeOutsideLambda(id);
}
}