-
Notifications
You must be signed in to change notification settings - Fork 40
/
PropertyDecl.ooc
133 lines (121 loc) · 4.45 KB
/
PropertyDecl.ooc
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
import structs/[ArrayList]
import Type, Declaration, Expression, Visitor, TypeDecl, VariableAccess,
Node, ClassDecl, FunctionCall, Argument, BinaryOp, Cast, Module,
Block, Scope, FunctionDecl, Argument, VariableDecl
import tinker/[Response, Resolver, Trail]
import ../frontend/BuildParams
PropertyDecl: class extends VariableDecl {
getter: FunctionDecl = null
setter: FunctionDecl = null
cls: ClassDecl = null
resolved := false
virtual := true // see `VariableAccess resolve` and `BinaryOp resolve`
init: func ~pDecl (.type, .name, .token) {
init(type, name, null, token)
}
isVirtual: func -> Bool { virtual }
setVirtual: func (=virtual) {}
setSetter: func (=setter) {}
setGetter: func (=getter) {}
/** create default getter for me. */
setDefaultGetter: func {
// a default getter just returns the value.
decl := FunctionDecl new("__defaultGet__", token)
access := VariableAccess new(this name, token)
decl body add(access)
setGetter(decl)
}
/** create default setter for me. */
setDefaultSetter: func {
// a default setter just sets
decl := FunctionDecl new("__defaultSet__", token)
decl args add(AssArg new(this name, token))
setSetter(decl)
}
getSetterName: func -> String {
"__set%s__" format(name)
}
getGetterName: func -> String {
"__get%s__" format(name)
}
resolve: func (trail: Trail, res: Resolver) -> Response {
if(resolved) {
return Responses OK
}
// get and store the class.
node := trail peek()
if(!node instanceOf(ClassDecl)) {
token throwError("Expected ClassDecl, got %s" format(node toString()))
}
cls = node as ClassDecl
// setup getter
if(getter != null) {
// this is also done for extern getters.
getter setName(getGetterName()) .setReturnType(type)
cls addFunction(getter)
// resolve!
trail push(this)
getter resolve(trail, res)
trail pop(this)
}
// setup setter
if(setter != null) {
// set name, argument type ...
setter setName(getSetterName())
if(setter isExtern()) {
// add single arg
newArg := Argument new(this type, this name, token)
setter args add(newArg)
} else {
arg := setter args[0]
// replace `assign` with `conventional`.
if(arg instanceOf(AssArg)) {
// create AST nodes, add setter contents
this_ := VariableAccess new("this", token)
left := VariableAccess new(this_, this name, token)
right := VariableAccess new(this name, token)
assignment := BinaryOp new(left, right, OpTypes ass, token)
setter body add(assignment)
// replace argument
newArg := Argument new(this type, this name, token)
setter args[0] = newArg
} else {
arg setType(this type)
}
}
cls addFunction(setter)
trail push(this)
setter resolve(trail, res)
trail pop(this)
}
super(trail, res)
resolved = true
return Responses OK
}
/** resolve `set` and `get` functions to `getter` and `setter` */
resolveCall: func (call: FunctionCall, res: Resolver, trail: Trail) -> Int {
match (call name) {
case "get" => {
call setName(getGetterName())
cls resolveCall(call, res, trail)
}
case "set" => {
call setName(getSetterName())
cls resolveCall(call, res, trail)
}
}
0
}
/** here for the resolving phase in `init`. Not the nicest way, but works. */
resolveAccess: func (access: VariableAccess, res: Resolver, trail: Trail) {
if(access name == this name) {
cls resolveAccess(access, res, trail)
}
}
/** return true if getters and setters should be used in this context */
inOuterSpace: func (trail: Trail) -> Bool {
!(setter ? trail data contains(setter) : false) \
&& !(getter ? trail data contains(getter) : false) \
&& !trail data contains(this)
}
}