Ticket #339: nil-safe-deref.patch
File nil-safe-deref.patch, 11.6 KB (added by hopscc, 11 years ago) |
---|
-
Source/Expr.cobra
1304 1304 def setDefinition(value as INamedNode?) 1305 1305 # cannot override definition with a set, because base does not do a set 1306 1306 _definition = value 1307 # override use detection for compiler generated variables - not being set under normal checks 1308 if .isCompilerMade, _definition.isUsed = true 1309 1307 1310 1308 1311 get canBeStatement as bool is override 1309 1312 return _definition inherits Method … … 1337 1340 else 1338 1341 return nil 1339 1342 1343 pro isCompilerMade from var as bool 1344 """ flag as internally created.""" 1345 1340 1346 def _bindImp is override 1341 1347 base._bindImp 1342 1348 if _definition is nil … … 1732 1738 def _bindImp is override 1733 1739 base._bindImp 1734 1740 assert .superNode inherits DotExpr 1735 assert .binarySuperNode.op == 'DOT' 1741 assert .binarySuperNode.op == 'DOT' or .binarySuperNode.op == 'QUESTION_DOT' 1736 1742 assert .binarySuperNode.right is this 1737 1743 left = .binarySuperNode.left 1738 1744 if _definition is nil or _type is nil -
Source/BinaryOpExpr.cobra
50 50 return AssignExpr(opToken, op, left, right) 51 51 on 'DOT' 52 52 return DotExpr(opToken, op, left, right) 53 on 'QUESTION_DOT' 54 # convert nilSafe to cascaded non-nil coalesce 55 #nilSafeHelper variable : (tv0 = left) ! (tv1 = tv0.right) 56 bangToken = opToken.copy('BANG', '!') 57 serNo = IdentifierExpr(opToken).serialNum 58 tmpNameToken = opToken.copy('ID', 'tnsh_[serNo]' ) # tnsh = tmp nilsafe helper 59 leftId = IdentifierExpr(tmpNameToken) # new id to capture value of this expr tv0 60 leftId.isCompilerMade = true 61 assToken = opToken.copy('ASSIGN', '=') 62 if left inherits InverseCoalesceExpr # previous InverseCoalesce 63 prevId = (left.right to AssignExpr).left # tv1 64 dotex = DotExpr(opToken, 'DOT', prevId, right) # tv1.right 65 rhs = AssignExpr(assToken, 'ASSIGN', leftId, dotex) # tv2 = tv1.right 66 ice = InverseCoalesceExpr(bangToken, 'BANG', left, rhs) # (<prev-ice) ! (tv2 = tv1.right) 67 else 68 assign = AssignExpr(assToken, 'ASSIGN', leftId, left) #tv0 = left 69 lhs = assign 70 serNo = IdentifierExpr(opToken).serialNum # for a different serNo 71 rightId = IdentifierExpr(opToken.copy('ID', 'tnsh_[serNo]')) # tv1 = tv0.right 72 rightId.isCompilerMade = true 73 rhs = AssignExpr(assToken, 'ASSIGN', rightId, DotExpr(opToken, 'DOT', leftId, right)) 74 ice = InverseCoalesceExpr(bangToken, 'BANG', lhs, rhs) 75 return ice 53 76 on 'INHERITS' or 'IMPLEMENTS' 54 77 return InheritsExpr(opToken, op, left, right) 55 78 on 'IN' or 'NOTIN' … … 633 656 634 657 cue init(opToken as IToken, op as String, left as Expr, right as Expr) 635 658 require 636 op == 'DOT' 659 op == 'DOT' or op == 'QUESTION_DOT' 637 660 right inherits IDotRightExpr 638 661 body 639 662 base.init(opToken, op, left, right) … … 1043 1066 cue init(opToken as IToken, op as String, left as Expr, right as Expr) 1044 1067 base.init(opToken, op, left, right) 1045 1068 1069 def addMinFields 1070 base.addMinFields 1071 .addField('left.toCobraSource', .left.toCobraSource) 1072 .addField('right.toCobraSource', .right.toCobraSource) 1073 1046 1074 def _bindImp 1047 1075 base._bindImp 1048 1076 left, right = .left, .right -
Source/CobraParser.cobra
2731 2731 'LBRACKET': 80, 2732 2732 'LPAREN': 80, 2733 2733 'ARRAY_OPEN': 80, 2734 'QUESTION_DOT': 80, 2734 2735 2735 2736 'STARSTAR': 70, # right associative 2736 2737 … … 2910 2911 # support to expression. Ex: x to int Ex: x to? Shape 2911 2912 right = .typeExpr to Expr 2912 2913 getTypeExprForRightHandSide = false 2913 else if op == 'DOT'and .peek.isKeyword2914 else if (op == 'DOT' or op == 'QUESTION_DOT') and .peek.isKeyword 2914 2915 # support foo.bar where bar is a keyword. Ex: foo.this 2915 2916 right = MemberExpr(.grab) to Expr 2916 else if op == 'DOT'and _isHelpDirective(.peek)2917 else if (op == 'DOT' or op == 'QUESTION_DOT') and _isHelpDirective(.peek) 2917 2918 # support foo.@help 2918 2919 left.isHelpRequested = true 2919 2920 op = '' # cancel the creation of a new binary op expr 2920 2921 .grab 2921 2922 else 2922 2923 right = _continuedExpression(prec, opToken) 2923 if op == 'DOT'and not right inherits IDotRightExpr2924 if (op == 'DOT' or op == 'QUESTION_DOT') and not right inherits IDotRightExpr 2924 2925 if left inherits StringLit or right inherits StringLit 2925 2926 sugg = ' Use plus "+", not dot ".", for string concatenation.' 2926 2927 else … … 3310 3311 """ 3311 3312 nameToken = .idOrKeyword 3312 3313 name = nameToken.text 3313 if .opStack.count and .opStack.peek=='DOT'3314 if .opStack.count and (.opStack.peek=='DOT' or .opStack.peek=='QUESTION_DOT') 3314 3315 return MemberExpr(nameToken) 3315 3316 if .peek.which=='AS' 3316 3317 return AsExpr(.grab, nameToken, .typeId) -
Source/CobraTokenizer.cobra
239 239 r'DOUBLE_LT_EQUALS s <<=', 240 240 r'DOUBLE_GT_EQUALS s >>=', 241 241 242 r'QUESTION_DOT s ?.', 242 243 r'QUESTION_EQUALS s ?=', 243 244 r'BANG_EQUALS s !=', 244 245 ] -
Tests/900-compiler-lib/300-keywords.cobra
1 1 # this used to fail due to a bug in the KeywordSpecs class 2 2 @ref 'Test.Cobra.Compiler' 3 3 use Cobra.Compiler 4 4 5 5 class KeywordDescriptions -
Tests/320-misc-two/410-nil-safe/020-nil-safe.cobra
1 class NilSafe 2 var co as Company? 3 var co1 as Company? 4 var ccnil as Object? 5 6 def main is shared 7 ns = NilSafe() 8 co = Company() 9 co.name ='H Die and Tool' 10 ns.co = co 11 12 assert ns.co.name == co.name 13 name = ns.co ! ns.co.name ? 'x' 14 assert name == co.name 15 16 name = ns.co1?.name ? 'no-Name?' 17 # name = (t=ns.co1) : t.name ) 18 assert name == 'no-Name?' 19 20 #name = (t=ns.co) ! t.name ? 'x' 21 #assert name == co.name 22 23 ns1 as NilSafe? 24 name = ((t0=ns1) ! (t1=t0.co1)) ! t1.name ? 'no.Name?' 25 assert name == 'no.Name?' 26 name = ns1?.co1?.name ? 'no.Name?' 27 assert name == 'no.Name?' 28 29 def x 30 pass 31 32 invariant .ccnil == nil 33 34 class Company 35 var name as String? 36 37 -
Tests/320-misc-two/410-nil-safe/040-nil-safe-non-idempotent.cobra
1 # non idempotent: calls changing return values on each call 2 class NilSafe 3 var co as Company? 4 var co1 as Company? 5 6 def main is shared 7 ns = NilSafe() 8 co = Company() 9 co.name ='Hops Die and Tool' 10 ns.co = co 11 12 13 #print ns.co.chkCo ? 'chkFail' 14 #print ns.co.chkCo ? 'chkFail' 15 ns2 = ns to ? 16 r = ns2 ! ns2.co ! ns2.co.chkCo ? 'chkFail' 17 assert r == 'OK' 18 r = ns2 ! ns2.co ! ns2.co.chkCo ? 'chkFail' 19 assert r == 'chkFail' 20 21 ns2 =NilSafe() 22 n = ns2.coCalc.name 23 assert n == 'Synth1' 24 n = ns2.coCalc.name 25 assert n == 'Synth2' 26 # ns2?.coCalc?.name 27 #n1 = ns2 ! ns2.coCalc ! ns2.coCalc.name 28 n1 = (t=ns2) ! (t1=t.coCalc) ! t1.name 29 assert n1 == 'Synth3' 30 ## ns2.coCalc?.name 31 n1 = ns2 ! (u=ns2.coCalc) ! u.name 32 assert n1 == 'Synth4' 33 34 n1 = ns2?.coCalc?.name 35 assert n1 == 'Synth5' 36 #print n1 37 n1 = ns2.coCalc?.name 38 assert n1 == 'Synth6' 39 #print n1 40 41 def coCalc as Company? 42 return .co1 ? Company(dname='Synth[Company.cnt]') 43 44 class Company 45 shared 46 var cnt = 0 47 var name as String? ='' 48 var n =0 49 50 set dname from name 51 52 cue init 53 base .init 54 Company.cnt += 1 55 56 def chkCo as String? 57 n = .n 58 .n += 1 59 if n ==0, return 'OK' 60 return nil 61 62 def chkN as int 63 n, .n = .n, .n+1 64 return n -
Tests/320-misc-two/410-nil-safe/030-many-nil-safe.cobra
1 class NilSafe 2 var co as Company? 3 var co1 as Company? 4 5 def main is shared 6 ns = NilSafe() 7 co = Company() 8 co.name ='Die and Tool' 9 co.subsid = Company() 10 co.subsid.name = 'Just Tool' 11 ns.co = co 12 13 assert ns.co.name == co.name 14 name = ns.co1?.name ? 'X?' 15 assert name == 'X?' 16 17 n2= ns.co1 ! ns.co1.name ? 'X!' 18 assert n2 == 'X!' 19 20 ns1 as NilSafe? 21 name = ns1?.co1?.name ? 'X?' 22 assert name == 'X?' 23 name = ns.co?.name ? 'X' 24 assert name == co.name 25 26 ssname = ns.co?.subsid?.name ? 'X' 27 assert ssname == 'Just Tool' 28 ns.co?.subsid.subsid =Company() 29 ns.co.subsid.subsid.name= 'Justy' 30 ns1 = ns 31 name = ns1?.co?.subsid?.subsid?.name ? 'X' 32 assert name == 'Justy' 33 34 ns1.co.subsid.subsid.name = nil 35 name = ns1?.co?.subsid?.subsid?.name ? 'X' 36 assert name == 'X' 37 ns1.co.subsid.subsid = nil 38 name = ns1?.co?.subsid?.subsid?.name ? 'X' 39 assert name == 'X' 40 41 coX = ns.co?.subsid?.subsid ? co 42 assert coX.name == 'Die and Tool' 43 44 coX1 = ns1?.co?.subsid?.subsid ? co 45 assert (coX1 to Company).name == 'Die and Tool' 46 47 class Company 48 var name as String? 49 var subsid as Company? 50 -
Tests/320-misc-two/410-nil-safe/010-simple-nil-safe.cobra
1 class NilSafe 2 var co as Company? 3 var co1 as Company? 4 var ccnil as Object? 5 6 def main is shared 7 ns = NilSafe() 8 co = Company() 9 co.name ='H Die and Tool' 10 ns.co = co 11 12 assert ns.co.name == co.name 13 name = ns.co ! ns.co.name ? 'x' 14 assert name == co.name 15 16 name = ns.co1?.name ? 'no-Name?' 17 assert name == 'no-Name?' 18 19 n2= ns.co1 ! ns.co1.name ? 'noName!' 20 assert n2 == 'noName!' 21 22 ns1 as NilSafe? 23 name = ns1?.co1?.name ? 'no.Name?' 24 assert name == 'no.Name?' 25 26 n2 = ns1 ! ns1.co1 ! ns.co1.name ? 'no.Name!' 27 assert n2 == 'no.Name!' 28 29 ns1 = NilSafe() 30 name = ns1?.co1?.name ? 'no.Name-co?' 31 assert name == 'no.Name-co?' 32 33 n2 = ns1 ! ns1.co1 ! ns1.co1.name ? 'no.Name-co!' 34 assert n2 == 'no.Name-co!' 35 36 ns1.co1 = Company() 37 name = ns1?.co1?.name ? 'no.Name-co-name?' 38 assert name == 'no.Name-co-name?' 39 40 n2 = ns1 ! ns1.co1 ! ns1.co1.name ? 'no.Name-co-name!' 41 assert n2 == 'no.Name-co-name!' 42 43 ns1.co1.name = 'xx' 44 name = ns1?.co1?.name ? 'no.Name-co-name?' 45 assert name == 'xx' 46 47 def x 48 pass 49 50 invariant .ccnil == nil 51 52 class Company 53 var name as String? 54 55