1 //
2 // Copyright (c) 2006, Brian Frank and Andy Frank
3 // Licensed under the Academic Free License version 3.0
4 //
5 // History:
6 // 26 Jul 06 Brian Frank Creation
7 //
8
9 **
10 ** GenericType models a parameterized generic type: List, Map, or Func
11 **
12 abstract class GenericType : CType
13 {
14
15 //////////////////////////////////////////////////////////////////////////
16 // Construction
17 //////////////////////////////////////////////////////////////////////////
18
19 new make(CType base)
20 {
21 this.base = base
22 }
23
24 //////////////////////////////////////////////////////////////////////////
25 // CType
26 //////////////////////////////////////////////////////////////////////////
27
28 override Namespace ns() { return base.ns }
29 override CPod pod() { return ns.sysPod }
30 override Str name() { return base.name }
31 override Str qname() { return base.qname }
32 override Int flags() { return 0 }
33
34 override Bool isGeneric() { return false }
35 override Bool isParameterized() { return true }
36
37 override ListType toListOf()
38 {
39 if (listOf == null) listOf = ListType.make(this)
40 return listOf
41 }
42
43 override CType[] mixins() { return CType[,] }
44
45 override Str:CSlot slots
46 {
47 get
48 {
49 if (@slots == null) @slots = parameterizeSlots()
50 return @slots
51 }
52 }
53
54 override Str toStr() { return signature() }
55
56 //////////////////////////////////////////////////////////////////////////
57 // Parameterize
58 //////////////////////////////////////////////////////////////////////////
59
60 private Str:CSlot parameterizeSlots()
61 {
62 s := Str:CSlot[:]
63 base.slots.map(s) |CSlot slot->Obj| { return parameterizeSlot(slot) }
64 return s
65 }
66
67 private CSlot parameterizeSlot(CSlot slot)
68 {
69 m := slot as CMethod
70 if (m == null) return slot
71 if (!m.isGeneric) return slot
72 return ParameterizedMethod.make(this, m)
73 }
74
75 internal CType parameterize(CType t)
76 {
77 if (!t.isGenericParameter) return t
78 if (t is ListType) return parameterizeListType((ListType)t)
79 if (t is FuncType) return parameterizeFuncType((FuncType)t)
80 if (t.name.size != 1) throw CompilerErr.make("Cannot parameterize $t.qname", null)
81 return doParameterize(t.name[0])
82 }
83
84 private CType parameterizeListType(ListType t)
85 {
86 return parameterize(t.v).toListOf
87 }
88
89 private CType parameterizeFuncType(FuncType t)
90 {
91 params := (CType[])t.params.map(CType[,]) |CType p->CType| { return parameterize(p) }
92 ret := parameterize(t.ret)
93 return FuncType.make(params, t.names, ret)
94 }
95
96 abstract CType doParameterize(Int ch)
97
98 //////////////////////////////////////////////////////////////////////////
99 // Fields
100 //////////////////////////////////////////////////////////////////////////
101
102 override readonly CType base
103 private ListType listOf
104 }
105
106 **************************************************************************
107 ** ListType
108 **************************************************************************
109
110 **
111 ** ListType models a parameterized List type.
112 **
113 class ListType : GenericType
114 {
115 new make(CType v)
116 : super(v.ns.listType)
117 {
118 this.v = v
119 this.signature = "${v.signature}[]"
120 }
121
122 override Bool isGenericParameter()
123 {
124 return v.isGenericParameter
125 }
126
127 override Bool fits(CType t)
128 {
129 if (this == t) return true
130 if (t.signature == "sys::List") return true
131 if (t.isObj) return true
132 if (t.name.size == 1 && t.pod.name == "sys") return true
133
134 that := t.deref as ListType
135 if (that == null) return false
136
137 return v.fits(that.v)
138 }
139
140 override CType doParameterize(Int ch)
141 {
142 switch (ch)
143 {
144 case 'V': return v
145 case 'L': return this
146 default: throw Err.make(ch.toChar)
147 }
148 }
149
150 readonly CType v // value type
151 override readonly Str signature // v[]
152
153 }
154
155 **************************************************************************
156 ** MapType
157 **************************************************************************
158
159 **
160 ** MapType models a parameterized Map type.
161 **
162 class MapType : GenericType
163 {
164 new make(CType k, CType v)
165 : super(k.ns.mapType)
166 {
167 this.k = k
168 this.v = v
169 this.signature = "[${k.signature}:${v.signature}]"
170 }
171
172 override Bool isGenericParameter()
173 {
174 return k.isGenericParameter || v.isGenericParameter
175 }
176
177 override Bool fits(CType t)
178 {
179 if (this == t) return true
180 if (t.signature == "sys::Map") return true
181 if (t.isObj) return true
182 if (t.name.size == 1 && t.pod.name == "sys") return true
183
184 that := t.deref as MapType
185 if (that == null) return false
186
187 return k.fits(that.k) && v.fits(that.v)
188 }
189
190 override CType doParameterize(Int ch)
191 {
192 switch (ch)
193 {
194 case 'K': return k
195 case 'V': return v
196 case 'M': return this
197 default: throw Err.make(ch.toChar)
198 }
199 }
200
201 readonly CType k // keytype
202 readonly CType v // value type
203 override readonly Str signature // [k:v]
204
205 }
206
207 **************************************************************************
208 ** FuncType
209 **************************************************************************
210
211 **
212 ** FuncType models a parameterized Func type.
213 **
214 class FuncType : GenericType
215 {
216 new make(CType[] params, Str[] names, CType ret)
217 : super(ret.ns.funcType)
218 {
219 this.params = params
220 this.names = names
221 this.ret = ret
222 this.isGenericParameter = ret.isGenericParameter
223
224 s := StrBuf.make.add("|")
225 params.each |CType p, Int i|
226 {
227 isGenericParameter |= p.isGenericParameter
228 if (i > 0) s.add(","); s.add(p.signature)
229 }
230 s.add("->").add(ret.signature).add("|")
231 this.signature = s.toStr
232 }
233
234 override Bool fits(CType t)
235 {
236 if (this == t) return true
237 if (t.signature == "sys::Func") return true
238 if (t.isObj) return true
239 if (t.name.size == 1 && t.pod.name == "sys") return true
240
241 that := t.deref as FuncType
242 if (that == null) return false
243
244 // match return type (if void is needed, anything matches)
245 if (!that.ret.isVoid && !ret.fits(that.ret)) return false
246
247 // match params - it is ok for me to have less than
248 // the type params (if I want to ignore them), but I
249 // must have no more
250 if (params.size > that.params.size) return false
251 for (i:=0; i<params.size; ++i)
252 if (!that.params[i].fits(params[i])) return false
253
254 // this method works for the specified method type
255 return true;
256 }
257
258 ParamDef[] toParamDefs(Location loc)
259 {
260 p := ParamDef[,]
261 p.size = params.size
262 for (i:=0; i<params.size; ++i)
263 {
264 p[i] = ParamDef.make(loc, params[i], names[i])
265 }
266 return p
267 }
268
269 override CType doParameterize(Int ch)
270 {
271 if ('A' <= ch && ch <= 'H')
272 {
273 index := ch - 'A'
274 if (index < params.size) return params[index]
275 return ns.objType
276 }
277
278 switch (ch)
279 {
280 case 'R': return ret
281 default: throw Err.make(ch.toChar)
282 }
283 }
284
285 readonly CType[] params // a, b, c ...
286 readonly Str[] names // parameter names
287 readonly CType ret // return type
288 override readonly Str signature // |a,b..n->r|
289 override readonly Bool isGenericParameter
290 }
291
292 **************************************************************************
293 ** GenericParameterType
294 **************************************************************************
295
296 **
297 ** GenericParameterType models the generic parameter types
298 ** sys::V, sys::K, etc.
299 **
300 class GenericParameterType : CType
301 {
302 new make(Namespace ns, Str name)
303 {
304 this.ns = ns
305 this.name = name
306 this.qname = "sys::$name"
307 }
308
309 override Namespace ns
310 override CPod pod() { return ns.sysPod }
311 override Str name
312 override Str qname
313 override Str signature() { return qname }
314 override Int flags() { return 0 }
315 override Bool isGeneric() { return false }
316 override Bool isParameterized() { return false }
317 override Bool isGenericParameter() { return true }
318 override ListType toListOf() { if (listOf == null) listOf = ListType.make(this); return listOf }
319 override CType base() { return ns.objType }
320 override CType[] mixins() { return CType[,] }
321 override Str:CSlot slots() { throw UnsupportedErr.make }
322 override Str toStr() { return qname }
323 private ListType listOf
324 }
325
326 **************************************************************************
327 ** ParameterizedMethod
328 **************************************************************************
329
330 **
331 ** ParameterizedMethod models a parameterized CMethod
332 **
333 class ParameterizedMethod : CMethod
334 {
335 new make(GenericType parent, CMethod generic)
336 {
337 this.parent = parent
338 this.generic = generic
339
340 this.returnType = parent.parameterize(generic.returnType)
341 generic.params.map(this.params = CParam[,]) |CParam p->Obj|
342 {
343 return ParameterizedMethodParam.make(parent, p)
344 }
345
346 signature = "$returnType $name(" + params.join(", ") + ")"
347 }
348
349 override Str name() { return generic.name }
350 override Str qname() { return generic.qname }
351 override Int flags() { return generic.flags }
352 override Str toStr() { return signature }
353
354 override Bool isParameterized() { return true }
355
356 override CType inheritedReturnType() { return generic.inheritedReturnType }
357
358 override readonly CType parent
359 override readonly Str signature
360 override readonly CMethod generic
361 override readonly CType returnType
362 override readonly CParam[] params
363 }
364
365 **************************************************************************
366 ** ParameterizedMethodParam
367 **************************************************************************
368
369 class ParameterizedMethodParam : CParam
370 {
371 new make(GenericType parent, CParam generic)
372 {
373 this.generic = generic
374 this.paramType = parent.parameterize(generic.paramType)
375 }
376
377 override Str name() { return generic.name }
378 override Bool hasDefault() { return generic.hasDefault }
379 override Str toStr() { return "$paramType $name" }
380
381 override readonly CType paramType
382 readonly CParam generic
383 }