Wiki

root/cobra/trunk/Source/TypeProxies.cobra

Revision 2579, 14.0 KB (checked in by Charles.Esterbrook, 10 months ago)

Code cleanup.

  • Property svn:eol-style set to native
Line 
1interface 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
21class AbstractTypeProxy
22    is abstract
23    inherits Node
24    implements ITypeProxy
25
26    get realType as IType is abstract
27
28
29class 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
46class 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
65class 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
89class 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
113class 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
123class 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
242class 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
272class 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
284class 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
307class 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
326class 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
339class 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
388class 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
473class 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
Note: See TracBrowser for help on using the browser.