-
Notifications
You must be signed in to change notification settings - Fork 0
/
typing.txt
144 lines (102 loc) · 4.98 KB
/
typing.txt
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
TYPING
func main() {
---
if (getBool()) { } // if depends on "getBool", condition is predicted to be Bool
---
b : Bool = ((getInt() + 1) - 2) == 0;
// getInt is unresolved, predicted to be AnyNumber (from the containing binop)
// binop1 depends on "getInt" and is predicted to be AnyNumber (because +)
// binop2 depends on the binop1 and is predicted to be AnyNumber (because +)
// binop3 depends on the binop2 and is predicted to be Bool (because ==)
// when getInt is resolved, binop1 that depends on it is resolved to Int
// when binop1 is resolved, binop2 is resolved to Int
// when binop2 is resolved, binop3 is resolved to Bool
---
@Note: is AnyNumber just Int Literal?
b : Bool = ((getFloat() + 1) - 2) == 0;
// getInt is unresolved, predicted to be AnyNumber (from the containing binop)
// binop1 depends on "getFloat" and is predicted(AnyNumber) (because +)
// binop2 depends on the binop1 and is predicted(AnyNumber) (because +)
// binop3 depends on the binop2 and is predicted(Bool) (because ==)
// when getFloat is resolved, binop1 that depends on it is resolved to Float
// second argument is IntLit, but it's not an error. it gets converted to FloatLit
// when binop1 is resolved, binop2 is resolved to Float
// second argument is IntLit, but it's not an error. it gets converted to FloatLit
// when binop2 is resolved, binop3 is resolved to Bool
algorithm
@Note: all these binops depend on their arguments, they don't depend on global
FIRST PASS
- call type is unresolved - added to unresolved[call.name]
- binop1 can't resolve first argument - adds itself as the argument's depentant
// but it's a '+' operation, so it's probably a number - sets the first argument and itself to be predicted(AnyNumber)
- binop2 can't resolve it's first argument - adds itself as the argument's dependant
// same here for '-' operation
- binop3 can't resolve it's first argument - adds itself as the argument's dependant
// same here, but it sets the first argument and itself to be predicted(Bool)
- getFloat is resolved
WHAT WE HAVE (brackets for dependencies)
// binop1: Predicted(AnyNumber) {arg1} = [Predicted(AnyNumber) {getFloat}] + [AnyNumber]
// binop1: Predicted(AnyNumber) {arg1} = [Predicted(AnyNumber)] + [AnyNumber]
// binop2: Predicted(Bool) {arg1} = [Predicted(AnyNumber)] + [AnyNumber]
SECOND PASS
---
b : Bool = ((getInt() + 1) - 2.0) == 0;
// getInt is unresolved, predicted to be AnyNumber (from the containing binop)
// binop1 depends on "getInt" and is predicted to be AnyNumber (because +)
// binop2 depends on the binop1 and is predicted to be Float (because +)
// back propagating to binop1, which is also now predicted to be Float (job of the binary expression's typer)
// binop3 depends on the binop2 and is predicted to be Bool (because ==)
// when getInt is resolved, binop1 that depends on it is resolved to Float, and we fail with error
---
d : Bool = getInt() - getFloat() == 0; // depends on both procedures, predicted to be AnyNumber
// when getInt is resolved, this will change predicted to Int
// when getFloat is resolved, we fail with error
}
func getInt() -> Int { return 1; }
func getFloat() -> Float { return 1; }
func getBool() -> Int { return true; }
///////
- if variable is unresolved, we only look for it in the global scope
- procedures only live in the global scope
depending_on_procedures = [string: [*Ast]]
depending_on_vars = [string: [*Ast]]
// we also have these for local scopes
declarations = [string: ProcDecl]
UNRESOLVED (procedure("proc_a"))
a := proc_a()
<< no way to know
~ declaration depends on resolving procedure proc_a
/// depending_on_procedures["proc_a"] += *a
PREDICTED (Bool, variable("b"))
if (b) { ... }
<< predicted as Bool
~ if statement depends on resolving variable a
+ after resolving a, we make sure it's a Bool
/// depending_on_vars["b"] += *if
c : Int = proc_c()
/// declare: func proc_b() -> Bool { ... }
/// resolved_procedures["proc_b"] = *proc_b
/// trying to resolve depending_on_procedures["proc_b"] - nothing found
RESOLVED
b := proc_b()
~ look [-> Bool]
<< resolved as Bool
/// resolved "b", trying to resolve depending_on_vars["b"]
/// found if, resolving if-cond to Bool, matching b to Bool, success, removing if from unresolved
/// declare: func proc_a() -> Int { ... }
/// resolved_procedures["proc_a"] = *proc_a
/// trying to resolve depending_on_procedures["proc_a"]
/// found var a, resolving a to Int, removing it from unresolved
-- in the end, check if all unresolved containers are empty
code snippet:
func main() -> Int32
a := proc_a();
if (b) { }
d : Int = proc_c();
return 0;
}
b := proc_a();
c := proc_b(proc_c());
func proc_c() -> Int { return 1; }
func proc_a() -> Float { return 1.0; }
func proc_b(val: Int) -> Bool { return true; }