Wiki

root/cobra/trunk/Source/Container.cobra

Revision 2636, 12.0 KB (checked in by Charles.Esterbrook, 7 weeks ago)

JVM back-end progress.
credit:hopscc

  • Property svn:eol-style set to native
Line 
1interface IContainer
2    inherits IMember
3    """
4    Containers are named nodes that respond to .declForName.
5    Containers include:
6        * NameSpace
7        * Box
8          * Class
9          * Struct
10          * Interface
11        * Enum
12    """
13    def declForName(name as String) as IMember?
14        """
15        Returns the member declared in this container with the given name.
16        May return nil if no such member exists.
17        Does not follow inheritance chains.
18        Case-sensitive.
19        """
20
21    def memberForName(name as String) as IMember?
22        """
23        Returns the member of this container with the given name, including any inherited members.
24        Since Object is the root of even primitive types and enumerations, then this method may return a Method such as .toString or .getHashCode.
25        May return nil if no such member exists.
26        Case-sensitive.
27        """
28# TODO:
29#       require
30#           # TODO: not .compiler.isParsing
31#           not .compiler.isBindingInh
32
33
34interface IParentSpace
35    is partial
36    inherits IContainer
37    """
38    Basically namespaces and boxes are "parent spaces" meaning they can contain others.
39    For example, any box can be contained by a namespace. And its anticipated that in the future, Cobra will support nested boxes.
40    Any namespace can be contained by another namespace.
41    But this is not a perfect model of how things work since a NameSpace cannot have a Box as a parent.
42    """
43   
44    pass
45
46
47class Container<of TMember>
48    is abstract, partial
49    where TMember must be class, IMember
50    inherits NamedNode
51    implements IContainer, IType
52    """
53    A container of declarations.
54   
55    A container has (optionally) a parent namespace or box, declarations preserved in order and
56    indexed by name, a doc string and "is names".
57
58    The declForName[CI] methods do not follow inheritance, but
59    .memberForName should (subclasses have to override).
60
61    IMember is implemented (brought in via IContainer).
62
63    Subclasses are responsible for passing bindInt and bindImp to _declsInOrder.  TODO: should that be the case
64
65    TODO: Should Container inherit from CobraType? I guess the problem is that NamedNode is a
66    SyntaxNode and CobraType inherits from Node. However, IType does specify a name... Maybe
67    NamedNode should inherit Node and the token thing done via ISyntaxNode only. At the very
68    least, .greatestCommonDenominatorWith is duplicated. Others may be as well.
69
70        More thoughts on this. NameSpace inherits from Container, but NameSpace is *not* a type.
71        Also, there are several members here that are duplicated from CobraType.
72        I wish .NET had natural support for multiple inheritance
73        So my current thoughts:
74            Container should not implement IType
75            Box should implement IType
76            Live with some duplication for now
77            Later, move duplicated members to the IType interface when Cobra supports interface code
78    """
79
80    var _parentNameSpace as NameSpace?
81    var _parentBox as Box?
82
83    var _declsInOrder as List<of TMember>
84    var _declsByName as Dictionary<of String, TMember>
85    var _declsByNameCI as Dictionary<of String, TMember>
86    var _docString as String
87    var _isNames as IList<of String>
88
89    cue init(token as IToken, name as String, isNames as String*, docString as String?)
90        .init(nil, token, name, isNames, docString)
91
92    cue init(parent as IParentSpace?, token as IToken, name as String, isNames as String*, docString as String?)
93        base.init(token, name)
94        _initParent(parent)
95        _declsInOrder = List<of TMember>()
96        _declsByName = Dictionary<of String, TMember>()
97        _declsByNameCI = Dictionary<of String, TMember>()
98        _isNames = isNames.toList
99        _docString = docString ? ''
100
101    def _initParent(parent as IParentSpace?)
102        if parent
103            if parent inherits NameSpace
104                # _parentNameSpace = parent
105                # don't set the parentNameSpace because NameSpace.addDecl does that *and* there it will substitute its .unifiedNameSpace
106                pass
107            else if parent inherits Box
108                _parentBox = parent
109            else
110                throw FallThroughException(parent)
111
112    get attributes as AttributeList
113        return AttributeList()
114
115    get canDeclNamesDifferOnlyByCase as bool
116        """
117        Cobra normally disallows declarations that differ only in their case.
118        This works fine for source code, but not for reading assemblies.
119        """
120        return false
121
122    get declsInOrder from var
123
124    get isNames as String*
125        return _isNames
126
127    pro parentNameSpace from var
128        """
129        The namespace this container was declared inside of, if any.
130        If nil, the .parentBox should not be.
131        """
132
133    pro parentBox from var
134        """
135        The box this container was declared inside of, if any.
136        Consider, for example, an enumeration that is declared inside a class.
137        If nil, the .parentNameSpace should not be.
138        """
139
140    get parent as IParentSpace?
141        if .parentBox, return .parentBox
142        if .parentNameSpace, return .parentNameSpace
143        return nil
144
145    def addDecl(decl as TMember)
146        require
147            decl.name.length
148            not .declsInOrder.contains(decl)
149            .declForName(decl.name) is nil
150            not .canDeclNamesDifferOnlyByCase implies .declForNameCI(decl.name) is nil
151        ensure
152            .declsInOrder.contains(decl)
153            .declForName(decl.name) is decl
154            .declForNameCI(decl.name) is decl
155            .declsInOrder.count == old .declsInOrder.count + 1
156        body
157            _declsInOrder.add(decl)
158            _declsByName.add(decl.name, decl)
159            if .canDeclNamesDifferOnlyByCase
160                _declsByNameCI[decl.name.toLower] = decl
161            else
162                _declsByNameCI.add(decl.name.toLower, decl)
163
164    def declForName(name as String) as TMember?
165        require
166            name.length
167        ensure
168            result implies result.name==name
169        body
170            #print _declsByName.keys
171            return if(_declsByName.containsKey(name), _declsByName[name], nil)
172           
173    # for debug
174    def dumpDeclsNameKeys
175        print _declsByName.keys
176       
177    def declForName(name as String) as IMember?
178        implements IContainer
179        return if(_declsByName.containsKey(name), _declsByName[name], nil)
180
181    def declForNameCI(name as String) as TMember?
182        require
183            name.length
184        ensure
185            result implies result.name.toLower==name.toLower
186            result is nil implies .declForName(name) is nil
187        body
188            decl as TMember?
189            _declsByNameCI.tryGetValue(name.toLower, out decl)
190            return decl
191
192    pro docString from var
193
194    def addSubFields is override
195        base.addSubFields
196        .addField('declsInOrder', _declsInOrder)
197
198    def dumpDeclNames
199        print
200        print this
201        for decl in _declsInOrder
202            print [decl.name] --> [decl.getType.name]'
203
204
205    ## IMember
206
207    get englishName as String is abstract
208
209    get isCallable as bool
210        return false
211
212    get requiresThis as bool
213        return false
214
215    get resultType as IType
216        return this
217
218
219    ## IType
220
221    def greatestCommonDenominatorWith(type as IType) as IType
222        # TODO: the duplication with CobraType here feels wrong
223        if this is type
224            return this
225        if type inherits NilableType
226            return type.greatestCommonDenominatorWith(this)
227        if type inherits NilType
228            return .typeProvider.nilableType(this)
229        if .isDescendantOf(type)
230            return type
231        if type.isDescendantOf(this)
232            return this
233        # TODO: following is a guess
234        if .superType and type.superType
235            return .superType.greatestCommonDenominatorWith(type.superType to !)
236        else
237            return .compiler.objectType
238
239    def isAssignableTo(type as IType) as bool
240        require
241            .compiler
242        body
243            # TODO: some code dup with IType
244            if .serialNum == type.serialNum
245                assert this is type
246            if this is type
247                return true
248            if type is .compiler.passThroughType
249                return true
250            if type is .compiler.dynamicType
251                return true
252            if type is .compiler.objectType
253                return true
254            if type inherits NilableType
255                return .isAssignableTo(type.theWrappedType to passthrough)  # CC: weird cast. bug. has to do with if-inherits and invoking the same method
256            return .isDescendantOf(type)
257
258    # CC: duplicated from Type
259    def isComparableTo(t as IType) as bool
260        t = t.nonNil
261        if t inherits NilableType
262            t = t.theWrappedType
263        compareTo = .memberForName('compareTo')
264        if compareTo and compareTo.isMethod and compareTo.resultType is .compiler.intType and t.isDescendantOf(this)
265            # TODO: check that the compareTo can take a `t` as an argument
266            return true
267        return false
268
269    # CC: duplicated from Type
270    def isEquatableTo(t as IType) as bool
271        t = t.nonNil
272        if .isAssignableTo(t) or t.isAssignableTo(this)  # CC: to ! or assert above with nil flow analysis
273            return true
274        return false
275
276    # CC: duplicated from Type
277    get nonNil as IType
278        return this
279
280    def isDescendantOf(type as IType) as bool
281        require .didBindInh
282        return type is this
283
284    # CC: duplicated from Type
285    def isStrictDescendantOf(type as IType) as bool
286        if type is this
287            return false
288        else
289            return .isDescendantOf(type)
290
291    get isDynamic as bool
292        return false
293
294    get isReference as bool is abstract
295
296    get isSystemObjectClass as bool
297        return false
298
299    get isSystemTypeClass as bool
300        return false
301
302    get isUninitializedForLocalVars as bool
303        return .isReference
304
305    get innerType as IType?
306        return nil
307
308    get realType as IType
309        return this
310       
311    get superType as IType?
312        require .didBindInh
313        return nil
314
315    def secondaryConstructedTypeFor(box as Box, gpToType as Dictionary<of GenericParam, IType>) as IType
316        return this
317
318    def memberForName(name as String) as IMember?
319        require .canAccessMemberForName
320        return .declForName(name)
321
322    get canAccessMemberForName as bool
323        # TODO: return not .compiler.isParsing  # use .declForName instead
324        return true
325
326    def suggestionsForBadMemberName(name as String) as List<of String>
327        name = name.toLower
328        suggs = List<of String>()
329        for decl in _declsInOrder
330            declName = decl.name.toLower
331            if declName == name or declName in name or name in declName
332                suggs.add(decl.name)
333            # TODO: would be nice to pick up on extraneous chars, missing chars, transposed chars
334        suggs.sort
335        return suggs
336
337    # 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.
338
339    get defaultAccessLevel as String is abstract
340
341    get isShared as bool
342        return 'shared' in _isNames
343
344    def unNilReturnType
345        # TODO: can this be axed when IMember gets broken up?
346        pass
347
348
349    ## Other
350
351    def cloneCollections
352        _declsInOrder = List<of TMember>(_declsInOrder)
353        _declsByName = Dictionary<of String, TMember>(_declsByName)
354        _declsByNameCI = Dictionary<of String, TMember>(_declsByNameCI)
355
356
357interface IMember
358    is partial
359    inherits INamedNode
360    """
361    TODO: this really needs to be split up into INameSpaceMember and IBoxMember. *Maybe* there is a logical IMember parent interface to both of those.
362   
363    Anything that could conceivably be a member of namespace, class,
364    struct or interface, implements IMember.
365
366    That includes namespaces, classes, structs and interfaces
367    themselves. As well as the obvious choices of methods, inits,
368    properties and indexers. Also, enums and generic parameters, which
369    themselves can be specific types such as `int`.
370
371    That mostly leaves statements and expressions as the nodes that
372    cannot be IMembers.
373
374    IContainer and Container both reference IMember extensively.
375
376    Furthermore, IContainer happens to implement IMember because, as it
377    turns out, all of the containers may be members of other containers
378    (though not without restrictions (a namespace can belong to only
379    another namespace)).
380    """
381
382    get attributes as AttributeList
383        """
384        Return the attributes of this member.
385        """
386
387    get isCallable as bool
388        """
389        Returns true if this member can be called with parens: () or (args)
390        """
391
392    get isShared as bool
393        """
394        Returns true if this member is shared (non-shared members can be
395        called instance members).
396        """
397
398    get englishName as String  # TODO: rename to englishTypeName
399        """
400        Return the type of member as a plain, lowercase English word:
401            class, property, method, namespace, etc.
402        """
403
404    pro parentNameSpace as NameSpace?
405        """
406        The NameSpace that the member directly belongs to, if any.
407        """
408
409    get requiresThis as bool
410        """
411        Returns true if accessing the member requires a `this`
412        reference. True of non-shared properties, methods and fields.
413        """
414
415    get resultType as IType  # TODO: rename to dottedAccessResultType
416        """
417        Returns the result of accessing this member in the source
418        expression "foo.bar" where this is the bar. For a method or
419        property, this would be the return type. For other members like
420        enums and classes, this would be the member itself.
421        """
422
423    def unNilReturnType
424        """
425        This is invoked to fix up the CLR library which does not indicate, for example, that StringBuilder.toString returns String not String?
426        """
Note: See TracBrowser for help on using the browser.