Wiki

Ticket #102: properties-init.patch

File properties-init.patch, 8.8 KB (added by hopscc, 16 years ago)
  • Source/Members.cobra

     
    443443    is partial 
    444444    inherits BoxField 
    445445    """ 
    446     A constanst such as: 
     446    A constant such as: 
    447447        const PI = 3.14 
    448448     
    449449    In practice, when developing libraries, a read-only var is more practical than a constant, 
     
    519519        else 
    520520            return false 
    521521 
     522    # used in property declaration when providing an initial value for an existing backing var 
     523    def setInitExpr(initExpr as Expr) as bool 
     524        if _initExpr 
     525            return false 
     526        _initExpr = initExpr 
     527        return true  
     528 
    522529    ## INamedNode 
    523530 
    524531    get typeForReceiver as IType is override 
  • Source/CobraParser.cobra

     
    269269        while .optional('EOL'), pass 
    270270        .expect('DEDENT') 
    271271 
    272     def indentIsDeclNames as List<of String> 
    273         """ 
    274         Parses indentation followed by "is" names, or "is" names followed by indentation. 
    275         Example 1: 
    276             def main is shared 
    277                 pass 
    278         Example 2: 
    279             def main 
    280                 is shared 
    281                 pass 
    282         In either case, returns the list of "is" names or nil if there were none. 
    283         """ 
    284         if .peek.which=='IS' 
    285             isNames = .isDeclNames 
    286             .expect('INDENT') 
    287             return isNames 
    288         else 
    289             if .optionalIndent 
    290                 return .isDeclNames 
    291             else 
    292                 .expect('INDENT') 
    293                 return List<of String>() 
    294  
    295272    def optionalIndent as IToken? 
    296273        """ 
    297274        Consumes and warns about COLON not being necessary. 
     
    593570            ['private', 'shared'] 
    594571        Errors: 
    595572            TODO 
    596         Used by: classDecl, interfaceDecl, enumDecl, indentIsDeclNames 
     573        Used by: classDecl, interfaceDecl, enumDecl 
    597574        """ 
    598575        if _validIsNames is nil 
    599576            _validIsNames = ['fake', 'extern', 'shared', 'virtual', 'nonvirtual', 'override', 'new', 'public', 'protected', 'private', 'internal', 'abstract', 'partial'] 
     577        hasIsNames = false 
     578        names = _isDeclNamesNoEOL(out hasIsNames) 
     579        if hasIsNames, .endOfLine 
     580        # TODO: error on virtual and override 
     581        # TODO: error on virtual and shared 
     582        # TODO: error if 2 or more of 'public', 'protected', 'private', 'internal' 
     583        return names 
     584         
     585    def _isDeclNamesNoEOL(hasIsNames as out bool) as List<of String> 
     586        """ Parse for possible stream of isNames without terminating EOL """ 
     587        require _validIsNames is not nil 
    600588        names = List<of String>(_isNamesStack) 
     589        hasIsNames = false 
    601590        if .optional('IS') is nil 
    602591            return names 
     592        hasIsNames = true 
    603593        while true 
    604594            what = .grab.text 
    605595            if what in _validIsNames 
     
    613603                if .peek.text in _validIsNames 
    614604                    .throwError(.peek, 'Multiple access modifiers should be separated by commas such as "[what], [.peek.text]".') 
    615605                break 
    616         .endOfLine 
    617         # TODO: error on virtual and override 
    618         # TODO: error on virtual and shared 
    619         # TODO: error if 2 or more of 'public', 'protected', 'private', 'internal' 
    620606        return names 
     607         
    621608 
    622609    def declGenericParams(token as IToken) as List<of GenericParam> 
    623610        """ 
     
    13971384        else 
    13981385            varName = .expect('ID').text 
    13991386        declVarType = if(.optional('AS'), .typeId, nil) 
    1400         if declVarType 
    1401             varDef = BoxVar(token, .curBox, varName, declVarType, List<of String>(_isNamesStack), nil, nil, 'Automatic backing var for property "[name]".') 
    1402             .curBox.addDecl(varDef) 
    1403         else 
    1404             possibleVarDef = .curBox.declForName(varName) 
    1405             if possibleVarDef is nil 
    1406                 .throwError('There is no variable named "[varName]" to match the property "[name]".') 
    1407             if possibleVarDef inherits BoxVar 
    1408                 varDef = possibleVarDef 
    1409             else 
    1410                 .throwError('A property can only cover for variables. [varName] is a [possibleVarDef]')  # TODO: .englishName? 
    14111387        if .curBox inherits Interface 
    14121388            .throwError('Cannot use the "from" form of a property inside an interface declaration.') 
    14131389        if .peek.which == 'IS' 
    1414             isNames = .isDeclNames 
    1415             hasIsNames = true 
    1416             indent = .optional('INDENT') 
    1417         else 
    1418             indent = .optionalIndent         
    1419         if indent 
     1390            hasIsNames = false 
     1391            isNames = _isDeclNamesNoEOL(out hasIsNames) 
     1392        if .optional('ASSIGN') 
     1393            initExpr = .expression to ? 
     1394        .endOfLine 
     1395        if .optional('INDENT') 
    14201396            if not hasIsNames, isNames = .isDeclNames 
    14211397            attribs = .hasAttribs 
    14221398            docString = .docString 
     
    14251401            if not hasIsNames, isNames = List<of String>(_isNamesStack) 
    14261402            attribs = AttributeList() 
    14271403            docString = '' 
     1404        varDef = _genVarDef(declVarType, token, name, varName, initExpr) 
    14281405        return Property(token, .curBox, name, isNames, attribs, varDef, coverWhat, docString) 
    1429  
     1406         
     1407    def _genVarDef(declVarType as ITypeProxy?, token as IToken, name as String, varName as String, initExpr as Expr?) as BoxVar 
     1408        """ Find existing backing variable for property or make one and return it."""  
     1409        possibleVarDef = .curBox.declForName(varName) 
     1410        if not possibleVarDef 
     1411            if not initExpr and not declVarType 
     1412                .throwError('There is no variable named "[varName]" to match the property "[name]".') 
     1413            varDef = BoxVar(token, .curBox, varName, declVarType, List<of String>(_isNamesStack), initExpr, nil, 'Automatic backing var for property "[name]".') 
     1414            .curBox.addDecl(varDef) 
     1415            return varDef 
     1416                 
     1417        if  possibleVarDef inherits BoxVar 
     1418            varDef = possibleVarDef 
     1419        else 
     1420            .throwError('A property can only cover for variables. [varName] is a [possibleVarDef]')  # TODO: .englishName? 
     1421        if initExpr and not varDef.setInitExpr(initExpr to !)    
     1422            .throwError('Property backing variable "[varName]" has already been initialised') # include line# of backing variable decl 
     1423        return varDef 
     1424             
    14301425    def declareGetOnlyProperty as ProperDexer? 
    14311426        return _declareGetOrSetOnlyProperty(0) 
    14321427 
  • Tests/120-classes/505-properties-from-init-error.cobra

     
     1# Properties init backing variable 
     2class PropInit 
     3 
     4    var _x as int = 22 
     5    get x from var = 95   
     6                        # .error. already been initialised 
     7    def main is shared 
     8        pass 
  • Tests/120-classes/505-properties-from-init-1.cobra

     
     1# Properties implicitly create and init backing variable 
     2class PropInit 
     3 
     4    var _x as int 
     5    var _y = 99 
     6    var _y1 = 99 
     7     
     8    # existing backing var 
     9    get x from var = 90  
     10    get y1 from var as int8  # type is redundant as set in backing var so ignored 
     11     
     12    # implicitly generate and init backing var 
     13    get z0 from var as int 
     14    get z from var as int = 100  # explicitly set type and init 
     15    get z1 from var as int is protected # explicitly set type and modifier 
     16    get z2 from var as int is protected = 101  # type, mod + init expr 
     17    get z3 from var = 103  # infer type fm init expr 
     18 
     19    def main is shared 
     20        x = PropInit() 
     21        assert x.x == 90 
     22        assert x.y1 == 99 
     23         
     24        assert x.z0 == 0 
     25         
     26        assert x.z == 100    
     27        assert x.z1 == 0 # not initted 
     28        assert x.z2 == 101 
     29        assert x.z3 == 103 
  • Tests/120-classes/505-properties-from-init.cobra

     
     1class Point 
     2 
     3    def init 
     4        _x += 1 
     5        __y += 1 
     6 
     7    get x from var as int = 100   # typical property with matching var backing 
     8     
     9    # test explicit naming of the var.  
     10    # note that __y will be private  
     11    get y from __y = 101 
     12     
     13    pro z from var = 201 
     14 
     15    set z0 from var = 300 
     16     
     17    def moveBy(dx as int, dy as int) 
     18        _x += dx 
     19        __y += dy 
     20     
     21    def chk 
     22        assert _x == 101 
     23        assert .x == _x 
     24     
     25        assert __y == 102 
     26        assert .y == __y 
     27     
     28        assert _z == 222 
     29        assert .z == _z 
     30         
     31        assert _z0 == 300 
     32         
     33    def main is shared   
     34        p = Point() 
     35        assert p.x == 101 
     36        assert p.y == 102 
     37         
     38        assert p.z == 201 
     39        p.z = 222 
     40        assert p.z == 222 
     41        p.chk 
     42         
  • Developer/IntermediateReleaseNotes.text

     
    1111 
    1212* Support constant declarations on class instance variables. ticket:122 
    1313 
     14* Allow property declarations to set an initial value (on property backing  
     15  variable). ticket:102 
    1416================================================================================ 
    1517Library 
    1618================================================================================