interface IContainer inherits IMember """ Containers are named nodes that respond to .declForName. Containers include: * NameSpace * Box * Class * Struct * Interface * Enum """ def declForName(name as String) as IMember? """ Returns the member declared in this container with the given name. May return nil if no such member exists. Does not follow inheritance chains. Case-sensitive. """ def memberForName(name as String) as IMember? """ Returns the member of this container with the given name, including any inherited members. Since Object is the root of even primitive types and enumerations, then this method may return a Method such as .toString or .getHashCode. May return nil if no such member exists. Case-sensitive. """ # TODO: # require # # TODO: not .compiler.isParsing # not .compiler.isBindingInh interface IParentSpace is partial inherits IContainer """ Basically namespaces and boxes are "parent spaces" meaning they can contain others. For example, any box can be contained by a namespace. And its anticipated that in the future, Cobra will support nested boxes. Any namespace can be contained by another namespace. But this is not a perfect model of how things work since a NameSpace cannot have a Box as a parent. """ pass class Container is abstract, partial where TMember must be class, IMember inherits NamedNode implements IContainer, IType """ A container of declarations. A container has (optionally) a parent namespace or box, declarations preserved in order and indexed by name, a doc string and "is names". The declForName[CI] methods do not follow inheritance, but .memberForName should (subclasses have to override). IMember is implemented (brought in via IContainer). Subclasses are responsible for passing bindInt and bindImp to _declsInOrder. TODO: should that be the case TODO: Should Container inherit from CobraType? I guess the problem is that NamedNode is a SyntaxNode and CobraType inherits from Node. However, IType does specify a name... Maybe NamedNode should inherit Node and the token thing done via ISyntaxNode only. At the very least, .greatestCommonDenominatorWith is duplicated. Others may be as well. More thoughts on this. NameSpace inherits from Container, but NameSpace is *not* a type. Also, there are several members here that are duplicated from CobraType. I wish .NET had natural support for multiple inheritance So my current thoughts: Container should not implement IType Box should implement IType Live with some duplication for now Later, move duplicated members to the IType interface when Cobra supports interface code """ var _parentNameSpace as NameSpace? var _parentBox as Box? var _declsInOrder as List var _declsByName as Dictionary var _declsByNameCI as Dictionary var _docString as String var _isNames as IList cue init(token as IToken, name as String, isNames as String*, docString as String?) .init(nil, token, name, isNames, docString) cue init(parent as IParentSpace?, token as IToken, name as String, isNames as String*, docString as String?) base.init(token, name) _initParent(parent) _declsInOrder = List() _declsByName = Dictionary() _declsByNameCI = Dictionary() _isNames = isNames.toList _docString = docString ? '' def _initParent(parent as IParentSpace?) if parent if parent inherits NameSpace # _parentNameSpace = parent # don't set the parentNameSpace because NameSpace.addDecl does that *and* there it will substitute its .unifiedNameSpace pass else if parent inherits Box _parentBox = parent else throw FallThroughException(parent) get attributes as AttributeList return AttributeList() get canDeclNamesDifferOnlyByCase as bool """ Cobra normally disallows declarations that differ only in their case. This works fine for source code, but not for reading assemblies. """ return false get declsInOrder from var get isNames as String* return _isNames pro parentNameSpace from var """ The namespace this container was declared inside of, if any. If nil, the .parentBox should not be. """ pro parentBox from var """ The box this container was declared inside of, if any. Consider, for example, an enumeration that is declared inside a class. If nil, the .parentNameSpace should not be. """ get parent as IParentSpace? if .parentBox, return .parentBox if .parentNameSpace, return .parentNameSpace return nil def addDecl(decl as TMember) require decl.name.length not .declsInOrder.contains(decl) .declForName(decl.name) is nil not .canDeclNamesDifferOnlyByCase implies .declForNameCI(decl.name) is nil ensure .declsInOrder.contains(decl) .declForName(decl.name) is decl .declForNameCI(decl.name) is decl .declsInOrder.count == old .declsInOrder.count + 1 body _declsInOrder.add(decl) _declsByName.add(decl.name, decl) if .canDeclNamesDifferOnlyByCase _declsByNameCI[decl.name.toLower] = decl else _declsByNameCI.add(decl.name.toLower, decl) def declForName(name as String) as TMember? require name.length ensure result implies result.name==name body #print _declsByName.keys return if(_declsByName.containsKey(name), _declsByName[name], nil) # for debug def dumpDeclsNameKeys print _declsByName.keys def declForName(name as String) as IMember? implements IContainer return if(_declsByName.containsKey(name), _declsByName[name], nil) def declForNameCI(name as String) as TMember? require name.length ensure result implies result.name.toLower==name.toLower result is nil implies .declForName(name) is nil body decl as TMember? _declsByNameCI.tryGetValue(name.toLower, out decl) return decl pro docString from var def addSubFields is override base.addSubFields .addField('declsInOrder', _declsInOrder) def dumpDeclNames print print this for decl in _declsInOrder print ' [decl.name] --> [decl.getType.name]' ## IMember get englishName as String is abstract get isCallable as bool return false get requiresThis as bool return false get resultType as IType return this ## IType def greatestCommonDenominatorWith(type as IType) as IType # TODO: the duplication with CobraType here feels wrong if this is type return this if type inherits NilableType return type.greatestCommonDenominatorWith(this) if type inherits NilType return .typeProvider.nilableType(this) if .isDescendantOf(type) return type if type.isDescendantOf(this) return this # TODO: following is a guess if .superType and type.superType return .superType.greatestCommonDenominatorWith(type.superType to !) else return .compiler.objectType def isAssignableTo(type as IType) as bool require .compiler body # TODO: some code dup with IType if .serialNum == type.serialNum assert this is type if this is type return true if type is .compiler.passThroughType return true if type is .compiler.dynamicType return true if type is .compiler.objectType return true if type inherits NilableType return .isAssignableTo(type.theWrappedType to passthrough) # CC: weird cast. bug. has to do with if-inherits and invoking the same method return .isDescendantOf(type) # CC: duplicated from Type def isComparableTo(t as IType) as bool t = t.nonNil if t inherits NilableType t = t.theWrappedType compareTo = .memberForName('compareTo') if compareTo and compareTo.isMethod and compareTo.resultType is .compiler.intType and t.isDescendantOf(this) # TODO: check that the compareTo can take a `t` as an argument return true return false # CC: duplicated from Type def isEquatableTo(t as IType) as bool t = t.nonNil if .isAssignableTo(t) or t.isAssignableTo(this) # CC: to ! or assert above with nil flow analysis return true return false # CC: duplicated from Type get nonNil as IType return this def isDescendantOf(type as IType) as bool require .didBindInh return type is this # CC: duplicated from Type def isStrictDescendantOf(type as IType) as bool if type is this return false else return .isDescendantOf(type) get isDynamic as bool return false get isReference as bool is abstract get isSystemObjectClass as bool return false get isSystemTypeClass as bool return false get isUninitializedForLocalVars as bool return .isReference get innerType as IType? return nil get realType as IType return this get superType as IType? require .didBindInh return nil def secondaryConstructedTypeFor(box as Box, gpToType as Dictionary) as IType return this def memberForName(name as String) as IMember? require .canAccessMemberForName return .declForName(name) get canAccessMemberForName as bool # TODO: return not .compiler.isParsing # use .declForName instead return true def suggestionsForBadMemberName(name as String) as List name = name.toLower suggs = List() for decl in _declsInOrder declName = decl.name.toLower if declName == name or declName in name or name in declName suggs.add(decl.name) # TODO: would be nice to pick up on extraneous chars, missing chars, transposed chars suggs.sort return suggs # TODO: _isNames, .writeSharpIsNames and defaultAccessLevel should be moved out to a mixin since NameSpace, a subclass of Container, has no isNames. Box and Enum do. So does ClassMember which duplicates this. get defaultAccessLevel as String is abstract get isShared as bool return 'shared' in _isNames def unNilReturnType # TODO: can this be axed when IMember gets broken up? pass ## Other def cloneCollections _declsInOrder = List(_declsInOrder) _declsByName = Dictionary(_declsByName) _declsByNameCI = Dictionary(_declsByNameCI) interface IMember is partial inherits INamedNode """ TODO: this really needs to be split up into INameSpaceMember and IBoxMember. *Maybe* there is a logical IMember parent interface to both of those. Anything that could conceivably be a member of namespace, class, struct or interface, implements IMember. That includes namespaces, classes, structs and interfaces themselves. As well as the obvious choices of methods, inits, properties and indexers. Also, enums and generic parameters, which themselves can be specific types such as `int`. That mostly leaves statements and expressions as the nodes that cannot be IMembers. IContainer and Container both reference IMember extensively. Furthermore, IContainer happens to implement IMember because, as it turns out, all of the containers may be members of other containers (though not without restrictions (a namespace can belong to only another namespace)). """ get attributes as AttributeList """ Return the attributes of this member. """ get isCallable as bool """ Returns true if this member can be called with parens: () or (args) """ get isShared as bool """ Returns true if this member is shared (non-shared members can be called instance members). """ get englishName as String # TODO: rename to englishTypeName """ Return the type of member as a plain, lowercase English word: class, property, method, namespace, etc. """ pro parentNameSpace as NameSpace? """ The NameSpace that the member directly belongs to, if any. """ get requiresThis as bool """ Returns true if accessing the member requires a `this` reference. True of non-shared properties, methods and fields. """ get resultType as IType # TODO: rename to dottedAccessResultType """ Returns the result of accessing this member in the source expression "foo.bar" where this is the bar. For a method or property, this would be the return type. For other members like enums and classes, this would be the member itself. """ def unNilReturnType """ This is invoked to fix up the CLR library which does not indicate, for example, that StringBuilder.toString returns String not String? """