1 //
2 // Copyright (c) 2006, Brian Frank and Andy Frank
3 // Licensed under the Academic Free License version 3.0
4 //
5 // History:
6 // 15 Sep 05 Brian Frank Creation
7 // 3 Jun 06 Brian Frank Ported from Java to Fan - Megan's b-day!
8 //
9
10 **
11 ** TypeDef models a type definition for a class, mixin or enum
12 **
13 class TypeDef : DefNode, CType
14 {
15
16 //////////////////////////////////////////////////////////////////////////
17 // Construction
18 //////////////////////////////////////////////////////////////////////////
19
20 new make(Namespace ns, Location location, CompilationUnit unit, Str name)
21 : super(location)
22 {
23 this.ns = ns
24 this.pod = unit.pod
25 this.unit = unit
26 this.name = name
27 this.qname = pod.name + "::" + name
28 this.mixins = CType[,]
29 this.enumDefs = EnumDef[,]
30 this.slotMap = Str:CSlot[:]
31 this.slotDefMap = Str:SlotDef[:]
32 this.slotDefList = SlotDef[,]
33 this.closures = ClosureExpr[,]
34 }
35
36 //////////////////////////////////////////////////////////////////////////
37 // CType
38 //////////////////////////////////////////////////////////////////////////
39
40 override Str signature() { return qname }
41
42 override Bool isGeneric() { return false }
43 override Bool isParameterized() { return false }
44 override Bool isGenericParameter() { return false }
45
46 override ListType toListOf()
47 {
48 if (listOf == null) listOf = ListType.make(this)
49 return listOf
50 }
51
52 //////////////////////////////////////////////////////////////////////////
53 // Access
54 //////////////////////////////////////////////////////////////////////////
55
56 **
57 ** Return if this type is the anonymous class of a closure
58 **
59 Bool isClosure()
60 {
61 return closure != null
62 }
63
64 //////////////////////////////////////////////////////////////////////////
65 // Slots
66 //////////////////////////////////////////////////////////////////////////
67
68 **
69 ** Return all the all slots (inherited and defined)
70 **
71 override Str:CSlot slots() { return slotMap }
72
73 **
74 ** Add a slot to the type definition. The method is used to add
75 ** SlotDefs declared by this type as well as slots inherited by
76 ** this type.
77 **
78 Void addSlot(CSlot s, Int slotDefIndex := null)
79 {
80 // if MethodDef
81 m := s as MethodDef
82 if (m != null)
83 {
84 // static initializes are just temporarily added to the
85 // slotDefList but never into the name map - we just need
86 // to keep them in declared order until they get collapsed
87 // and removed in the Normalize step
88 if (m.isStaticInit)
89 {
90 slotDefList.add(m)
91 return
92 }
93
94 // field accessors are added only to slotDefList,
95 // name lookup is always the field itself
96 if (m.isFieldAccessor)
97 {
98 slotDefList.add(m)
99 return
100 }
101 }
102
103 // sanity check
104 name := s.name
105 if (hasSlot(name))
106 throw CompilerErr.make("Internal error: duplicate slot $name", location)
107
108 // add to all slots table
109 slotMap[name] = s
110
111 // if my own SlotDef
112 def := s as SlotDef
113 if (def != null && def.parent === this)
114 {
115 // add to my slot definitions
116 slotDefMap[name] = def
117 if (slotDefIndex == null)
118 slotDefList.add(def)
119 else
120 slotDefList.insert(slotDefIndex, def)
121
122 // if non-const FieldDef, then add getter/setter methods
123 if (s is FieldDef)
124 {
125 f := (FieldDef)s
126 if (f.get != null) addSlot(f.get)
127 if (f.set != null) addSlot(f.set)
128 }
129 }
130 }
131
132 **
133 ** Replace oldSlot with newSlot in my slot tables.
134 **
135 Void replaceSlot(CSlot oldSlot, CSlot newSlot)
136 {
137 // sanity checks
138 if (oldSlot.name != newSlot.name)
139 throw CompilerErr.make("Not same names: $oldSlot != $newSlot", location)
140 if (slotMap[oldSlot.name] !== oldSlot)
141 throw CompilerErr.make("Old slot not mapped: $oldSlot", location)
142
143 // remap in slotMap table
144 slotMap[oldSlot.name] = newSlot
145
146 // if SlotDef
147 def := newSlot as SlotDef
148 if (def != null && def.parent === this)
149 {
150 slotDefMap[name] = def
151 slotDefList.add(def)
152 }
153 }
154
155 **
156 ** If during parse we added any static initializer methods,
157 ** now is the time to remove them all and replace them with a
158 ** single collapsed MethodDef (processed in Normalize step)
159 **
160 Void normalizeStaticInits(MethodDef m)
161 {
162 // remove any temps we had in slotDefList
163 slotDefList = slotDefList.exclude |SlotDef s->Bool|
164 {
165 return MethodDef.isNameStaticInit(s.name)
166 }
167
168 // fix enclosingMethod of closures used in those temp statics
169 closures.each |ClosureExpr c|
170 {
171 if (c.enclosingMethod.isStaticInit)
172 c.enclosingMethod = m
173 }
174
175 // now we add into all slot tables
176 slotMap[m.name] = m
177 slotDefMap[m.name] = m
178 slotDefList.add(m)
179 }
180
181 //////////////////////////////////////////////////////////////////////////
182 // SlotDefs
183 //////////////////////////////////////////////////////////////////////////
184
185 **
186 ** Return if this class has a slot definition for specified name.
187 **
188 Bool hasSlotDef(Str name)
189 {
190 return slotDefMap.containsKey(name)
191 }
192
193 **
194 ** Return SlotDef for specified name or null.
195 **
196 SlotDef slotDef(Str name)
197 {
198 return slotDefMap[name]
199 }
200
201 **
202 ** Return FieldDef for specified name or null.
203 **
204 FieldDef fieldDef (Str name)
205 {
206 return (FieldDef)slotDefMap[name]
207 }
208
209 **
210 ** Return MethodDef for specified name or null.
211 **
212 MethodDef methodDef(Str name)
213 {
214 return (MethodDef)slotDefMap[name]
215 }
216
217 **
218 ** Get the SlotDefs declared within this TypeDef.
219 **
220 SlotDef[] slotDefs()
221 {
222 return slotDefList
223 }
224
225 **
226 ** Get the FieldDefs declared within this TypeDef.
227 **
228 FieldDef[] fieldDefs()
229 {
230 return (FieldDef[])slotDefList.findType(FieldDef.type)
231 }
232
233 **
234 ** Get the static FieldDefs declared within this TypeDef.
235 **
236 FieldDef[] staticFieldDefs()
237 {
238 return fieldDefs.findAll |FieldDef f->Bool| { return f.isStatic }
239 }
240
241 **
242 ** Get the instance FieldDefs declared within this TypeDef.
243 **
244 FieldDef[] instanceFieldDefs()
245 {
246 return fieldDefs.findAll |FieldDef f->Bool| { return !f.isStatic }
247 }
248
249 **
250 ** Get the MethodDefs declared within this TypeDef.
251 **
252 MethodDef[] methodDefs()
253 {
254 return (MethodDef[])slotDefList.findType(MethodDef.type)
255 }
256
257 //////////////////////////////////////////////////////////////////////////
258 // Enum
259 //////////////////////////////////////////////////////////////////////////
260
261 **
262 ** Return EnumDef for specified name or null.
263 **
264 public EnumDef enumDef(Str name)
265 {
266 return enumDefs.find |EnumDef def->Bool| { return def.name == name }
267 }
268
269 //////////////////////////////////////////////////////////////////////////
270 // Tree
271 //////////////////////////////////////////////////////////////////////////
272
273 Void walk(Visitor v, VisitDepth depth)
274 {
275 v.enterTypeDef(this)
276 walkFacets(v, depth)
277 if (depth >= VisitDepth.slotDef)
278 {
279 slotDefs.each |SlotDef slot| { slot.walk(v, depth) }
280 }
281 v.visitTypeDef(this)
282 v.exitTypeDef(this)
283 }
284
285 //////////////////////////////////////////////////////////////////////////
286 // Debug
287 //////////////////////////////////////////////////////////////////////////
288
289 override Str toStr()
290 {
291 return signature()
292 }
293
294 override Void print(AstWriter out)
295 {
296 out.nl
297 printFacets(out)
298 if (isMixin)
299 out.w("mixin $qname").nl
300 else if (isEnum)
301 out.w("enum $qname").nl
302 else
303 out.w("class $qname").nl
304
305 if (base != null || !mixins.isEmpty)
306 {
307 out.w(" : ")
308 if (base != null) out.w(" $base")
309 if (!mixins.isEmpty) out.w(", ").w(mixins.join(", ")).nl
310 }
311
312 out.w("{").nl
313 out.indent
314 enumDefs.each |EnumDef e| { e.print(out) }
315 slotDefs.each |SlotDef s| { s.print(out) }
316 out.unindent
317 out.w("}").nl
318 }
319
320 //////////////////////////////////////////////////////////////////////////
321 // Fields
322 //////////////////////////////////////////////////////////////////////////
323
324 override readonly Namespace ns // compiler's namespace
325 readonly CompilationUnit unit // parent unit
326 override readonly CPod pod // parent pod
327 override readonly Str name // simple class name
328 override readonly Str qname // podName::name
329 Bool baseSpecified := true // was base assigned from source code
330 override CType base // extends class
331 override CType[] mixins // mixin types
332 EnumDef[] enumDefs // declared enumerated pairs (only if enum)
333 ClosureExpr[] closures // closures where I am enclosing type (Parse)
334 ClosureExpr closure // if I am a closure anonymous class
335 private Str:CSlot slotMap // all slots
336 private Str:SlotDef slotDefMap // declared slot definitions
337 private SlotDef[] slotDefList // declared slot definitions
338 private ListType listOf // lazily created list of
339 FacetDef[] indexedFacets // used by WritePod
340
341 }