Ticket #262: property-overload.patch
File property-overload.patch, 20.6 KB (added by hopscc, 14 years ago) |
---|
-
Source/Members.cobra
1238 1238 var _coverAccess as String? 1239 1239 var _returnType as IType? 1240 1240 var _returnTypeNode as ITypeProxy? 1241 1242 var _implementsTypeNode as ITypeProxy? 1243 var _implementsType as IType? 1241 1244 1242 1245 cue init(token as IToken, idToken as IToken, box as Box, name as String, isNames as String*, attribs as AttributeList, docString as String?) 1243 1246 base.init(token, idToken, box, name, isNames, attribs, docString) … … 1266 1269 if _coverVar, .addField('coverVar', _coverVar) 1267 1270 if _returnType, .addField('returnType', _returnType) 1268 1271 else, .addField('returnTypeNode', _returnTypeNode) 1272 .addField('implementsType', _implementsType) 1269 1273 1270 1274 def addSubFields is override 1271 1275 base.addSubFields 1276 if _implementsTypeNode 1277 .addField('implementsTypeNode', _implementsTypeNode) 1272 1278 if _getPart, .addField('getPart', _getPart) 1273 1279 if _setPart, .addField('setPart', _setPart) 1274 1280 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 1275 1288 get returnType from var 1276 1289 1277 1290 get returnTypeNode from var … … 1287 1300 get setPart from var 1288 1301 1289 1302 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') 1291 1309 1292 1310 def mergedIntoPartialBox(newBox as Box) 1293 1311 base.mergedIntoPartialBox(newBox) … … 1330 1348 1331 1349 def _bindImp is override 1332 1350 base._bindImp 1351 if _implementsTypeNode 1352 _implementsType = _implementsTypeNode.realType 1353 # TODO: make sure the type is among the interfaces of the box 1333 1354 if _getPart, _getPart.bindImp 1334 1355 if _setPart, _setPart.bindImp 1335 1356 -
Source/Expr.cobra
1565 1565 _definition = member 1566 1566 didResolveOverload = true 1567 1567 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 1568 1574 if not didResolveOverload 1569 1575 .throwError('Could not find an overload for "[.name]" with zero arguments.') 1570 1576 else if defn inherits AbstractMethod -
Source/BackEndClr/SharpGenerator.cobra
1914 1914 .writeSharpNotNull(sw) 1915 1915 .writeSharpAttribs(sw) 1916 1916 .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]') 1918 1921 .writeSharpBody(sw) 1919 1922 getPart = .getPart 1920 1923 if getPart -
Source/Boxes.cobra
1046 1046 other = _declsByName[decl.name] 1047 1047 if other inherits MemberOverload 1048 1048 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) 1051 1051 .registerOverload(overload to !) 1052 1052 else 1053 1053 throw FallThroughException(other) -
Source/CobraParser.cobra
1531 1531 .dedent 1532 1532 1533 1533 methodSig = MethodSig(wordToken, opener, curContainer to IParentSpace, name, params, returnType, isNames, attribs, docString) 1534 1535 1534 return methodSig 1536 1535 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 1537 1546 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) 1546 1548 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) 1640 1551 1552 def declareSetOnlyProperty as ProperDexer? 1553 return _declareProperty(PropertyVariant.setOnly) 1554 1641 1555 def declarePropertyFrom(token as IToken, idToken as IToken, name as String, coverWhat as String) as Property 1642 1556 require coverWhat.isOneOf('get.set.getset.') 1643 1557 if .optional('VAR') … … 1691 1605 .throwError('Property backing variable "[varName]" has already been initialized.') # include line# of backing variable decl 1692 1606 return varDef 1693 1607 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? 1701 1613 """ 1702 1614 Example source 1615 pro age as int 1616 get 1617 return _age 1618 set 1619 assert value>0 1620 _age = value 1621 1703 1622 get meaningOfLife as int 1704 1623 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. 1705 1634 """ 1706 require getOrSet in [ 0, 1]1635 require getOrSet in [PropertyVariant.getOnly, PropertyVariant.setOnly, PropertyVariant.getAndSet] 1707 1636 curBox = .curBox 1708 1637 prop as ProperDexer? 1709 token = .expect(if(getOrSet, 'SET', 'GET')) 1638 tokenStr = ['GET', 'SET', 'PRO'][getOrSet to int] 1639 token = .expect(tokenStr) 1710 1640 overload as MemberOverload? 1711 if .optional('LBRACKET') 1641 if .optional('LBRACKET') # Indexer 1712 1642 idToken = .last to ! 1713 1643 params = .paramDecls(true, 'RBRACKET') 1714 1644 name = r'[]' 1715 overload = _overloadIfNeeded(idToken, curBox, name)1645 #overload = _overloadIfNeeded(idToken, curBox, name) 1716 1646 else 1717 1647 idToken = .idOrKeyword 1718 1648 name = idToken.text 1719 1649 .checkProperty(name) 1720 1650 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) 1722 1653 params = List<of Param>() 1723 1654 if .optional('AS') 1724 1655 returnType = .typeId to ITypeProxy 1725 1656 else 1726 1657 returnType = _typeProvider.defaultType 1727 # TODO: implements? 1658 implementsType as ITypeProxy? 1659 if .optional('IMPLEMENTS') 1660 implementsType = .typeId 1728 1661 hasIsNames = false 1729 1662 isAbstract = false 1730 1663 if .peek.which == 'IS' … … 1753 1686 prop = Indexer(token, idToken, curBox, name, params, returnType, isNames, attribs, docString) 1754 1687 else 1755 1688 prop = Property(token, idToken, curBox, name, returnType, isNames, attribs, docString) 1689 if implementsType 1690 prop.implementsTypeNode = implementsType 1756 1691 if indent 1757 1692 if .peek.which=='TEST' 1758 1693 if curBox inherits Interface 1759 1694 _warning(.peek, 'Interface `test` sections are parsed, but ignored. In the future, classes will acquire the tests of the interfaces they implement.') 1760 1695 # TODO: what about abstract? 1761 1696 .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 1769 1711 prop.makeSetPart(TokenFix.empty) 1770 else 1712 else if getOrSet == PropertyVariant.getAndSet 1771 1713 prop.makeGetPart(TokenFix.empty) 1714 prop.makeSetPart(TokenFix.empty) 1715 1772 1716 if isAbstract and not curBox inherits Class 1773 1717 .throwError('Only properties in classes can be marked abstract.') 1718 overload = _overloadIfNeeded(idToken, curBox, name) 1774 1719 if overload 1775 1720 assert prop 1776 1721 overload.addMember(prop to !) … … 1778 1723 else 1779 1724 return prop 1780 1725 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) 1781 1729 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 1782 1766 ## 1783 1767 ## Parameter declarations 1784 1768 ## … … 3535 3519 3536 3520 def checkProperty(name as String) 3537 3521 box = .curBox 3538 if name ==box.name3522 if name == box.name 3539 3523 .throwError('Property names cannot be the same as their enclosing type.') # TODO: list the enclosing types location 3540 3524 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.') 3546 3532 if name.startsWithNonLowerLetter 3547 3533 .throwError('Property names must start with lowercase letters. ([name])') 3548 3534 3549 3535 def checkStartsLowercase(identifier as String, whatName as String) 3550 3536 """ 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 '_') 3552 3538 whatName should be capitalized. 3553 3539 """ 3554 3540 if identifier[0] == '_' … … 3611 3597 else 3612 3598 .throwError(token, 'There is already another class member with the name "[name]".') # TODO list its location and possibly what it is 3613 3599 else 3614 other = box.declForName (name) # TODO: should be a CI there for case-insensitive3600 other = box.declForNameCI(name) 3615 3601 if other 3616 3602 .throwError(token, 'There is already another class member with the name "[other.name]". You must differentiate member names by more than just case.') 3617 3603 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])') 3619 3605 3620 3606 return overload 3621 3607 -
Tests/820-errors/400-declarations/210-member-names-same-but-diff-case.cobra
1 # .error. Cannot have members with the same name1 # .error. You must differentiate member names by more than just case 2 2 3 3 class Program 4 4 -
Tests/320-misc-two/450-implement-generic-IEnumerator.cobra
1 # very simple Generic Enumerable implementation 2 # showing tkt:262 3 # overloaded properties (current) 4 class 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 20 class 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 68 class 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 2 interface IWun 3 get wun as int 4 5 interface IWunToo 6 get wun as uint8 7 8 class 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 2 interface IWun 3 pro wun as int 4 5 interface IWunToo 6 get wun as uint8 7 8 class 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