| 1 | interface ITypeProxy |
|---|
| 2 | inherits INode |
|---|
| 3 | """ |
|---|
| 4 | An ITypeProxy is a node that represents/stands-in for a type. |
|---|
| 5 | Its .realType property returns that type, often by locating it among symbols. |
|---|
| 6 | Implemented by CobraType, AbstractTypeIdentifier, NilableTypeProxy and the backEnd TypeProxies. |
|---|
| 7 | """ |
|---|
| 8 | |
|---|
| 9 | # TODO: See above NOTE and consider adding name below. Also see _bindBase in Boxes.cobra which would benefit from .name |
|---|
| 10 | # get name as String |
|---|
| 11 | # """ |
|---|
| 12 | # Return the name of the type. |
|---|
| 13 | # """ |
|---|
| 14 | |
|---|
| 15 | get realType as IType |
|---|
| 16 | """ |
|---|
| 17 | Returns the type that this node represents or .throwError if the type cannot be located. |
|---|
| 18 | """ |
|---|
| 19 | |
|---|
| 20 | |
|---|
| 21 | class AbstractTypeProxy |
|---|
| 22 | is abstract |
|---|
| 23 | inherits Node |
|---|
| 24 | implements ITypeProxy |
|---|
| 25 | |
|---|
| 26 | get realType as IType is abstract |
|---|
| 27 | |
|---|
| 28 | |
|---|
| 29 | class TypeProxy |
|---|
| 30 | inherits AbstractTypeProxy |
|---|
| 31 | """ |
|---|
| 32 | Once in awhile you might need to pass or use an ITypeProxy even though you already know the type (probably because it is a builtin type such as `int` or `dynamic`. |
|---|
| 33 | In that case, you can use TypeProxy(someType) |
|---|
| 34 | """ |
|---|
| 35 | |
|---|
| 36 | var _type as IType |
|---|
| 37 | |
|---|
| 38 | cue init(type as IType) |
|---|
| 39 | base.init |
|---|
| 40 | _type = type |
|---|
| 41 | |
|---|
| 42 | get realType as IType is override |
|---|
| 43 | return _type |
|---|
| 44 | |
|---|
| 45 | |
|---|
| 46 | class LibraryTypeProxy |
|---|
| 47 | inherits AbstractTypeProxy |
|---|
| 48 | """ |
|---|
| 49 | Relies on .compiler.libraryType(qualifiedName) to locate the Cobra type. |
|---|
| 50 | Useful for the primitive types that need a reference to, for example, System.Char. |
|---|
| 51 | """ |
|---|
| 52 | |
|---|
| 53 | var _qualifiedName as String |
|---|
| 54 | |
|---|
| 55 | cue init(qualifiedName as String) |
|---|
| 56 | base.init |
|---|
| 57 | _qualifiedName = qualifiedName |
|---|
| 58 | |
|---|
| 59 | get qualifiedName from var |
|---|
| 60 | |
|---|
| 61 | get realType as IType is override |
|---|
| 62 | return .typeProvider.libraryType(_qualifiedName) |
|---|
| 63 | |
|---|
| 64 | |
|---|
| 65 | class NilableTypeProxy |
|---|
| 66 | inherits AbstractTypeProxy |
|---|
| 67 | """ |
|---|
| 68 | Returns the type proxy it is given wrapped in a NilableType. |
|---|
| 69 | Used when scanning, for example, method arguments in DLLs. See _scan* in Box. |
|---|
| 70 | """ |
|---|
| 71 | |
|---|
| 72 | var _innerType as ITypeProxy |
|---|
| 73 | |
|---|
| 74 | cue init(innerType as ITypeProxy) |
|---|
| 75 | base.init |
|---|
| 76 | _innerType = innerType |
|---|
| 77 | |
|---|
| 78 | get innerTypeProxy as ITypeProxy # TODO: should probably rename to nonNil |
|---|
| 79 | return _innerType |
|---|
| 80 | |
|---|
| 81 | def addMinFields |
|---|
| 82 | base.addMinFields |
|---|
| 83 | .addField('innerTypeProxy', .innerTypeProxy) |
|---|
| 84 | |
|---|
| 85 | get realType as IType is override |
|---|
| 86 | return .typeProvider.nilableType(_innerType.realType) |
|---|
| 87 | |
|---|
| 88 | |
|---|
| 89 | class VariTypeProxy |
|---|
| 90 | inherits AbstractTypeProxy |
|---|
| 91 | """ |
|---|
| 92 | Returns the type proxy it is given wrapped in a VariType. |
|---|
| 93 | Used when scanning, for example, method arguments in DLLs. See _scan* in Box. |
|---|
| 94 | """ |
|---|
| 95 | |
|---|
| 96 | var _innerType as ITypeProxy |
|---|
| 97 | |
|---|
| 98 | cue init(innerType as ITypeProxy) |
|---|
| 99 | base.init |
|---|
| 100 | _innerType = innerType |
|---|
| 101 | |
|---|
| 102 | get innerTypeProxy as ITypeProxy |
|---|
| 103 | return _innerType |
|---|
| 104 | |
|---|
| 105 | def addMinFields |
|---|
| 106 | base.addMinFields |
|---|
| 107 | .addField('innerTypeProxy', .innerTypeProxy) |
|---|
| 108 | |
|---|
| 109 | get realType as IType is override |
|---|
| 110 | return VariType(_innerType.realType) |
|---|
| 111 | |
|---|
| 112 | |
|---|
| 113 | class NativeTypeProxy inherits AbstractTypeProxy is abstract |
|---|
| 114 | """ |
|---|
| 115 | TypeProxy specifically for a BackEnd provided Type otherwise same as an AbstractTypeProxy |
|---|
| 116 | Specific implementation will be provided by the backend e.g. {Clr,Jvm}TypeProxy |
|---|
| 117 | """ |
|---|
| 118 | |
|---|
| 119 | ## |
|---|
| 120 | ## Type Identifiers |
|---|
| 121 | ## |
|---|
| 122 | |
|---|
| 123 | class AbstractTypeIdentifier |
|---|
| 124 | is abstract |
|---|
| 125 | inherits SyntaxNode |
|---|
| 126 | implements ITypeProxy |
|---|
| 127 | """ |
|---|
| 128 | The ancestor class for specific kinds of type identifiers including TypeIdentifier, GenericTypeIdentifier, WrappedTypeIdentifier and more. |
|---|
| 129 | """ |
|---|
| 130 | |
|---|
| 131 | var _name as String |
|---|
| 132 | var _actualType as IType? is private |
|---|
| 133 | var _didResolveType as bool is private |
|---|
| 134 | |
|---|
| 135 | cue init(token as IToken, name as String) |
|---|
| 136 | base.init(token) |
|---|
| 137 | _name = name |
|---|
| 138 | |
|---|
| 139 | cue init(token as IToken, name as String, type as IType) |
|---|
| 140 | .init(token, name) |
|---|
| 141 | _actualType = type |
|---|
| 142 | _didResolveType = true |
|---|
| 143 | |
|---|
| 144 | def addMinFields is override |
|---|
| 145 | base.addMinFields |
|---|
| 146 | .addField('name', _name) |
|---|
| 147 | .addField('didResolveType', _didResolveType) |
|---|
| 148 | |
|---|
| 149 | def addRefFields is override |
|---|
| 150 | base.addSubFields |
|---|
| 151 | .addField('actualType', _actualType) |
|---|
| 152 | |
|---|
| 153 | get name from var |
|---|
| 154 | |
|---|
| 155 | get actualType from var |
|---|
| 156 | |
|---|
| 157 | get didResolveType from var |
|---|
| 158 | |
|---|
| 159 | get realType as IType |
|---|
| 160 | ensure .actualType |
|---|
| 161 | if not .didResolveType |
|---|
| 162 | _actualType = _resolveType() |
|---|
| 163 | assert .actualType |
|---|
| 164 | _didResolveType = true |
|---|
| 165 | _recommendBuiltInType |
|---|
| 166 | assert _actualType |
|---|
| 167 | return _actualType to ! |
|---|
| 168 | |
|---|
| 169 | def _recommendBuiltInType |
|---|
| 170 | n = .backEnd.getRecommendedBuiltInType(_actualType.parentNameSpace, _actualType.name) |
|---|
| 171 | if n, .compiler.warning(this, 'Use the builtin type "[n]" instead of the struct "[_actualType.name]".') |
|---|
| 172 | |
|---|
| 173 | def equals(other as Object?) as bool is override |
|---|
| 174 | if other is nil |
|---|
| 175 | return false |
|---|
| 176 | if this is other |
|---|
| 177 | return true |
|---|
| 178 | if other inherits AbstractTypeIdentifier |
|---|
| 179 | if _actualType and other._actualType |
|---|
| 180 | return _actualType.equals(other._actualType) |
|---|
| 181 | else |
|---|
| 182 | return _name.equals(other._name) |
|---|
| 183 | return false |
|---|
| 184 | |
|---|
| 185 | def getHashCode as int is override |
|---|
| 186 | return _name.getHashCode |
|---|
| 187 | |
|---|
| 188 | def memberFrom(container as IContainer) as IMember? |
|---|
| 189 | """ |
|---|
| 190 | Used to get the real member represented by this type identifier in container. |
|---|
| 191 | Used for qualified types such as: |
|---|
| 192 | System.Windows.Forms.Control |
|---|
| 193 | System.Collections.Generic.List<of String> |
|---|
| 194 | The default implementation is: |
|---|
| 195 | return container.memberForName(.name) |
|---|
| 196 | Generics have to do more work, though. |
|---|
| 197 | So do types with funky names. |
|---|
| 198 | """ |
|---|
| 199 | return container.memberForName(.name) |
|---|
| 200 | |
|---|
| 201 | def _resolveType as IType is abstract |
|---|
| 202 | """ |
|---|
| 203 | Invoked by .realType only when needed. |
|---|
| 204 | Subclasses must override to compute and return the actual type that this identifier represents (or invoke `.throwError('...')`). |
|---|
| 205 | Subclasses should not bother with other operations such as checking or setting _actualType or _didResolveType to true. |
|---|
| 206 | Subclasses need not invoke `base`. |
|---|
| 207 | """ |
|---|
| 208 | |
|---|
| 209 | def _symbolForName(name as String) as IMember |
|---|
| 210 | """ |
|---|
| 211 | Returns the symbol for this node's name or .throwError. |
|---|
| 212 | Also, implements -correct-source:case or suggests it if it is off, but would have resolved. |
|---|
| 213 | """ |
|---|
| 214 | # don't need to check "basic types" like int, bool, etc. here. the parser does those. |
|---|
| 215 | if name.isCapitalized |
|---|
| 216 | symbol = .compiler.symbolForName(name, false) # nested enum and class types are capitalized and can be members of the current class |
|---|
| 217 | else # examples: wx.NET, libtcodWrapper.Console |
|---|
| 218 | symbol = .compiler.symbolForName(name, false, true) |
|---|
| 219 | if symbol is nil |
|---|
| 220 | correctCase = 'case' in .compiler.options.setValue('correct-source') |
|---|
| 221 | if correctCase |
|---|
| 222 | if not name.isCapitalized |
|---|
| 223 | # not very sophisticated, but catches 'string', 'object', etc. |
|---|
| 224 | name = name.capitalized |
|---|
| 225 | symbol = .compiler.symbolForName(name, false) |
|---|
| 226 | if symbol is not nil |
|---|
| 227 | if '<' in name # handle generics |
|---|
| 228 | # 'dictionary<of ' vs. 'Dictionary<of,>' |
|---|
| 229 | name = name[:name.indexOf('<')] + .token.text[.token.text.indexOf('<'):] |
|---|
| 230 | assert name.length == .token.text.length |
|---|
| 231 | .compiler.correctSource(.token, name) |
|---|
| 232 | if symbol is nil |
|---|
| 233 | sugg = Compiler.suggestionFor(name) ? '' |
|---|
| 234 | if sugg == '' and not name.isCapitalized |
|---|
| 235 | other = .compiler.symbolForName(name.capitalized, false) |
|---|
| 236 | if other, sugg = name.capitalized |
|---|
| 237 | if sugg <> '', sugg = ' Try "[sugg]". Also, consider the -correct-source option (see cobra -h for details).' |
|---|
| 238 | .throwError('Cannot find type for "[_name]".[sugg]') |
|---|
| 239 | return symbol to ! |
|---|
| 240 | |
|---|
| 241 | |
|---|
| 242 | class WrappedTypeIdentifier |
|---|
| 243 | is abstract |
|---|
| 244 | inherits AbstractTypeIdentifier |
|---|
| 245 | |
|---|
| 246 | var _typeId as AbstractTypeIdentifier |
|---|
| 247 | |
|---|
| 248 | cue init(token as IToken, typeId as AbstractTypeIdentifier) |
|---|
| 249 | require |
|---|
| 250 | token.text.length |
|---|
| 251 | ensure |
|---|
| 252 | .name.length |
|---|
| 253 | body |
|---|
| 254 | base.init(token, token.text) |
|---|
| 255 | _typeId = typeId |
|---|
| 256 | |
|---|
| 257 | def addMinFields |
|---|
| 258 | base.addMinFields |
|---|
| 259 | .addField('typeId', _typeId) |
|---|
| 260 | |
|---|
| 261 | get theWrappedTypeIdentifier from _typeId |
|---|
| 262 | |
|---|
| 263 | def _bindInt is override |
|---|
| 264 | _typeId.bindInt |
|---|
| 265 | base._bindInt |
|---|
| 266 | |
|---|
| 267 | def _bindImp is override |
|---|
| 268 | _typeId.bindImp |
|---|
| 269 | base._bindImp |
|---|
| 270 | |
|---|
| 271 | |
|---|
| 272 | class ArrayTypeIdentifier inherits WrappedTypeIdentifier |
|---|
| 273 | |
|---|
| 274 | cue init(token as IToken, typeId as AbstractTypeIdentifier) |
|---|
| 275 | base.init(token, typeId) |
|---|
| 276 | |
|---|
| 277 | def memberFrom(container as IContainer) as IMember? is override |
|---|
| 278 | return container.memberForName(.theWrappedTypeIdentifier.name) |
|---|
| 279 | |
|---|
| 280 | def _resolveType as IType is override |
|---|
| 281 | return .typeProvider.arrayType(_typeId.realType) |
|---|
| 282 | |
|---|
| 283 | |
|---|
| 284 | class NilableTypeIdentifier |
|---|
| 285 | inherits WrappedTypeIdentifier |
|---|
| 286 | """ |
|---|
| 287 | Foo? |
|---|
| 288 | """ |
|---|
| 289 | |
|---|
| 290 | cue init(token as IToken, typeId as AbstractTypeIdentifier) |
|---|
| 291 | base.init(token, typeId) |
|---|
| 292 | |
|---|
| 293 | def _resolveType as IType is override |
|---|
| 294 | return .typeProvider.nilableType(_typeId.realType) |
|---|
| 295 | |
|---|
| 296 | get name as String is override |
|---|
| 297 | return _typeId.name + '?' |
|---|
| 298 | |
|---|
| 299 | def memberFrom(container as IContainer) as IMember? is override |
|---|
| 300 | m = container.memberForName(.name[:-1]) |
|---|
| 301 | if m inherits IType |
|---|
| 302 | return .typeProvider.nilableType(m) |
|---|
| 303 | else |
|---|
| 304 | return m |
|---|
| 305 | |
|---|
| 306 | |
|---|
| 307 | class StreamTypeIdentifier |
|---|
| 308 | inherits WrappedTypeIdentifier |
|---|
| 309 | """ |
|---|
| 310 | Foo* |
|---|
| 311 | """ |
|---|
| 312 | |
|---|
| 313 | cue init(token as IToken, typeId as AbstractTypeIdentifier) |
|---|
| 314 | base.init(token, typeId) |
|---|
| 315 | |
|---|
| 316 | def _resolveType as IType is override |
|---|
| 317 | t = StreamType(_typeId.realType) |
|---|
| 318 | t.bindInh |
|---|
| 319 | t.bindInt |
|---|
| 320 | return t |
|---|
| 321 | |
|---|
| 322 | get name as String is override |
|---|
| 323 | return _typeId.name + '*' |
|---|
| 324 | |
|---|
| 325 | |
|---|
| 326 | class VariTypeIdentifier |
|---|
| 327 | inherits WrappedTypeIdentifier |
|---|
| 328 | |
|---|
| 329 | cue init(token as IToken, typeId as AbstractTypeIdentifier) |
|---|
| 330 | base.init(token, typeId) |
|---|
| 331 | |
|---|
| 332 | def _resolveType as IType is override |
|---|
| 333 | t = VariType(_typeId.realType) |
|---|
| 334 | t.bindInh |
|---|
| 335 | t.bindInt |
|---|
| 336 | return t |
|---|
| 337 | |
|---|
| 338 | |
|---|
| 339 | class TypeIdentifier |
|---|
| 340 | inherits AbstractTypeIdentifier |
|---|
| 341 | """ |
|---|
| 342 | Created by CobraParser.type for identifiers found where types are |
|---|
| 343 | expected. |
|---|
| 344 | |
|---|
| 345 | Cobra allows forward references so even though types are expected in |
|---|
| 346 | places like the return type of a method, they cannot be turned into |
|---|
| 347 | actual types until the bindInt phase (or bindImp for expressions). |
|---|
| 348 | """ |
|---|
| 349 | |
|---|
| 350 | cue init(token as IToken) |
|---|
| 351 | require |
|---|
| 352 | token.which=='ID' |
|---|
| 353 | token.text.length |
|---|
| 354 | ensure |
|---|
| 355 | .name.length |
|---|
| 356 | body |
|---|
| 357 | base.init(token, token.text) |
|---|
| 358 | |
|---|
| 359 | cue init(token as IToken, type as IType) |
|---|
| 360 | require |
|---|
| 361 | token.text.length |
|---|
| 362 | ensure |
|---|
| 363 | .name.length |
|---|
| 364 | body |
|---|
| 365 | base.init(token, token.text, type) |
|---|
| 366 | |
|---|
| 367 | cue init(token as IToken, name as String, type as IType) |
|---|
| 368 | """ |
|---|
| 369 | Use this to dictate a name other than what is specified by the token. |
|---|
| 370 | Used for QualifiedTypes, for example, that are created from multiple tokens. |
|---|
| 371 | """ |
|---|
| 372 | require |
|---|
| 373 | name.length |
|---|
| 374 | ensure |
|---|
| 375 | .name.length |
|---|
| 376 | body |
|---|
| 377 | base.init(token, name, type) |
|---|
| 378 | assert name == token.text |
|---|
| 379 | |
|---|
| 380 | def _resolveType as IType is override |
|---|
| 381 | symbol = _symbolForName(.name) to dynamic |
|---|
| 382 | if symbol inherits ITypeProxy |
|---|
| 383 | return symbol.realType |
|---|
| 384 | else |
|---|
| 385 | throw FallThroughException(symbol) |
|---|
| 386 | |
|---|
| 387 | |
|---|
| 388 | class GenericTypeIdentifier inherits AbstractTypeIdentifier |
|---|
| 389 | """ |
|---|
| 390 | The parser produces these when it encounters "List<of String>", for example. |
|---|
| 391 | """ |
|---|
| 392 | |
|---|
| 393 | var _rootName as String # ex: 'List' |
|---|
| 394 | var _fullName as String # ex: 'List<of String>' |
|---|
| 395 | var _typeRefName as String # ex: 'List<of>' 'IDictionary<of,>' -- matches the actual box |
|---|
| 396 | |
|---|
| 397 | var _numArgs as int |
|---|
| 398 | var _typeNodes as List<of ITypeProxy>? |
|---|
| 399 | |
|---|
| 400 | cue init(token as IToken, rootName as String, fullName as String, typeNodes as List<of ITypeProxy>) |
|---|
| 401 | require |
|---|
| 402 | token.which=='OPEN_GENERIC' |
|---|
| 403 | rootName.length and '<of' not in rootName |
|---|
| 404 | fullName.length and '<of' in fullName |
|---|
| 405 | typeNodes.count |
|---|
| 406 | body |
|---|
| 407 | .init(token, rootName, fullName, typeNodes, 0) |
|---|
| 408 | |
|---|
| 409 | cue init(token as IToken, rootName as String, fullName as String, numArgs as int) |
|---|
| 410 | require |
|---|
| 411 | token.which=='OPEN_GENERIC' |
|---|
| 412 | rootName.length and '<of' not in rootName |
|---|
| 413 | fullName.length and '<of' in fullName |
|---|
| 414 | numArgs > 0 |
|---|
| 415 | body |
|---|
| 416 | .init(token, rootName, fullName, nil, numArgs) |
|---|
| 417 | |
|---|
| 418 | cue init(token as IToken, rootName as String, fullName as String, typeNodes as List<of ITypeProxy>?, numArgs as int) is protected |
|---|
| 419 | require typeNodes or numArgs > 0 |
|---|
| 420 | base.init(token, fullName) |
|---|
| 421 | _rootName, _fullName = rootName, fullName |
|---|
| 422 | if typeNodes |
|---|
| 423 | _typeNodes = typeNodes |
|---|
| 424 | _typeRefName = _rootName + '<of' |
|---|
| 425 | # TODO: String(c',', _typeNodes.count-1) ? |
|---|
| 426 | for i in _typeNodes.count-1, _typeRefName += ',' |
|---|
| 427 | _typeRefName += '>' |
|---|
| 428 | _numArgs = _typeNodes.count |
|---|
| 429 | else |
|---|
| 430 | _typeRefName = fullName |
|---|
| 431 | _numArgs = numArgs |
|---|
| 432 | _name = fullName |
|---|
| 433 | |
|---|
| 434 | get numArgs from var |
|---|
| 435 | |
|---|
| 436 | get typeNodes from var |
|---|
| 437 | |
|---|
| 438 | def memberFrom(container as IContainer) as IMember? is override |
|---|
| 439 | # happens for a qualified generic. See ../Tests/160-qualified/200-qual-generic.cobra |
|---|
| 440 | genericType = container.memberForName(_typeRefName) |
|---|
| 441 | assert genericType |
|---|
| 442 | return _locateType(genericType to !) |
|---|
| 443 | |
|---|
| 444 | def _resolveType as IType is override |
|---|
| 445 | symbol = _symbolForName(_typeRefName) |
|---|
| 446 | return _locateType(symbol) |
|---|
| 447 | |
|---|
| 448 | def _locateType(genericType as IMember) as IType |
|---|
| 449 | if genericType inherits Box |
|---|
| 450 | if not genericType.isGeneric |
|---|
| 451 | .throwError('"[_rootName]" is not a generic type.') |
|---|
| 452 | if _typeNodes |
|---|
| 453 | types = List<of IType>() |
|---|
| 454 | for tn in _typeNodes, types.add(tn.realType) |
|---|
| 455 | if genericType.genericParams.count <> types.count |
|---|
| 456 | .throwError('The generic type "[_rootName]" expects [genericType.genericParams.count] type arguments, not [types.count].') |
|---|
| 457 | t = genericType.constructedTypeFor(types) |
|---|
| 458 | assert t.genericParams == types |
|---|
| 459 | assert t.isGeneric and not t.isGenericDef |
|---|
| 460 | else |
|---|
| 461 | t = genericType |
|---|
| 462 | assert t.isGeneric and t.isGenericDef |
|---|
| 463 | return t |
|---|
| 464 | else if genericType inherits IType |
|---|
| 465 | .throwError('"[_rootName]" is not a generic type.') |
|---|
| 466 | return nil to passthrough |
|---|
| 467 | else |
|---|
| 468 | assert false, 'When does this happen?' |
|---|
| 469 | .throwError('The definition for "[_fullName]" is not a type.') |
|---|
| 470 | return nil to passthrough |
|---|
| 471 | |
|---|
| 472 | |
|---|
| 473 | class QualifiedTypeIdentifier |
|---|
| 474 | inherits AbstractTypeIdentifier |
|---|
| 475 | |
|---|
| 476 | var _typeNodes as List<of AbstractTypeIdentifier> |
|---|
| 477 | |
|---|
| 478 | cue init(typeNodes as List<of AbstractTypeIdentifier>) |
|---|
| 479 | require typeNodes.count > 1 |
|---|
| 480 | base.init(typeNodes[0].token, '(uninitialized name)') |
|---|
| 481 | _typeNodes = typeNodes |
|---|
| 482 | sb = StringBuilder() |
|---|
| 483 | sep = '' |
|---|
| 484 | for t in typeNodes |
|---|
| 485 | sb.append(sep) |
|---|
| 486 | sb.append(t.name) |
|---|
| 487 | sep = '.' |
|---|
| 488 | _name = sb.toString |
|---|
| 489 | # TODO: would it be useful to set the _token.text to the name? Maybe it would help with syntax highlighting |
|---|
| 490 | |
|---|
| 491 | get typeNodes from var |
|---|
| 492 | |
|---|
| 493 | def _resolveType as IType is override |
|---|
| 494 | member = _symbolForName(_typeNodes[0].name) to ? |
|---|
| 495 | i = 1 |
|---|
| 496 | while i < _typeNodes.count and member <> nil |
|---|
| 497 | if member inherits IContainer |
|---|
| 498 | m = _typeNodes[i].memberFrom(member) |
|---|
| 499 | if m |
|---|
| 500 | member = m |
|---|
| 501 | else |
|---|
| 502 | .throwError('Cannot find "[_typeNodes[i].name]" at component [i+1] of qualified type.') |
|---|
| 503 | i += 1 |
|---|
| 504 | else |
|---|
| 505 | .throwError('"[member]" cannot contain additional members.') |
|---|
| 506 | if member inherits NameSpace # TODO: remove when NameSpace is no longer an IType |
|---|
| 507 | .throwError('The definition for "[_name]" is a namespace, not a type.') |
|---|
| 508 | if member inherits IType |
|---|
| 509 | return member |
|---|
| 510 | else |
|---|
| 511 | .throwError('The definition for "[_name]" is not a type.') |
|---|
| 512 | throw Exception('') # CC: axe when 'always throws' for methods is available |
|---|