-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathanalysis.go
More file actions
148 lines (130 loc) · 4.38 KB
/
Copy pathanalysis.go
File metadata and controls
148 lines (130 loc) · 4.38 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
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
142
143
144
145
146
147
148
package main
import (
"errors"
"fmt"
)
// Rules:
// [ ] 1. Inside of functions, symbols need to be defined either before its declaration or in global scope
// [ ] 2. The types of parameters and variables must be the same as the type of the assigned expression
// [ ] 3. Calling a global function (not a fun variable) must respect arg count and arg types
// [ ] 4. Only variables of type obj can have fields accessed
// [ ] 5. break is only used in while loops
// [ ] 6. return must return an expression of the same type as the current function, and must return nothing if the function returns nothing
// [ ] 7. No local variable can share a name with an earlier variable, a parameter, a function, or a global variable
// [x] 8. No parameter can share a name with an earlier parameter, a function, or global variable
// [x] 9. No global variable can share a name with an earlier function or global variable
// [x] 10. No function can share a name with an earlier function or global variable
// [ ] 11. Global variables cannot be initialized with global variables declared later
// [ ] 12. A function with a non-void return type must return a value on all paths
// [ ] 13. All binary operators can only be done with members of the same type, but and and or do not have this restriction, and != and == work with fun/nil and obj/nil
// [ ] 14. Binary + is only allowed with strings and integers and symbols resolving to integers
// [ ] 15. Binary - * / % <= >= < > are only allowed with integers and symbols resolving to integers
// [ ] 16. Unary + and - are only allowed with integers and symbols resolving to integers
// [ ] 17. for =, on lvalues can only be field access or symbols
// [ ] 18. for =, if the lvalue is a symbol, the type of the rvalue must be the same as the variable of the lvalue
// [ ] 19. for =, the lvalue cannot be the symbol of a function
// [ ] 20. Initial field accesses can only be on object type variables
// [ ] 21. Two fields on the same scope in an object cannot have the same name
// [ ] 22. When an lvalue is called and it is not a field access, it must be a symbol resolving to a function
// [ ] 23. There must be one main function with no argument and no return type
type varTable []map[string]Type
type funcSig struct {
params []Type
ret Type
variadic bool
}
type funcTable map[string]funcSig
type symbolTable struct {
vars varTable
funcs funcTable
}
func analyze(ast Ast) {
var t symbolTable
var errs []error
errs = append(errs, registerGlobalScope(ast, &t)...)
errs = append(errs, analyzeGlobalVars(ast)...)
}
func registerGlobalScope(ast Ast, t *symbolTable) (errs []error) {
var vars = make(map[string]Type, len(ast.vars))
for _, v := range ast.vars {
if _, exists := vars[v.name]; exists {
errs = append(errs, fmt.Errorf(
"Variable %s is already defined",
v.name,
))
continue
}
vars[v.name] = v.kind
}
t.vars = append(t.vars, vars)
var funcs = make(funcTable, len(ast.funcs))
for _, f := range ast.funcs {
if _, exists := vars[f.name]; exists {
errs = append(errs, fmt.Errorf(
"Function %s is already defined",
f.name,
))
continue
}
if _, exists := funcs[f.name]; exists {
errs = append(errs, fmt.Errorf(
"Function %s is already defined",
f.name,
))
continue
}
var signature = funcSig{}
signature.variadic = f.params.variadic
signature.ret = f.ret
for _, v := range f.params.vars {
if _, exists := t.vars[0][v.name]; exists {
errs = append(errs, fmt.Errorf(
"Parameter %s is already defined",
v.name,
))
continue
}
if _, exists := funcs[v.name]; exists {
errs = append(errs, fmt.Errorf(
"Parameter %s is already defined",
v.name,
))
continue
}
if f.name == v.name {
errs = append(errs, fmt.Errorf(
"Parameter %s is already defined",
v.name,
))
continue
}
signature.params = append(signature.params, v.kind)
}
funcs[f.name] = signature
}
t.funcs = funcs
return errs
}
func analyzeGlobalVars(ast Ast) error {
var scope = make(map[string]Type, len(vars))
for _, v := range vars {
var exprType, err = getExprType(&v.assigned, *t)
if err != nil {
return err
}
if exprType != v.kind {
return fmt.Errorf(
"Variable %s is type %s but was assigned %s",
v.name,
v.kind,
exprType,
)
}
}
*t = append(*t, scope)
return nil
}
// TODO
func getExprType(expr *Expr, t symbolTable) (Type, error) {
return TYPE_VOID, nil
}