@@ -366,7 +366,12 @@ async Task<JObject> ResolveAsInstanceMember(ArraySegment<string> parts, JObject
366366            } 
367367        } 
368368
369-         public  async  Task < JObject >  Resolve ( ElementAccessExpressionSyntax  elementAccess ,  Dictionary < string ,  JObject >  memberAccessValues ,  JObject  indexObject ,  List < VariableDefinition >  variableDefinitions ,  CancellationToken  token ) 
369+         public  async  Task < JObject >  Resolve ( 
370+             ElementAccessExpressionSyntax  elementAccess , 
371+             Dictionary < string ,  JObject >  memberAccessValues , 
372+             List < JObject >  nestedIndexObject , 
373+             List < VariableDefinition >  variableDefinitions , 
374+             CancellationToken  token ) 
370375        { 
371376            try 
372377            { 
@@ -376,12 +381,13 @@ public async Task<JObject> Resolve(ElementAccessExpressionSyntax elementAccess,
376381
377382                if  ( rootObject  ==  null ) 
378383                { 
379-                     // it might be a jagged array where indexObject should be treated as a new rootObject 
380-                     rootObject  =  indexObject ; 
381-                     indexObject  =  null ; 
384+                     // it might be a jagged array where the previously added nestedIndexObject should be treated as a new rootObject 
385+                     rootObject  =  nestedIndexObject . LastOrDefault ( ) ; 
386+                     if  ( rootObject  !=  null ) 
387+                         nestedIndexObject . RemoveAt ( nestedIndexObject . Count  -  1 ) ; 
382388                } 
383389
384-                 ElementIndexInfo  elementIdxInfo  =  await  GetElementIndexInfo ( ) ; 
390+                 ElementIndexInfo  elementIdxInfo  =  await  GetElementIndexInfo ( nestedIndexObject ) ; 
385391                if  ( elementIdxInfo  is  null ) 
386392                    return  null ; 
387393
@@ -394,6 +400,7 @@ public async Task<JObject> Resolve(ElementAccessExpressionSyntax elementAccess,
394400                if  ( ! DotnetObjectId . TryParse ( rootObject ? [ "objectId" ] ? . Value < string > ( ) ,  out  DotnetObjectId  objectId ) ) 
395401                    throw  new  InvalidOperationException ( $ "Cannot apply indexing with [] to a primitive object of type '{ type } '") ; 
396402
403+                 bool  isMultidimensional  =  elementIdxInfo . DimensionsCount  !=  1 ; 
397404                switch  ( objectId . Scheme ) 
398405                { 
399406                    case  "valuetype" :  //can be an inlined array 
@@ -407,7 +414,7 @@ public async Task<JObject> Resolve(ElementAccessExpressionSyntax elementAccess,
407414                    } 
408415                    case  "array" : 
409416                        rootObject [ "value" ]  =  await  context . SdbAgent . GetArrayValues ( objectId . Value ,  token ) ; 
410-                         if  ( ! elementIdxInfo . IsMultidimensional ) 
417+                         if  ( ! isMultidimensional ) 
411418                        { 
412419                            int . TryParse ( elementIdxInfo . ElementIdxStr ,  out  elementIdx ) ; 
413420                            return  ( JObject ) rootObject [ "value" ] [ elementIdx ] [ "value" ] ; 
@@ -417,18 +424,16 @@ public async Task<JObject> Resolve(ElementAccessExpressionSyntax elementAccess,
417424                            return  ( JObject ) ( ( ( JArray ) rootObject [ "value" ] ) . FirstOrDefault ( x =>  x [ "name" ] . Value < string > ( )  ==  elementIdxInfo . ElementIdxStr ) [ "value" ] ) ; 
418425                        } 
419426                    case  "object" : 
420-                         if  ( elementIdxInfo . IsMultidimensional ) 
421-                             throw  new  InvalidOperationException ( $ "Cannot apply indexing with [,] to an object of type '{ type } '") ; 
422427                        // ToDo: try to use the get_Item for string as well 
423-                         if  ( type  ==  "string" ) 
428+                         if  ( ! isMultidimensional   &&   type  ==  "string" ) 
424429                        { 
425430                            var  eaExpressionFormatted  =  elementAccessStrExpression . Replace ( '.' ,  '_' ) ;  // instance_str 
426431                            variableDefinitions . Add ( new  ( eaExpressionFormatted ,  rootObject ,  ExpressionEvaluator . ConvertJSToCSharpLocalVariableAssignment ( eaExpressionFormatted ,  rootObject ) ) ) ; 
427432                            var  eaFormatted  =  elementAccessStr . Replace ( '.' ,  '_' ) ;  // instance_str[1] 
428433                            var  variableDef  =  await  ExpressionEvaluator . GetVariableDefinitions ( this ,  variableDefinitions ,  invokeToStringInObject :  false ,  token ) ; 
429434                            return  await  ExpressionEvaluator . EvaluateSimpleExpression ( this ,  eaFormatted ,  elementAccessStr ,  variableDef ,  logger ,  token ) ; 
430435                        } 
431-                         if  ( indexObject  is  null  &&  elementIdxInfo . IndexingExpression   is   null ) 
436+                         if  ( elementIdxInfo . Indexers  is  null  ||  elementIdxInfo . Indexers . Count   ==   0 ) 
432437                            throw  new  InternalErrorException ( $ "Unable to write index parameter to invoke the method in the runtime.") ; 
433438
434439                        var  typeIds  =  await  context . SdbAgent . GetTypeIdsForObject ( objectId . Value ,  true ,  token ) ; 
@@ -441,15 +446,13 @@ public async Task<JObject> Resolve(ElementAccessExpressionSyntax elementAccess,
441446                        { 
442447                            MethodInfoWithDebugInformation  methodInfo  =  await  context . SdbAgent . GetMethodInfo ( methodIds [ i ] ,  token ) ; 
443448                            ParameterInfo [ ]  paramInfo  =  methodInfo . GetParametersInfo ( ) ; 
444-                             if  ( paramInfo . Length  ==  1 ) 
449+                             if  ( paramInfo . Length  ==  elementIdxInfo . DimensionsCount ) 
445450                            { 
446451                                try 
447452                                { 
448-                                     if  ( indexObject   !=   null   &&   ! CheckParametersCompatibility ( paramInfo [ 0 ] . TypeCode ,   indexObject ) ) 
453+                                     if  ( ! CheckParametersCompatibility ( paramInfo ,   elementIdxInfo . Indexers ) ) 
449454                                        continue ; 
450-                                     ArraySegment < byte >  buffer  =  indexObject  is  null  ? 
451-                                         await  WriteLiteralExpressionAsIndex ( objectId ,  elementIdxInfo . IndexingExpression ,  elementIdxInfo . ElementIdxStr )  : 
452-                                         await  WriteJObjectAsIndex ( objectId ,  indexObject ,  elementIdxInfo . ElementIdxStr ,  paramInfo [ 0 ] . TypeCode ) ; 
455+                                     ArraySegment < byte >  buffer  =  await  WriteIndexObjectAsIndices ( objectId ,  elementIdxInfo . Indexers ,  paramInfo ) ; 
453456                                    JObject  getItemRetObj  =  await  context . SdbAgent . InvokeMethod ( buffer ,  methodIds [ i ] ,  token ) ; 
454457                                    return  ( JObject ) getItemRetObj [ "value" ] ; 
455458                                } 
@@ -470,31 +473,32 @@ await WriteLiteralExpressionAsIndex(objectId, elementIdxInfo.IndexingExpression,
470473                throw  new  ReturnAsErrorException ( $ "Unable to evaluate element access '{ elementAccess } ': { ex . Message } ",  ex . GetType ( ) . Name ) ; 
471474            } 
472475
473-             async  Task < ElementIndexInfo >  GetElementIndexInfo ( ) 
476+             async  Task < ElementIndexInfo >  GetElementIndexInfo ( List < JObject >   nestedIndexers ) 
474477            { 
475-                 // e.g. x[a[0]], x[a[b[1]]] etc. 
476-                 if  ( indexObject  is  not null ) 
477-                     return  new  ElementIndexInfo ( ElementIdxStr :  indexObject [ "value" ] . ToString ( )  ) ; 
478- 
479478                if  ( elementAccess . ArgumentList  is  null ) 
480479                    return  null ; 
481480
482-                 StringBuilder  elementIdxStr  =  new  StringBuilder ( ) ; 
483-                 var  multiDimensionalArray  =  false ; 
481+                 int  dimCnt  =  elementAccess . ArgumentList . Arguments . Count ; 
484482                LiteralExpressionSyntax  indexingExpression  =  null ; 
485-                 for  ( int  i  =  0 ;  i  <  elementAccess . ArgumentList . Arguments . Count ;  i ++ ) 
483+                 StringBuilder  elementIdxStr  =  new  StringBuilder ( ) ; 
484+                 List < object >  indexers  =  new ( ) ; 
485+                 // nesting should be resolved in reverse order 
486+                 int  nestedIndexersCnt  =  nestedIndexers . Count  -  1 ; 
487+                 for  ( int  i  =  0 ;  i  <  dimCnt ;  i ++ ) 
486488                { 
489+                     JObject  indexObject ; 
487490                    var  arg  =  elementAccess . ArgumentList . Arguments [ i ] ; 
488491                    if  ( i  !=  0 ) 
489492                    { 
490493                        elementIdxStr . Append ( ", " ) ; 
491-                         multiDimensionalArray  =  true ; 
492494                    } 
493495                    // e.g. x[1] 
494496                    if  ( arg . Expression  is  LiteralExpressionSyntax ) 
495497                    { 
496498                        indexingExpression  =  arg . Expression  as  LiteralExpressionSyntax ; 
497-                         elementIdxStr . Append ( indexingExpression . ToString ( ) ) ; 
499+                         string  expression  =  indexingExpression . ToString ( ) ; 
500+                         elementIdxStr . Append ( expression ) ; 
501+                         indexers . Add ( indexingExpression ) ; 
498502                    } 
499503
500504                    // e.g. x[a] or x[a.b] 
@@ -508,6 +512,18 @@ async Task<ElementIndexInfo> GetElementIndexInfo()
508512                        // x[a] 
509513                        indexObject  ??=  await  Resolve ( argParm . Identifier . Text ,  token ) ; 
510514                        elementIdxStr . Append ( indexObject [ "value" ] . ToString ( ) ) ; 
515+                         indexers . Add ( indexObject ) ; 
516+                     } 
517+                     // nested indexing, e.g. x[a[0]], x[a[b[1]]], x[a[0], b[1]] 
518+                     else  if  ( arg . Expression  is  ElementAccessExpressionSyntax ) 
519+                     { 
520+                         if  ( nestedIndexers  ==  null  ||  nestedIndexersCnt  <  0 ) 
521+                             throw  new  InvalidOperationException ( $ "Cannot resolve nested indexing") ; 
522+                         JObject  nestedIndexObject  =  nestedIndexers [ nestedIndexersCnt ] ; 
523+                         nestedIndexers . RemoveAt ( nestedIndexersCnt ) ; 
524+                         elementIdxStr . Append ( nestedIndexObject [ "value" ] . ToString ( ) ) ; 
525+                         indexers . Add ( nestedIndexObject ) ; 
526+                         nestedIndexersCnt -- ; 
511527                    } 
512528                    // indexing with expressions, e.g. x[a + 1] 
513529                    else 
@@ -519,36 +535,57 @@ async Task<ElementIndexInfo> GetElementIndexInfo()
519535                        if  ( idxType  !=  "number" ) 
520536                            throw  new  InvalidOperationException ( $ "Cannot index with an object of type '{ idxType } '") ; 
521537                        elementIdxStr . Append ( indexObject [ "value" ] . ToString ( ) ) ; 
538+                         indexers . Add ( indexObject ) ; 
522539                    } 
523540                } 
524541                return  new  ElementIndexInfo ( 
542+                     DimensionsCount :  dimCnt , 
525543                    ElementIdxStr :  elementIdxStr . ToString ( ) , 
526-                     IsMultidimensional :  multiDimensionalArray , 
527-                     IndexingExpression :  indexingExpression ) ; 
544+                     Indexers :  indexers ) ; 
528545            } 
529546
530-             async  Task < ArraySegment < byte > >  WriteJObjectAsIndex ( DotnetObjectId  rootObjId ,  JObject   indexObject ,   string   elementIdxStr ,   ElementType ?   expectedType ) 
547+             async  Task < ArraySegment < byte > >  WriteIndexObjectAsIndices ( DotnetObjectId  rootObjId ,  List < object >   indexObjects ,   ParameterInfo [ ]   paramInfo ) 
531548            { 
532549                using  var  writer  =  new  MonoBinaryWriter ( ) ; 
533550                writer . WriteObj ( rootObjId ,  context . SdbAgent ) ; 
534-                 writer . Write ( 1 ) ;  // number of method args 
535-                 if  ( ! await  writer . WriteJsonValue ( indexObject ,  context . SdbAgent ,  expectedType ,  token ) ) 
536-                     throw  new  InternalErrorException ( $ "Parsing index of type { indexObject [ "type" ] . Value < string > ( ) }  to write it into the buffer failed.") ; 
551+                 writer . Write ( indexObjects . Count ) ;  // number of method args 
552+                 foreach  ( ( ParameterInfo  pi ,  object  indexObject )  in  paramInfo . Zip ( indexObjects ) ) 
553+                 { 
554+                     if  ( indexObject  is  JObject  indexJObject ) 
555+                     { 
556+                         // indexed by an identifier name syntax 
557+                         if  ( ! await  writer . WriteJsonValue ( indexJObject ,  context . SdbAgent ,  pi . TypeCode ,  token ) ) 
558+                             throw  new  InternalErrorException ( $ "Parsing index of type { indexJObject [ "type" ] . Value < string > ( ) }  to write it into the buffer failed.") ; 
559+                     } 
560+                     else  if  ( indexObject  is  LiteralExpressionSyntax  expression ) 
561+                     { 
562+                         // indexed by a literal expression syntax 
563+                         if  ( ! await  writer . WriteConst ( expression ,  context . SdbAgent ,  token ) ) 
564+                             throw  new  InternalErrorException ( $ "Parsing literal expression index = { expression }  to write it into the buffer failed.") ; 
565+                     } 
566+                     else 
567+                     { 
568+                         throw  new  InternalErrorException ( $ "Unexpected index type.") ; 
569+                     } 
570+                 } 
537571                return  writer . GetParameterBuffer ( ) ; 
538572            } 
573+         } 
539574
540-             async  Task < ArraySegment < byte > >  WriteLiteralExpressionAsIndex ( DotnetObjectId  rootObjId ,  LiteralExpressionSyntax  indexingExpression ,  string  elementIdxStr ) 
575+         private  static bool  CheckParametersCompatibility ( ParameterInfo [ ]  paramInfos ,  List < object >  indexObjects ) 
576+         { 
577+             if  ( paramInfos . Length  !=  indexObjects . Count ) 
578+                 return  false ; 
579+             foreach  ( ( ParameterInfo  paramInfo ,  object  indexObj )  in  paramInfos . Zip ( indexObjects ) ) 
541580            { 
542-                 using  var  writer  =  new  MonoBinaryWriter ( ) ; 
543-                 writer . WriteObj ( rootObjId ,  context . SdbAgent ) ; 
544-                 writer . Write ( 1 ) ;  // number of method args 
545-                 if  ( ! await  writer . WriteConst ( indexingExpression ,  context . SdbAgent ,  token ) ) 
546-                     throw  new  InternalErrorException ( $ "Parsing index of type { indexObject [ "type" ] . Value < string > ( ) }  to write it into the buffer failed.") ; 
547-                 return  writer . GetParameterBuffer ( ) ; 
581+                 // shouldn't we check LiteralExpressionSyntax for compatibility as well? 
582+                 if  ( indexObj  is  JObject  indexJObj  &&  ! CheckParameterCompatibility ( paramInfo . TypeCode ,  indexJObj ) ) 
583+                     return  false ; 
548584            } 
585+             return  true ; 
549586        } 
550587
551-         private  static bool  CheckParametersCompatibility ( ElementType ?  paramTypeCode ,  JObject  value ) 
588+         private  static bool  CheckParameterCompatibility ( ElementType ?  paramTypeCode ,  JObject  value ) 
552589        { 
553590            if  ( ! paramTypeCode . HasValue ) 
554591                return  true ; 
@@ -871,7 +908,8 @@ public JObject TryGetEvaluationResult(string id)
871908
872909        private  sealed  record  ElementIndexInfo ( 
873910            string  ElementIdxStr , 
874-             bool  IsMultidimensional  =  false , 
875-             LiteralExpressionSyntax  IndexingExpression  =  null ) ; 
911+             // keeps JObjects and LiteralExpressionSyntaxes: 
912+             List < object >  Indexers , 
913+             int  DimensionsCount  =  1 ) ; 
876914    } 
877915} 
0 commit comments