
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 }