Ticket #102: properties-init.patch
File properties-init.patch, 8.8 KB (added by hopscc, 16 years ago) |
---|
-
Source/Members.cobra
443 443 is partial 444 444 inherits BoxField 445 445 """ 446 A constan st such as:446 A constant such as: 447 447 const PI = 3.14 448 448 449 449 In practice, when developing libraries, a read-only var is more practical than a constant, … … 519 519 else 520 520 return false 521 521 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 522 529 ## INamedNode 523 530 524 531 get typeForReceiver as IType is override -
Source/CobraParser.cobra
269 269 while .optional('EOL'), pass 270 270 .expect('DEDENT') 271 271 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 shared277 pass278 Example 2:279 def main280 is shared281 pass282 In either case, returns the list of "is" names or nil if there were none.283 """284 if .peek.which=='IS'285 isNames = .isDeclNames286 .expect('INDENT')287 return isNames288 else289 if .optionalIndent290 return .isDeclNames291 else292 .expect('INDENT')293 return List<of String>()294 295 272 def optionalIndent as IToken? 296 273 """ 297 274 Consumes and warns about COLON not being necessary. … … 593 570 ['private', 'shared'] 594 571 Errors: 595 572 TODO 596 Used by: classDecl, interfaceDecl, enumDecl , indentIsDeclNames573 Used by: classDecl, interfaceDecl, enumDecl 597 574 """ 598 575 if _validIsNames is nil 599 576 _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 600 588 names = List<of String>(_isNamesStack) 589 hasIsNames = false 601 590 if .optional('IS') is nil 602 591 return names 592 hasIsNames = true 603 593 while true 604 594 what = .grab.text 605 595 if what in _validIsNames … … 613 603 if .peek.text in _validIsNames 614 604 .throwError(.peek, 'Multiple access modifiers should be separated by commas such as "[what], [.peek.text]".') 615 605 break 616 .endOfLine617 # TODO: error on virtual and override618 # TODO: error on virtual and shared619 # TODO: error if 2 or more of 'public', 'protected', 'private', 'internal'620 606 return names 607 621 608 622 609 def declGenericParams(token as IToken) as List<of GenericParam> 623 610 """ … … 1397 1384 else 1398 1385 varName = .expect('ID').text 1399 1386 declVarType = if(.optional('AS'), .typeId, nil) 1400 if declVarType1401 varDef = BoxVar(token, .curBox, varName, declVarType, List<of String>(_isNamesStack), nil, nil, 'Automatic backing var for property "[name]".')1402 .curBox.addDecl(varDef)1403 else1404 possibleVarDef = .curBox.declForName(varName)1405 if possibleVarDef is nil1406 .throwError('There is no variable named "[varName]" to match the property "[name]".')1407 if possibleVarDef inherits BoxVar1408 varDef = possibleVarDef1409 else1410 .throwError('A property can only cover for variables. [varName] is a [possibleVarDef]') # TODO: .englishName?1411 1387 if .curBox inherits Interface 1412 1388 .throwError('Cannot use the "from" form of a property inside an interface declaration.') 1413 1389 if .peek.which == 'IS' 1414 isNames = .isDeclNames1415 hasIsNames = true1416 indent = .optional('INDENT')1417 else1418 indent = .optionalIndent1419 if indent1390 hasIsNames = false 1391 isNames = _isDeclNamesNoEOL(out hasIsNames) 1392 if .optional('ASSIGN') 1393 initExpr = .expression to ? 1394 .endOfLine 1395 if .optional('INDENT') 1420 1396 if not hasIsNames, isNames = .isDeclNames 1421 1397 attribs = .hasAttribs 1422 1398 docString = .docString … … 1425 1401 if not hasIsNames, isNames = List<of String>(_isNamesStack) 1426 1402 attribs = AttributeList() 1427 1403 docString = '' 1404 varDef = _genVarDef(declVarType, token, name, varName, initExpr) 1428 1405 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 1430 1425 def declareGetOnlyProperty as ProperDexer? 1431 1426 return _declareGetOrSetOnlyProperty(0) 1432 1427 -
Tests/120-classes/505-properties-from-init-error.cobra
1 # Properties init backing variable 2 class 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 2 class 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
1 class 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
11 11 12 12 * Support constant declarations on class instance variables. ticket:122 13 13 14 * Allow property declarations to set an initial value (on property backing 15 variable). ticket:102 14 16 ================================================================================ 15 17 Library 16 18 ================================================================================