Wiki

Ticket #25: extIndexing.patch

File extIndexing.patch, 19.9 KB (added by hopscc, 16 years ago)

extended Index patch with fixed line endings

  • Source/CobraLang.cs

     
    10871087        } 
    10881088    } 
    10891089 
     1090    static private int ProcessIndexArgs(int count, int? idx) { 
     1091        if (idx==null) 
     1092            idx = 0; 
     1093        else if (idx < 0) { 
     1094            idx += count; 
     1095            //run off front should throw bounds exc 
     1096            //if (idx < 0) { 
     1097            //    idx = 0; 
     1098            //} 
     1099        } 
     1100        return (int) idx; 
     1101    } 
     1102     
     1103    static public char GetExtIndexed(string s, int? idx) { 
     1104        //Console.WriteLine("GetIndex String"); 
     1105        if (s==null) 
     1106            throw new NullReferenceException("Cannot index null."); 
     1107            int i = ProcessIndexArgs(s.Length, idx); 
     1108        return s[i]; 
     1109    } 
     1110 
     1111    static public T GetExtIndexed<T>(T[] array, int? idx) { 
     1112        //Console.WriteLine("GetIndex Array"); 
     1113        if (array==null) 
     1114            throw new NullReferenceException("Cannot index null array."); 
     1115        int i = ProcessIndexArgs(array.Length, idx); 
     1116        return array[i];  // array.GetValue(i); 
     1117    } 
     1118     
     1119    static public object GetExtIndexed(System.Collections.IList list, int? idx) { 
     1120        if (list==null) 
     1121            throw new NullReferenceException("Cannot slice null."); 
     1122        int i = ProcessIndexArgs(list.Count, idx); 
     1123        return list[i]; 
     1124    } 
     1125 
     1126    static public T GetExtIndexed<T>(IList<T> list, int? idx) { 
     1127        //Console.WriteLine("GetIndex IList<T>"); 
     1128        if (list==null) 
     1129            throw new NullReferenceException("Cannot index null IList<T>."); 
     1130        int i = ProcessIndexArgs(list.Count, idx); 
     1131        return list[i]; 
     1132    } 
     1133 
     1134    static public T GetExtIndexed<T>(List<T> list, int? idx) { 
     1135        //Console.WriteLine("GetIndex List<T>"); 
     1136        if (list==null) 
     1137            throw new NullReferenceException("Cannot slice null List."); 
     1138        int i = ProcessIndexArgs(list.Count, idx); 
     1139        return list[i]; 
     1140    } 
     1141 
     1142/*  hops: Is this needed (for dynamic sequences) ?? 
     1143        static public object GetExtIndexed(Object obj, int? idx) { 
     1144        // this is for when obj is type `dynamic` 
     1145        if (obj==null) 
     1146            throw new NullReferenceException("Cannot Index null."); 
     1147        if (obj is String) 
     1148                return GetExtIndexed((String)obj, idx); 
     1149        else if (obj is ArrayList) 
     1150            return GetExtIndexed((ArrayList)obj, idx); 
     1151        else if (obj is IList) 
     1152            return GetExtIndexed((IList)obj, idx); 
     1153        else 
     1154            throw new Exception(String.Format("GetExtIndexed unhandled Type {0}", obj)); 
     1155    } 
     1156*/         
     1157 
    10901158    static public object GetIndexerValue(Object obj, params object[] args) { 
    10911159        if (obj==null) 
    10921160            throw new ArgumentNullException("obj"); 
  • Source/Expr.cobra

     
    13931393            _type = _definition.resultType 
    13941394            assert _type 
    13951395 
    1396     def toCobraSource as String is override 
     1396    def toCobraSource(startDelim as String, stopDelim as String) as String 
    13971397        sb = StringBuilder() 
    13981398        sb.append(_target.toCobraSource) 
    1399         sb.append(r'[') 
     1399        sb.append(startDelim) 
    14001400        sep = '' 
    14011401        for arg in _args 
    14021402            sb.append(sep) 
    14031403            sb.append(arg.toCobraSource) 
    14041404            sep = ', ' 
    1405         sb.append(']') 
     1405        sb.append(stopDelim) 
    14061406        return sb.toString 
     1407         
     1408    def toCobraSource as String is override 
     1409        return .toCobraSource(r'[', ']') 
    14071410 
    14081411    def writeSharpDef(sw as SharpWriter, parens as bool) is override 
    14091412        if _target.type.isDynamic 
     
    14141417                expr.writeSharpDef(sw, false) 
    14151418            sw.write(')') 
    14161419            return 
     1420             
    14171421        if parens 
    14181422            sw.write('(') 
    1419         if _target inherits IdentifierExpr 
    1420             if _target.isKindOf(.compiler.typeType) 
    1421                 # here we're favoring "Foo[]" being an array type rather than a shared indexer 
    1422                 sw.write(_target.name) 
    1423                 handled = true 
    1424         if not handled 
    1425             _target.writeSharpDef(sw) 
     1423        .writeTarget(sw) 
    14261424        sw.write(r'[') 
    14271425        sep = '' 
    14281426        for expr in _args 
     
    14411439            expr.writeSharpBreakdownItems(sw) 
    14421440        sw.write(', -1') 
    14431441 
     1442    def writeTarget(sw as SharpWriter) 
     1443        if _target inherits IdentifierExpr 
     1444            if _target.isKindOf(.compiler.typeType) 
     1445                # here we're favoring "Foo[]" being an array type rather than a shared indexer 
     1446                sw.write(_target.name) 
     1447                handled = true 
     1448        if not handled 
     1449            _target.writeSharpDef(sw) 
     1450         
     1451class ExtIndexExpr 
     1452    inherits IndexExpr 
     1453    """ 
     1454    Extended Index Expression - Maps index onto function supporting 
     1455    conversion of single -ve arg to offset from end of sequence 
     1456    """ 
    14441457 
     1458    def init(token as IToken, target as Expr, args as List<of Expr>) 
     1459        base.init(token, target, args) 
     1460         
     1461    def toCobraSource as String is override 
     1462        return .toCobraSource(r'[[', ']]') 
     1463 
     1464    def writeSharpDef(sw as SharpWriter, parens as bool) is override 
     1465        if _target.type.isDynamic  # TODO: should this also be overloaded ? 
     1466            base.writeSharpDef(sw, parens) 
     1467            return 
     1468             
     1469        if not _isSequence(_target.type to !) or _args.count <> 1  
     1470            base.writeSharpDef(sw, parens) 
     1471            return 
     1472             
     1473        if parens 
     1474            sw.write('(') 
     1475        # GetExtIndexed(target, idx) 
     1476        sw.write('CobraImp.GetExtIndexed(') 
     1477        _target.writeSharpDef(sw, false) 
     1478        sw.write(', ') 
     1479        _args[0].writeSharpDefInContext(sw) 
     1480        sw.write(')') 
     1481        if parens 
     1482            sw.write(')') 
     1483             
     1484             
    14451485class IsNilExpr 
    14461486    inherits Expr 
    14471487 
  • Source/CobraParser.cobra

     
    10871087        isNames = List<of String>(_isNamesStack) 
    10881088        if .peek.which=='IS' 
    10891089            isNames = .isDeclNames 
    1090             attribs = .hasAttribs 
     1090            #attribs = .hasAttribs 
    10911091            assert .last.which=='EOL' 
    10921092            .undo  # need the EOL 
    10931093            if .optionalIndent 
     
    10961096        else 
    10971097            if .optionalIndent 
    10981098                isNames = .isDeclNames 
    1099                 attribs = .hasAttribs 
     1099                #attribs = .hasAttribs 
    11001100                docString = .docString 
    11011101                .dedent 
    11021102        return BoxVar(tok, .curBox, identifier, type, isNames, initExpr, docString) 
     
    22792279        var _binaryOpPrec = { 
    22802280            # CANNOT USE 0 AS A VALUE IN THIS DICTIONARY 
    22812281            'DOT':              80, 
     2282            'LBRACKET_DBL':     80, 
    22822283            'LBRACKET':         80, 
    22832284            'LPAREN':           80, 
    22842285            'ARRAY_OPEN':       80, 
     
    24002401                token = .grab 
    24012402                exprs = .commaSepExprs('RPAREN') 
    24022403                return .expression(precedence, PostCallExpr(token, left, exprs)) 
     2404            else if peek=='LBRACKET_DBL' 
     2405                # requires special handling - extIndexExpr 
     2406                return .expression(precedence, .extIndexExpr(left to !)) 
    24032407            else 
    24042408                # most operators are one-word affairs 
    24052409                if op is nil 
     
    27672771            for expr in exprs 
    27682772                assert expr, exprs 
    27692773            return IndexExpr(token, left, exprs) 
    2770  
     2774             
     2775    def extIndexExpr(left as Expr) as Expr 
     2776        token = .expect('LBRACKET_DBL') 
     2777        exprs = .commaSepExprs(['RBRACKET_DBL'], false) 
     2778        return ExtIndexExpr(token, left, exprs) 
     2779             
    27712780    def literalList as ListLit 
    27722781        token = .expect('LBRACKET') 
    27732782        exprs = .commaSepExprs(['RBRACKET'], true) 
  • Source/CobraTokenizer.cobra

     
    5050    var _inSubstStringSingle = false 
    5151    var _inSubstStringDouble = false 
    5252    var _inDocString = false 
     53    var _lBracketDblCount as int 
     54    var _rBSpecStack as Collections.Stack = Collections.Stack() 
    5355 
    5456    def init 
    5557        base.init 
     
    6264        base.addInfo(sb) 
    6365        sb.append('_indentCount=[_indentCount], ') 
    6466        sb.append('_substLBracketCount=[_substLBracketCount], ') 
     67        sb.append('_lBracketDblCount=[_lBracketDblCount], ') 
    6568        sb.append('_inSubstStringSingle=[_inSubstStringSingle], ') 
    6669        sb.append('_inDocString=[_inDocString]') 
    6770 
     
    116119            r'STRING_RAW_DOUBLE     r"[^"\n]*"', 
    117120 
    118121            # substituted strings 
     122            r'RBRACKET_DBL_SPECIAL  ]]', 
    119123            r'RBRACKET_SPECIAL      ]', 
    120124            r"STRING_START_SINGLE   '",  # see "def make_STRING_FOO_BAR" 
    121125            r"STRING_PART_SINGLE    '", 
     
    159163            r'ASSIGN            =', 
    160164            r'LPAREN            \(', 
    161165            r'RPAREN            \)', 
     166            r'LBRACKET_DBL      \[\[', 
    162167            r'LBRACKET          \[', 
     168            r'RBRACKET_DBL      \]\]', 
    163169            r'RBRACKET          \]', 
    164170            r'LCURLY            \{', 
    165171            r'RCURLY            \}', 
     
    210216        base._reset 
    211217        _indentCount = 0 
    212218        _substLBracketCount = 0 
     219        _lBracketDblCount = 0 
    213220 
    214221    def makeSTRING_START_SINGLE(definition as String) as TokenDef? 
    215222        return StringStartTokenDef('STRING_START_SINGLE', definition[0]) 
     
    228235         
    229236    def makeSTRING_STOP_DOUBLE(definition as String) as TokenDef? 
    230237        return StringStopTokenDef('STRING_STOP_DOUBLE', definition[0]) 
    231  
     238             
     239    def makeLBRACKET_DBL(definition as String) as TokenDef? 
     240        return LBracketDblTokenDef('LBRACKET_DBL', definition, this) 
     241             
    232242    def afterStart is override 
    233243        base.afterStart 
    234244        # CC: 
    235245        # _tokenDefsByWhich['STRING_PART_SINGLE'].isActiveCall = def(tokenizer)=tokenizer.inSubstStringSingle 
    236246        # _tokenDefsByWhich['STRING_STOP_SINGLE'].isActiveCall = def(tokenizer)=tokenizer.inSubstStringSingle 
    237         for which in 'RBRACKET_SPECIAL STRING_PART_SINGLE STRING_STOP_SINGLE STRING_PART_DOUBLE STRING_STOP_DOUBLE STRING_PART_FORMAT'.split(c' ') 
     247        for which in 'RBRACKET_SPECIAL RBRACKET_DBL_SPECIAL RBRACKET_DBL STRING_PART_SINGLE STRING_STOP_SINGLE STRING_PART_DOUBLE STRING_STOP_DOUBLE STRING_PART_FORMAT'.split(c' ') 
    238248            _tokenDefsByWhich[which].isActive = false 
    239249 
    240250    def isActiveCall(tok as TokenDef) as bool is override 
     
    610620        _tokenDefsByWhich['STRING_STOP_DOUBLE'].isActive = false 
    611621        _tokenDefsByWhich['STRING_PART_FORMAT'].isActive = false 
    612622        return tok 
     623         
     624    # Swap out and deactivate a (possibly inactive) lookout Token for  
     625    # another one. 
     626    # pair to unSwapActive()     
     627    def _swapActive(currTokName as String, nextTokName as String) 
     628        _rBSpecStack.push(_tokenDefsByWhich[currTokName].isActive) 
     629        _tokenDefsByWhich[currTokName].isActive = false  
     630        _tokenDefsByWhich[nextTokName].isActive = true 
     631         
     632    # Deactivate and swapout a lookout Token for a (possibly inactive) 
     633    # previous paired one 
     634    # pair to swapActive()   
     635    def _unSwapActive(currTokName as String, prevTokName as String) 
     636        require 
     637            _rBSpecStack.count  
     638        body 
     639            _tokenDefsByWhich[currTokName].isActive = false 
     640            _tokenDefsByWhich[prevTokName].isActive = _rBSpecStack.pop to bool 
     641         
     642    def onLBRACKET_DBL(tok as IToken) as IToken 
     643        _lBracketDblCount += 1 
     644        if _inSubstStringSingle or _inSubstStringDouble 
     645            # change to lookout for ']]' rather than ']' closing subst in String.  
     646            ._swapActive('RBRACKET_SPECIAL', 'RBRACKET_DBL_SPECIAL') 
     647        else 
     648            if _lBracketDblCount==1 
     649                _tokenDefsByWhich['RBRACKET_DBL'].isActive = true 
     650        return tok 
     651         
     652    def onRBRACKET_DBL(tok as IToken) as IToken 
     653        _lBracketDblCount -= 1 
     654        if _lBracketDblCount == 0 
     655            _tokenDefsByWhich['RBRACKET_DBL'].isActive = false 
     656        return tok 
     657         
     658    def onRBRACKET_DBL_SPECIAL(tok as IToken) as IToken 
     659        require 
     660            _inSubstStringSingle or _inSubstStringDouble 
     661            _lBracketDblCount 
     662        body 
     663            _lBracketDblCount -= 1 
     664            if _lBracketDblCount == 0 
     665                # revert back to any previous RBRACKET_SPECIAL lookout 
     666                ._unSwapActive('RBRACKET_DBL_SPECIAL', 'RBRACKET_SPECIAL') 
     667            tok.which = 'RBRACKET_DBL' 
     668            return tok 
    613669 
    614  
    615670    def onLBRACKET(tok as IToken) as IToken 
    616671        if _inSubstStringSingle or _inSubstStringDouble 
    617672            _substLBracketCount += 1 
    618673            if _substLBracketCount==1 
    619                 _tokenDefsByWhich['RBRACKET_SPECIAL'].isActive = true 
     674                ._swapActive('RBRACKET_DBL_SPECIAL', 'RBRACKET_SPECIAL')  
    620675                assert _tokenDefsByWhich['STRING_PART_FORMAT'].isActive 
    621676                _tokenDefsByWhich['STRING_PART_FORMAT'].isActive = false 
    622677        return tok 
     
    628683        body 
    629684            _substLBracketCount -= 1 
    630685            if _substLBracketCount == 0 
    631                 _tokenDefsByWhich['RBRACKET_SPECIAL'].isActive = false 
     686                ._unSwapActive('RBRACKET_SPECIAL', 'RBRACKET_DBL_SPECIAL') 
    632687                assert not _tokenDefsByWhich['STRING_PART_FORMAT'].isActive 
    633688                _tokenDefsByWhich['STRING_PART_FORMAT'].isActive = true 
    634689            tok.which = 'RBRACKET'  # tricky, tricky. the parser never sees an RBRACKET_SPECIAL 
     
    886941                    if c == quote, return sb.toString 
    887942                    if c == c'\\', isEscaped = true 
    888943            return nil 
     944             
     945class LBracketDblTokenDef  
     946    inherits TokenRegexDef 
     947    """ 
     948    This would work using default TokenRegexDef except that matches 
     949        '[[' in literal lists of lists or arrays of lists    
     950        e.g. @[[1,2],[3,4]].  [['a',1],['b',2]] 
     951    Thats avoidable by inserting whitespace into literal to disambiguate  
     952       the [[ token         e.g.   @[ [1,2], [3,4] ]  [ ['a',1], ['b',2] ] 
     953    But it's nicer if we handle it regardless of ws 
     954    """ 
     955 
     956    var _tknizr as Tokenizer 
     957     
     958    def init(which as String, regExSource  as String, tknizer as Tokenizer) 
     959        base.init(which, regExSource) 
     960        _tknizr = tknizer 
     961     
     962    # do a regex match and succeed if match and lastToken is an id   
     963    def match(input as String) as TokenMatch? is override 
     964        reMatch = _re.match(input) 
     965        if reMatch.success and _ 
     966                _tknizr.lastToken and _tknizr.lastToken.which == 'ID' 
     967            assert reMatch.index == 0 
     968            assert reMatch.value 
     969#           print "LBracketDbl match and ID" 
     970            return TokenRegexMatch(reMatch) 
     971        else 
     972            return nil 
  • Tests/100-basics/067-extended-indexing.cobra

     
     1namespace Test 
     2     
     3    class ExtIdx 
     4        shared 
     5            var _a= @['abc', 'def', 'ghi', 'jkl', 'mno', 'pqr', 'stu',  
     6                'vw', 'xyz', 
     7            ] 
     8            var _b = @[1,2,3,4,5] 
     9            var _list = ['abc', 'def', 'ghi', 'jkl', 'mno', 'pqr',  
     10                'stu', 'vw', 'xyz', 
     11            ] 
     12 
     13        pro [i as int] as int 
     14            get 
     15                return i*i 
     16            set 
     17                pass 
     18 
     19        def checkPropIdx is shared 
     20            x=ExtIdx() 
     21            assert x[1]==1 
     22            assert x[2]==4 
     23            assert x[3]==9 
     24            assert x[-3]==9 
     25            assert x[[-3]]==9 
     26            x[1] = 5 
     27            x[2] = 6 
     28                 
     29        def extListIdx is shared 
     30            l = _list 
     31            assert l[0] == 'abc' 
     32            assert l[l.count-1] == 'xyz' 
     33            t as String = l[1] 
     34            s = t 
     35            assert s==t 
     36            assert t==l[1] 
     37            assert l[0] == 'abc' 
     38            assert l[1] == 'def' 
     39            assert l[2] == 'ghi' 
     40            assert l[3] == 'jkl' 
     41            assert l[4] == 'mno' 
     42            assert l[5] == 'pqr' 
     43            assert l[6] == 'stu' 
     44            assert l[7] == 'vw' 
     45            assert l[8] == 'xyz' 
     46            assert l[0] == 'abc' 
     47         
     48            # List Ext Indexing positive indexes 
     49 
     50            l = _list 
     51            assert l[[0]] == 'abc' 
     52            assert l[[l.count-1]] == 'xyz' 
     53            t as String = l[[1]] 
     54            s = t 
     55            assert s==t 
     56            assert t==l[[1]] 
     57            assert l[[0]] == 'abc' 
     58            assert l[[1]] == 'def' 
     59            assert l[[2]] == 'ghi' 
     60            assert l[[3]] == 'jkl' 
     61            assert l[[4]] == 'mno' 
     62            assert l[[5]] == 'pqr' 
     63            assert l[[6]] == 'stu' 
     64            assert l[[7]] == 'vw' 
     65            assert l[[8]] == 'xyz' 
     66            assert l[[0]] == 'abc' 
     67             
     68            # List Ext Indexing negative values 
     69 
     70            l = _list 
     71            x = l[[-1]]  
     72            assert x == 'xyz' 
     73            assert l[[l.count-1]] == 'xyz' 
     74            y = l[[-1]] 
     75            assert l[[l.count-1]] == y 
     76            t as String = l[[-2]] 
     77            s = t 
     78            assert s==t 
     79            assert t==l[[-2]] 
     80            assert s==l[[-2]] 
     81            assert l[[-9]] == 'abc' 
     82            assert l[[-8]] == 'def' 
     83            assert l[[-7]] == 'ghi' 
     84            assert l[[-6]] == 'jkl' 
     85            assert l[[-5]] == 'mno' 
     86            assert l[[-4]] == 'pqr' 
     87            assert l[[-3]] == 'stu' 
     88            assert l[[-2]] == 'vw' 
     89            assert l[[-1]] == 'xyz' 
     90            expect ArgumentOutOfRangeException 
     91                assert l[[-19]] == 'abc' 
     92             
     93             
     94        def extStrIdx is shared 
     95 
     96            s as String = 'aoeu' 
     97            c as char = s[0] 
     98            assert c==c'a' 
     99 
     100            assert '[s][s]'=='aoeuaoeu' 
     101 
     102            # now the real test: 
     103            assert '[s[0]]'=='a' 
     104 
     105            c = s[[s.length-1]] 
     106            assert c==c'u' 
     107            c=s[0] 
     108            assert c==c'a' 
     109            c=s[1] 
     110            assert c==c'o' 
     111            c=s[2] 
     112            assert c==c'e' 
     113            c=s[3] 
     114            assert c==c'u' 
     115 
     116            # String ext indexing positive indexes 
     117            s = 'aoeu' 
     118            c = s[0] 
     119            assert c==c'a' 
     120 
     121            assert '[s][s]'=='aoeuaoeu' 
     122 
     123            c = s[[s.length-1]] 
     124            assert c==c'u' 
     125            c=s[[0]] 
     126            assert c==c'a' 
     127            c=s[[1]] 
     128            assert c==c'o' 
     129            c=s[[2]] 
     130            assert c==c'e' 
     131            c=s[[3]] 
     132            assert c==c'u' 
     133             
     134            # String ext indexing negative indexes 
     135 
     136            s = 'aoeu' 
     137            c = s[[-1]] 
     138            assert c==c'u' 
     139 
     140            assert '[s][s]'=='aoeuaoeu' 
     141 
     142            # now the real test: 
     143#           assert '[s[-1] ]'=='u' 
     144            assert '[s[[-1]]]'=='u'   
     145## breaks here          a = [[1,2],[3,4]]   # treat as [ [1,2], [3,4] ]  
     146 
     147            c = s[s.length-1] 
     148            assert c==c'u' 
     149            c=s[[-1]] 
     150            assert c==c'u' 
     151            c=s[[-2]] 
     152            assert c==c'e' 
     153            c=s[[-3]] 
     154            assert c==c'o' 
     155            c=s[[-4]] 
     156            assert c==c'a' 
     157            expect IndexOutOfRangeException 
     158                c=s[[-5]] 
     159                assert c==c'a' 
     160            expect IndexOutOfRangeException 
     161                c=s[[-6]] 
     162                assert c==c'a' 
     163         
     164        def extArrIdx is shared 
     165            a = _a 
     166            assert a[0] == 'abc' 
     167            assert a[a.length-1] == 'xyz' 
     168            t as String = a[1] 
     169            s = t 
     170            assert s==t 
     171            assert s==a[1] 
     172         
     173            b = _b 
     174            assert b[0] == 1 
     175            assert b[b.length-1] == 5 
     176            bt = b[1] 
     177            bs = bt 
     178            assert bs==bt 
     179            assert bs==b[1] 
     180            assert b[0] == 1 
     181            assert b[1] == 2 
     182            assert b[2] == 3 
     183            assert b[3] == 4 
     184            assert b[4] == 5 
     185         
     186            # Array ext indexing positive indexes 
     187            a = _a 
     188            assert a[[0]] == 'abc' 
     189            assert a[[a.length-1]] == 'xyz' 
     190            t as String = a[[1]] 
     191            s = t 
     192            assert s==t 
     193            assert s==a[[1]] 
     194         
     195            b = _b 
     196            assert b[[0]] == 1 
     197            assert b[[b.length-1]] == 5 
     198            bt = b[[1]] 
     199            bs = bt 
     200            assert bs==bt 
     201            assert bs==b[[1]] 
     202            assert b[[0]] == 1 
     203            assert b[[1]] == 2 
     204            assert b[[2]] == 3 
     205            assert b[[3]] == 4 
     206            assert b[[4]] == 5 
     207             
     208            # Array ext Indexing - negative indexes 
     209            a = _a  
     210            assert a[[-1]] == 'xyz' 
     211            expect IndexOutOfRangeException 
     212                assert a[[-10]] == 'abc' 
     213            t as String = a[[-2]] 
     214            s = t 
     215            assert s==t 
     216            assert s==a[[-2]] 
     217         
     218            #b = @[1,2,3,4,5] 
     219            b = _b 
     220            assert b[[-1]] == 5 
     221            expect IndexOutOfRangeException 
     222                assert b[[-10]] == 1 
     223            bt = b[[-3]] 
     224            bs = bt 
     225            assert bs==bt 
     226            assert bs==b[[-3]] 
     227            assert b[[0]] == 1 
     228            assert b[[-1]] == 5 
     229            assert b[[-2]] == 4 
     230            assert b[[-3]] == 3 
     231            assert b[[-4]] == 2 
     232            assert b[[-5]] == 1 
     233            expect IndexOutOfRangeException 
     234                assert b[[-6]] == 1 
     235         
     236            assert b[[-1]] == b[b.length-1] 
     237            assert b[[-2]] == 4 
     238            assert b[[-3]] == 3 
     239            assert b[[-4]] == 2 
     240            assert b[[-5]] == 1 
     241            expect IndexOutOfRangeException 
     242                assert b[[-6]] == 1 
     243             
     244        def arrNegIdx1 is shared 
     245            a = _a #@['abc', 'def', 'ghi', 'jkl', 'mno', 'pqr', 'stu', 'vw', 'xyz'] 
     246            i=-1 
     247            assert a[[i]] == 'xyz' 
     248            i=-10 
     249            expect IndexOutOfRangeException 
     250                assert a[[i]] == 'abc' 
     251            i=-2 
     252            t as String = a[[i]] 
     253            s = t 
     254            assert s==t 
     255            assert s==a[[i]] 
     256         
     257            #b = @[1,2,3,4,5] 
     258            b = _b 
     259            i=-1 
     260            assert b[[i]] == 5 
     261            i=-10 
     262            expect IndexOutOfRangeException 
     263                assert b[[i]] == 1 
     264            i=-3 
     265            bt = b[[i]] 
     266            bs = bt 
     267            assert bs==bt 
     268            assert bs==b[[i]] 
     269            i=0 
     270            assert b[[i]] == 1 
     271            j=5 
     272            for i in -1:-5:-1 
     273                assert b[[i]] == j 
     274                if j>1 
     275                    j -= 1 
     276                 
     277        # Extended indexing in String substitutions 
     278        def extIdxInStrSubst is shared 
     279 
     280            s as String = 'aoeu' 
     281            c as char = s[0] 
     282            assert c==c'a' 
     283            ia = @[1,2,-1,3] 
     284 
     285            c = s[[-1]] 
     286            assert c==c'u' 
     287 
     288            # now the real tests: 
     289            assert '[s[[-1]]]'=='u' 
     290             
     291            assert '[s[ia[1]]]!'=='e!' 
     292            assert '[s[[ia[1]]]]!' == 'e!'  
     293            assert '[s[[ia[1] ]] ]!' == 'e!'  
     294            assert '[s[[ia[[1]]]]]!' == 'e!'  
     295             
     296            assert '[s[[ia[[-1]]]]]!' == 'u!'  
     297            assert '[ s[[ ia[[-1]] ]] ]!' == 'u!'  
     298            assert '-[s[[ia[[-2]]]]]!' == '-u!'  
     299             
     300        def tokenCompileTest is shared 
     301            # these will fail to compile with recognition of dbl [ 
     302            # as LBRACKET_DBL if tokeniser not clever 
     303            a = [[1,2],[3,4]]   # treat as [ [1,2], [3,4] ]  
     304            b = @[[1,1],[2,2]]  # treat as @[ [1,1],[2,2] ]  
     305            c = [1, [2,3], [[4,5],[6,7]]] 
     306            assert a.count == 2 
     307            assert b.length == 2 
     308            assert c.count == 3 
     309             
     310        def main is shared 
     311            .extListIdx 
     312            .extArrIdx 
     313            .extStrIdx 
     314            .extIdxInStrSubst 
     315             
     316            .checkPropIdx 
     317