Wiki

Ticket #339: nil-safe-deref.patch

File nil-safe-deref.patch, 11.6 KB (added by hopscc, 4 years ago)
  • Source/Expr.cobra

     
    13041304    def setDefinition(value as INamedNode?) 
    13051305        # cannot override definition with a set, because base does not do a set 
    13061306        _definition = value 
     1307        # override use detection for compiler generated variables - not being set under normal checks 
     1308        if .isCompilerMade, _definition.isUsed = true 
     1309             
    13071310 
    13081311    get canBeStatement as bool is override 
    13091312        return _definition inherits Method 
     
    13371340        else 
    13381341            return nil 
    13391342 
     1343    pro isCompilerMade from var as bool 
     1344        """ flag as internally created."""       
     1345         
    13401346    def _bindImp is override 
    13411347        base._bindImp 
    13421348        if _definition is nil 
     
    17321738    def _bindImp is override 
    17331739        base._bindImp 
    17341740        assert .superNode inherits DotExpr 
    1735         assert .binarySuperNode.op == 'DOT' 
     1741        assert .binarySuperNode.op == 'DOT' or .binarySuperNode.op == 'QUESTION_DOT' 
    17361742        assert .binarySuperNode.right is this 
    17371743        left = .binarySuperNode.left 
    17381744        if _definition is nil or _type is nil 
  • Source/BinaryOpExpr.cobra

     
    5050                    return AssignExpr(opToken, op, left, right) 
    5151                on 'DOT' 
    5252                    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 
    5376                on 'INHERITS' or 'IMPLEMENTS' 
    5477                    return InheritsExpr(opToken, op, left, right) 
    5578                on 'IN' or 'NOTIN' 
     
    633656 
    634657    cue init(opToken as IToken, op as String, left as Expr, right as Expr) 
    635658        require 
    636             op == 'DOT' 
     659            op == 'DOT' or op == 'QUESTION_DOT' 
    637660            right inherits IDotRightExpr  
    638661        body 
    639662            base.init(opToken, op, left, right) 
     
    10431066    cue init(opToken as IToken, op as String, left as Expr, right as Expr) 
    10441067        base.init(opToken, op, left, right) 
    10451068 
     1069    def addMinFields 
     1070        base.addMinFields 
     1071        .addField('left.toCobraSource', .left.toCobraSource) 
     1072        .addField('right.toCobraSource', .right.toCobraSource) 
     1073 
    10461074    def _bindImp 
    10471075        base._bindImp 
    10481076        left, right = .left, .right 
  • Source/CobraParser.cobra

     
    27312731            'LBRACKET':         80, 
    27322732            'LPAREN':           80, 
    27332733            'ARRAY_OPEN':       80, 
     2734            'QUESTION_DOT':     80, 
    27342735 
    27352736            'STARSTAR':         70,  # right associative 
    27362737 
     
    29102911                        # support to expression. Ex: x to int  Ex: x to? Shape 
    29112912                        right = .typeExpr to Expr 
    29122913                        getTypeExprForRightHandSide = false 
    2913                     else if op == 'DOT' and .peek.isKeyword 
     2914                    else if (op == 'DOT' or op == 'QUESTION_DOT') and .peek.isKeyword 
    29142915                        # support foo.bar where bar is a keyword. Ex: foo.this 
    29152916                        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) 
    29172918                        # support foo.@help 
    29182919                        left.isHelpRequested = true 
    29192920                        op = ''  # cancel the creation of a new binary op expr 
    29202921                        .grab 
    29212922                    else 
    29222923                        right = _continuedExpression(prec, opToken) 
    2923                     if op == 'DOT' and not right inherits IDotRightExpr 
     2924                    if (op == 'DOT' or op == 'QUESTION_DOT') and not right inherits IDotRightExpr 
    29242925                        if left inherits StringLit or right inherits StringLit 
    29252926                            sugg = ' Use plus "+", not dot ".", for string concatenation.' 
    29262927                        else 
     
    33103311        """ 
    33113312        nameToken = .idOrKeyword 
    33123313        name = nameToken.text 
    3313         if .opStack.count and .opStack.peek=='DOT' 
     3314        if .opStack.count and (.opStack.peek=='DOT' or .opStack.peek=='QUESTION_DOT') 
    33143315            return MemberExpr(nameToken) 
    33153316        if .peek.which=='AS' 
    33163317            return AsExpr(.grab, nameToken, .typeId) 
  • Source/CobraTokenizer.cobra

     
    239239            r'DOUBLE_LT_EQUALS      s   <<=', 
    240240            r'DOUBLE_GT_EQUALS      s   >>=', 
    241241 
     242            r'QUESTION_DOT      s   ?.', 
    242243            r'QUESTION_EQUALS   s   ?=', 
    243244            r'BANG_EQUALS       s   !=', 
    244245        ] 
  • Tests/900-compiler-lib/300-keywords.cobra

     
    11# this used to fail due to a bug in the KeywordSpecs class 
    2  
     2@ref 'Test.Cobra.Compiler' 
    33use Cobra.Compiler 
    44 
    55class KeywordDescriptions 
  • Tests/320-misc-two/410-nil-safe/020-nil-safe.cobra

     
     1class 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     
     34class 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 
     2class 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 
     44class 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

     
     1class 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         
     47class Company 
     48    var name as String? 
     49    var subsid as Company? 
     50     
  • Tests/320-misc-two/410-nil-safe/010-simple-nil-safe.cobra

     
     1class 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     
     52class Company 
     53    var name as String? 
     54     
     55