Wiki

Ticket #262: property-overload.patch

File property-overload.patch, 20.6 KB (added by hopscc, 7 years ago)
  • Source/Members.cobra

     
    12381238    var _coverAccess as String? 
    12391239    var _returnType as IType? 
    12401240    var _returnTypeNode as ITypeProxy? 
     1241     
     1242    var _implementsTypeNode as ITypeProxy? 
     1243    var _implementsType as IType? 
    12411244 
    12421245    cue init(token as IToken, idToken as IToken, box as Box, name as String, isNames as String*, attribs as AttributeList, docString as String?) 
    12431246        base.init(token, idToken, box, name, isNames, attribs, docString) 
     
    12661269        if _coverVar, .addField('coverVar', _coverVar) 
    12671270        if _returnType, .addField('returnType', _returnType) 
    12681271        else, .addField('returnTypeNode', _returnTypeNode) 
     1272        .addField('implementsType', _implementsType) 
    12691273 
    12701274    def addSubFields is override 
    12711275        base.addSubFields 
     1276        if _implementsTypeNode 
     1277            .addField('implementsTypeNode', _implementsTypeNode) 
    12721278        if _getPart, .addField('getPart', _getPart) 
    12731279        if _setPart, .addField('setPart', _setPart) 
    12741280 
     1281    get defaultAccessLevel as String is override 
     1282        dal = base.defaultAccessLevel 
     1283        if dal.length and not _implementsType and not _implementsTypeNode 
     1284            return dal 
     1285        else 
     1286            return '' 
     1287 
    12751288    get returnType from var 
    12761289 
    12771290    get returnTypeNode from var 
     
    12871300    get setPart from var 
    12881301 
    12891302    get shouldBeVirtual as bool is override 
    1290         return .isClassMember and not .isPrivate  # TODO: and not _implementsTypeNode and not _implementsType 
     1303        return .isClassMember and not .isPrivate and not _implementsTypeNode and not _implementsType 
     1304         
     1305    set implementsTypeNode as ITypeProxy     
     1306        _implementsTypeNode = value 
     1307        if 'virtual' in _isNames  
     1308            _isNames.remove('virtual') 
    12911309 
    12921310    def mergedIntoPartialBox(newBox as Box) 
    12931311        base.mergedIntoPartialBox(newBox) 
     
    13301348 
    13311349    def _bindImp is override 
    13321350        base._bindImp 
     1351        if _implementsTypeNode 
     1352            _implementsType = _implementsTypeNode.realType 
     1353            # TODO: make sure the type is among the interfaces of the box 
    13331354        if _getPart, _getPart.bindImp 
    13341355        if _setPart, _setPart.bindImp 
    13351356 
  • Source/Expr.cobra

     
    15651565                                _definition = member 
    15661566                                didResolveOverload = true 
    15671567                                break 
     1568                for member in defn.members 
     1569                    if member inherits ProperDexer  # prefers first declared 
     1570                        if member.params.count == 0    
     1571                            _definition = member 
     1572                            didResolveOverload = true 
     1573                            break 
    15681574                if not didResolveOverload 
    15691575                    .throwError('Could not find an overload for "[.name]" with zero arguments.') 
    15701576            else if defn inherits AbstractMethod 
  • Source/BackEndClr/SharpGenerator.cobra

     
    19141914        .writeSharpNotNull(sw) 
    19151915        .writeSharpAttribs(sw) 
    19161916        .writeSharpIsNames(sw) 
    1917         sw.write(' [_returnType.sharpRef] [.name.capitalized]') 
     1917        name = .name.capitalized 
     1918        if _implementsType 
     1919            name = _implementsType.sharpRef + '.' + name 
     1920        sw.write(' [_returnType.sharpRef] [name]') 
    19181921        .writeSharpBody(sw) 
    19191922        getPart = .getPart 
    19201923        if getPart 
  • Source/Boxes.cobra

     
    10461046                    other = _declsByName[decl.name] 
    10471047                    if other inherits MemberOverload 
    10481048                        overload = other 
    1049                     else if other inherits AbstractMethod 
    1050                         overload = MemberOverload(other) 
     1049                    else if other inherits AbstractMethod or other inherits ProperDexer  
     1050                        overload = MemberOverload(other to BoxMember) 
    10511051                        .registerOverload(overload to !) 
    10521052                    else 
    10531053                        throw FallThroughException(other) 
  • Source/CobraParser.cobra

     
    15311531            .dedent 
    15321532 
    15331533        methodSig = MethodSig(wordToken, opener, curContainer to IParentSpace, name, params, returnType, isNames, attribs, docString) 
    1534  
    15351534        return methodSig 
    15361535         
     1536    # 
     1537    # Properties 
     1538    # 
     1539 
     1540    # Enum for the current 3 variants of a property declaration 
     1541    enum PropertyVariant 
     1542        getOnly 
     1543        setOnly 
     1544        getAndSet 
     1545         
    15371546    def declareProperty as ProperDexer? 
    1538         """ 
    1539         Example source 
    1540             pro age as int 
    1541                 get 
    1542                     return _age 
    1543                 set 
    1544                     assert value>0 
    1545                     _age = value 
     1547        return _declareProperty(PropertyVariant.getAndSet) 
    15461548 
    1547         If .curBox is an Interface, then no body. 
    1548         If 'abstract' is in the "is names" then no body. 
    1549         The "is names" can be on the same line or the next. 
    1550         No explicit return type implies "as dynamic" (same as arguments). 
    1551         No "implements" in interfaces. 
    1552         """ 
    1553         curBox = .curBox 
    1554         prop as ProperDexer? 
    1555         token = .expect('PRO') 
    1556         overload as MemberOverload? 
    1557         if .optional('LBRACKET') 
    1558             idToken = .last to ! 
    1559             params = .paramDecls(true, 'RBRACKET') 
    1560             name = r'[]' 
    1561             overload = _overloadIfNeeded(idToken, curBox, name) 
    1562         else 
    1563             idToken = .idOrKeyword 
    1564             name = idToken.text 
    1565             .checkProperty(name) 
    1566             if .optional('FROM') 
    1567                 return .declarePropertyFrom(token, idToken, name, 'getset') 
    1568             params = List<of Param>() 
    1569         if .optional('AS') 
    1570             returnType = .typeId to ITypeProxy 
    1571         else 
    1572             returnType = _typeProvider.defaultType 
    1573         # TODO: implements? 
    1574         hasIsNames = false 
    1575         isAbstract = false 
    1576         if .peek.which == 'IS' 
    1577             isNames = .isDeclNames 
    1578             isAbstract = 'abstract' in isNames 
    1579             hasIsNames = true 
    1580             indent = .optional('INDENT') 
    1581         else 
    1582             indent = .optionalIndent 
    1583         if indent 
    1584             if not hasIsNames 
    1585                 isNames = .isDeclNames 
    1586             isAbstract = 'abstract' in isNames 
    1587             hasIsNames = true 
    1588             attribs = .hasAttribs 
    1589             docString = .docString 
    1590         else 
    1591             # no additional specs 
    1592             if not isAbstract and curBox.canHaveStatements 
    1593                 .throwError('Missing body for property.') 
    1594             if not hasIsNames 
    1595                 isNames = List<of String>(_isNamesStack) 
    1596             attribs = AttributeList() 
    1597             docString = '' 
    1598         if params.count 
    1599             prop = Indexer(token, idToken, curBox, name, params, returnType, isNames, attribs, docString) 
    1600         else 
    1601             prop = Property(token, idToken, curBox, name, returnType, isNames, attribs, docString) 
    1602         if indent 
    1603             if .peek.which=='TEST' 
    1604                 if curBox inherits Interface 
    1605                     _warning(.peek, 'Interface `test` sections are parsed, but ignored. In the future, classes will acquire the tests of the interfaces they implement.') 
    1606                 # TODO: what about abstract? 
    1607                 .testSection(prop to !) 
    1608             getWord = .optional('GET') 
    1609             if getWord 
    1610                 if isAbstract or not curBox.canHaveStatements 
    1611                     prop.makeGetPart(getWord) 
    1612                 else 
    1613                     .indent 
    1614                     .statementsFor(prop.makeGetPart(getWord)) 
    1615             setWord = .optional('SET') 
    1616             if setWord 
    1617                 if isAbstract or not curBox.canHaveStatements 
    1618                     prop.makeSetPart(setWord) 
    1619                 else 
    1620                     .indent 
    1621                     .statementsFor(prop.makeSetPart(setWord)) 
    1622             if not getWord and not setWord 
    1623                 if isAbstract or not curBox.canHaveStatements 
    1624                     prop.makeGetPart(TokenFix.empty) 
    1625                     prop.makeSetPart(TokenFix.empty) 
    1626                 else 
    1627                     .throwError('Expecting "get" or "set" for the property.') 
    1628             .dedent 
    1629         else 
    1630             prop.makeGetPart(TokenFix.empty) 
    1631             prop.makeSetPart(TokenFix.empty) 
    1632         if isAbstract and not curBox inherits Class 
    1633             .throwError('Only properties in classes can be marked abstract.') 
    1634         if overload 
    1635             assert prop 
    1636             overload.addMember(prop to !) 
    1637             return nil 
    1638         else 
    1639             return prop 
     1549    def declareGetOnlyProperty as ProperDexer? 
     1550        return _declareProperty(PropertyVariant.getOnly) 
    16401551 
     1552    def declareSetOnlyProperty as ProperDexer? 
     1553        return _declareProperty(PropertyVariant.setOnly) 
     1554 
    16411555    def declarePropertyFrom(token as IToken, idToken as IToken, name as String, coverWhat as String) as Property 
    16421556        require coverWhat.isOneOf('get.set.getset.') 
    16431557        if .optional('VAR') 
     
    16911605            .throwError('Property backing variable "[varName]" has already been initialized.') # include line# of backing variable decl 
    16921606        return varDef 
    16931607             
    1694     def declareGetOnlyProperty as ProperDexer? 
    1695         return _declareGetOrSetOnlyProperty(0) 
    1696  
    1697     def declareSetOnlyProperty as ProperDexer? 
    1698         return _declareGetOrSetOnlyProperty(1) 
    1699  
    1700     def _declareGetOrSetOnlyProperty(getOrSet as int) as ProperDexer? 
     1608    sig PropBodySig(token as IToken, prop as ProperDexer, isAbstract as bool, curBox as Box) 
     1609    sig MakePartSig(token as IToken) as AbstractMethod 
     1610         
     1611    #Parse all the variants of Property declaration; get, set and full (getAndSet) 
     1612    def _declareProperty(getOrSet as PropertyVariant) as ProperDexer? 
    17011613        """ 
    17021614        Example source 
     1615            pro age as int 
     1616                get 
     1617                    return _age 
     1618                set 
     1619                    assert value>0 
     1620                    _age = value 
     1621 
    17031622            get meaningOfLife as int 
    17041623                return 42 
     1624                 
     1625            set timeToDie 
     1626                assert value > 55 
     1627                _dieTime = value 
     1628                 
     1629        If .curBox is an Interface, then no body. 
     1630        If 'abstract' is in the "is names" then no body. 
     1631        The "is names" can be on the same line or the next. 
     1632        No explicit return type implies "as dynamic" (same as arguments). 
     1633        No "implements" in interfaces. 
    17051634        """ 
    1706         require getOrSet in [0, 1] 
     1635        require getOrSet in [PropertyVariant.getOnly, PropertyVariant.setOnly, PropertyVariant.getAndSet] 
    17071636        curBox = .curBox 
    17081637        prop as ProperDexer? 
    1709         token = .expect(if(getOrSet, 'SET', 'GET')) 
     1638        tokenStr = ['GET', 'SET', 'PRO'][getOrSet to int] 
     1639        token = .expect(tokenStr) 
    17101640        overload as MemberOverload? 
    1711         if .optional('LBRACKET') 
     1641        if .optional('LBRACKET')    # Indexer 
    17121642            idToken = .last to ! 
    17131643            params = .paramDecls(true, 'RBRACKET') 
    17141644            name = r'[]' 
    1715             overload = _overloadIfNeeded(idToken, curBox, name) 
     1645            #overload = _overloadIfNeeded(idToken, curBox, name) 
    17161646        else 
    17171647            idToken = .idOrKeyword 
    17181648            name = idToken.text 
    17191649            .checkProperty(name) 
    17201650            if .optional('FROM') 
    1721                 return .declarePropertyFrom(token, idToken, name, if(getOrSet, 'set', 'get')) 
     1651                tokenStr = ['get', 'set', 'getset'][getOrSet to int] 
     1652                return .declarePropertyFrom(token, idToken, name, tokenStr) 
    17221653            params = List<of Param>() 
    17231654        if .optional('AS') 
    17241655            returnType = .typeId to ITypeProxy 
    17251656        else 
    17261657            returnType = _typeProvider.defaultType 
    1727         # TODO: implements? 
     1658        implementsType as ITypeProxy? 
     1659        if .optional('IMPLEMENTS') 
     1660            implementsType = .typeId 
    17281661        hasIsNames = false 
    17291662        isAbstract = false 
    17301663        if .peek.which == 'IS' 
     
    17531686            prop = Indexer(token, idToken, curBox, name, params, returnType, isNames, attribs, docString) 
    17541687        else 
    17551688            prop = Property(token, idToken, curBox, name, returnType, isNames, attribs, docString) 
     1689        if implementsType  
     1690            prop.implementsTypeNode = implementsType     
    17561691        if indent 
    17571692            if .peek.which=='TEST' 
    17581693                if curBox inherits Interface 
    17591694                    _warning(.peek, 'Interface `test` sections are parsed, but ignored. In the future, classes will acquire the tests of the interfaces they implement.') 
    17601695                # TODO: what about abstract? 
    17611696                .testSection(prop to !) 
    1762             part = if(getOrSet, prop.makeSetPart(token), prop.makeGetPart(token)) 
    1763             if isAbstract or not curBox.canHaveStatements 
    1764                 .dedent 
    1765             else 
    1766                 .statementsFor(part, prop) 
    1767         else 
    1768             if getOrSet 
     1697                 
     1698            # needs ref correctly generating Type or explicit typing on Collection Literals 
     1699            #propBody as PropBodySig = [ref _getPropBody, ref _setPropBody, ref _getSetPropBody][getOrSet to int] 
     1700            #propBody(token, prop to !, isAbstract, curBox) 
     1701            propBodyList = List<of PropBodySig>() 
     1702            propBodyList.add(ref _getPropBody) 
     1703            propBodyList.add(ref _setPropBody) 
     1704            propBodyList.add(ref _getSetPropBody) 
     1705            propBody  = propBodyList[getOrSet to int] 
     1706            propBody(token, prop to !, isAbstract, curBox) 
     1707        else    # for interfaces 
     1708            if getOrSet == PropertyVariant.getOnly 
     1709                prop.makeGetPart(TokenFix.empty) 
     1710            if getOrSet == PropertyVariant.setOnly 
    17691711                prop.makeSetPart(TokenFix.empty) 
    1770             else 
     1712            else if getOrSet == PropertyVariant.getAndSet 
    17711713                prop.makeGetPart(TokenFix.empty) 
     1714                prop.makeSetPart(TokenFix.empty) 
     1715                 
    17721716        if isAbstract and not curBox inherits Class 
    17731717            .throwError('Only properties in classes can be marked abstract.') 
     1718        overload = _overloadIfNeeded(idToken, curBox, name) 
    17741719        if overload 
    17751720            assert prop 
    17761721            overload.addMember(prop to !) 
     
    17781723        else 
    17791724            return prop 
    17801725 
     1726    # parse a get only properties body 
     1727    def _getPropBody(token as IToken, prop as ProperDexer, isAbstract as bool, curBox as Box) 
     1728        _getOrSetPropBody(prop.makeGetPart(token), prop, isAbstract, curBox) 
    17811729 
     1730    # parse a set only properties body 
     1731    def _setPropBody(token as IToken, prop as ProperDexer, isAbstract as bool, curBox as Box) 
     1732        _getOrSetPropBody(prop.makeSetPart(token), prop, isAbstract, curBox) 
     1733 
     1734    # common handling for parsing body of a get or set only property 
     1735    def _getOrSetPropBody(part as AbstractMethod, prop as ProperDexer, isAbstract as bool, curBox as Box) 
     1736        if isAbstract or not curBox.canHaveStatements 
     1737            .dedent 
     1738        else 
     1739            .statementsFor(part, prop) 
     1740 
     1741    # handle parsing body for a full (get and set-able) property 
     1742    def _getSetPropBody(token, prop as ProperDexer, isAbstract as bool, curBox as Box) 
     1743        getWord = _propSubClause('GET', prop, isAbstract, curBox, ref prop.makeGetPart) 
     1744        setWord = _propSubClause('SET', prop, isAbstract, curBox, ref prop.makeSetPart) 
     1745        if not getWord and not setWord 
     1746            if isAbstract or not curBox.canHaveStatements 
     1747                prop.makeGetPart(TokenFix.empty) 
     1748                prop.makeSetPart(TokenFix.empty) 
     1749            else 
     1750                .throwError('Expecting "get" or "set" for the property.') 
     1751        .dedent 
     1752 
     1753 
     1754    # parse the get or set subclause of a full property declaration 
     1755    def _propSubClause(tknStr as String, prop as ProperDexer, isAbstract as bool, curBox as Box, makePart as MakePartSig) as IToken? 
     1756        tknWord = .optional(tknStr) 
     1757        if tknWord 
     1758            if isAbstract or not curBox.canHaveStatements 
     1759                makePart(tknWord) 
     1760            else 
     1761                .indent 
     1762                part = makePart(tknWord) 
     1763                .statementsFor(part) 
     1764        return tknWord 
     1765 
    17821766    ## 
    17831767    ## Parameter declarations 
    17841768    ## 
     
    35353519 
    35363520    def checkProperty(name as String) 
    35373521        box = .curBox 
    3538         if name==box.name 
     3522        if name == box.name 
    35393523            .throwError('Property names cannot be the same as their enclosing type.')  # TODO: list the enclosing types location 
    35403524        other = box.declForName(name) 
    3541         if other 
    3542             .throwError('There is already another class member with the name "[name]".')  # TODO: list its location and possibly what it is 
    3543         other = box.declForNameCI(name) 
    3544         if other 
    3545             .throwError('There is already another class member with the name "[other.name]". You must differentiate member names by more than just case.') 
     3525        if other  
     3526            if not other inherits ProperDexer 
     3527                .throwError('There is already another class member with the name "[name]".')  # TODO: list its location and possibly what it is 
     3528        else 
     3529            other = box.declForNameCI(name) 
     3530            if other 
     3531                .throwError('There is already another class member with the name "[other.name]". You must differentiate member names by more than just case.') 
    35463532        if name.startsWithNonLowerLetter 
    35473533            .throwError('Property names must start with lowercase letters. ([name])') 
    35483534 
    35493535    def checkStartsLowercase(identifier as String, whatName as String) 
    35503536        """ 
    3551         Makes an error if identifier does not match 'foo'. 
     3537        Makes an error if identifier is not correctly capitalised. (Starts lowercased after any leading '_') 
    35523538        whatName should be capitalized. 
    35533539        """ 
    35543540        if identifier[0] == '_' 
     
    36113597            else 
    36123598                .throwError(token, 'There is already another class member with the name "[name]".')  # TODO list its location and possibly what it is 
    36133599        else 
    3614             other = box.declForName(name)  # TODO: should be a CI there for case-insensitive 
     3600            other = box.declForNameCI(name)   
    36153601            if other 
    36163602                .throwError(token, 'There is already another class member with the name "[other.name]". You must differentiate member names by more than just case.') 
    36173603            if name[0] in _uppercaseLetters 
    3618                 .recordError(token, 'Method names must start with lowercase letters. ([name])') 
     3604                .recordError(token, 'Method and property names must start with lowercase letters. ([name])') 
    36193605 
    36203606        return overload 
    36213607 
  • Tests/820-errors/400-declarations/210-member-names-same-but-diff-case.cobra

     
    1 # .error. Cannot have members with the same name 
     1# .error. You must differentiate member names by more than just case 
    22 
    33class Program 
    44 
  • Tests/320-misc-two/450-implement-generic-IEnumerator.cobra

     
     1# very simple Generic Enumerable implementation 
     2# showing tkt:262 
     3# overloaded properties (current) 
     4class Ranger<of T> implements IEnumerable<of T>  
     5    var _start as T 
     6    var _stop as T 
     7 
     8    cue init(start as T, endSent as T) 
     9        base.init 
     10        _start = start 
     11        _stop = endSent 
     12     
     13    def getEnumerator as IEnumerator<of T> 
     14        return RangeEnumerator<of T>(_start, _stop) 
     15             
     16    def getEnumerator as System.Collections.IEnumerator 
     17        implements System.Collections.IEnumerable 
     18        return .getEnumerator 
     19             
     20class RangeEnumerator<of T> implements IEnumerator<of T> 
     21    var _first = false 
     22    var _start as T 
     23    var _stop  as T 
     24    var _currVal as T 
     25     
     26    cue init(start as T, stopVal as T) 
     27        base.init 
     28        _start = start 
     29        _stop = stopVal 
     30        _currVal = start 
     31        _first = true 
     32         
     33    def hasMoreElements as bool 
     34        return _currVal <> _stop 
     35             
     36    def nextElement 
     37        _currVal = _inc(_currVal) 
     38         
     39    def _inc(v) as dynamic 
     40        return v + 1 
     41     
     42        # 
     43        # For IEnumerator  
     44        # 
     45         
     46    def dispose 
     47        pass 
     48     
     49    def reset 
     50        _currVal = _start 
     51        _first = true 
     52                 
     53    def moveNext as bool 
     54        if not _first 
     55            .nextElement 
     56        _first = false   
     57        if .hasMoreElements 
     58            return true 
     59        return false 
     60 
     61    get current as T 
     62        return _currVal 
     63         
     64    get current as Object implements System.Collections.IEnumerator 
     65        #return _currVal 
     66        return .current 
     67             
     68class Test 
     69    def main is shared 
     70        for i in Ranger<of int>(1,10) 
     71            assert  i in [1,2,3,4,5,6,7,8,9] 
     72             
  • Tests/320-misc-two/452-overload-property.cobra

     
     1# Show overloading of a property - 1 Get only prop 
     2interface IWun 
     3    get wun as int 
     4     
     5interface IWunToo 
     6    get wun as uint8 
     7     
     8class PropOverload implements IWun, IWunToo 
     9    var _wun = 0 
     10     
     11    cue init(i as int) 
     12        base.init 
     13        _wun = i 
     14 
     15    get wun as int 
     16        return _wun 
     17     
     18    get wun as uint8 implements IWunToo 
     19        #return (_wun/2) to uint8 
     20        return (.wun/2) to uint8 
     21             
     22    def main is shared 
     23        p = PropOverload(20) 
     24        iw = p to IWun 
     25        assert iw.wun == 20 
     26        assert iw.wun.typeOf == int 
     27         
     28        iw2 = p to IWunToo 
     29        assert iw2.wun == 10 
     30        assert iw2.wun.typeOf == uint8 
     31         
     32        assert p.wun.typeOf == int # first dcl 
     33        assert (p to IWun).wun.typeOf == int 
  • Tests/320-misc-two/454-overload-property.cobra

     
     1# Show overloading of a property - 2 - full property get+set 
     2interface IWun 
     3    pro wun as int 
     4     
     5interface IWunToo 
     6    get wun as uint8 
     7     
     8class PropOverload implements IWun, IWunToo 
     9    var _wun = 0 
     10     
     11    cue init(i as int) 
     12        base.init 
     13        _wun = i 
     14 
     15    pro wun as int 
     16        get 
     17            return _wun 
     18        set 
     19            _wun = value 
     20     
     21    get wun as uint8 implements IWunToo 
     22        #return (_wun/2) to uint8 
     23        return (.wun/2) to uint8 
     24             
     25    def main is shared 
     26        p = PropOverload(20) 
     27        iw = p to IWun 
     28        assert iw.wun == 20 
     29        assert iw.wun.typeOf == int 
     30         
     31        iw2 = p to IWunToo 
     32        assert iw2.wun == 10 
     33        assert iw2.wun.typeOf == uint8 
     34         
     35        assert p.wun.typeOf == int # first dcl 
     36        assert (p to IWun).wun.typeOf == int 
     37         
     38        #set 
     39        iw.wun = 30 
     40        assert iw.wun == 30 
     41        assert iw2.wun == 15 
     42         
     43        p.wun = 40 
     44        assert p.wun == 40 
     45        assert (p to IWunToo).wun == 20