Browse Source

pastojs: setlength(arr) now always clone

git-svn-id: trunk@42227 -
Mattias Gaertner 6 years ago
parent
commit
f50b4c5fbb
3 changed files with 74 additions and 5 deletions
  1. 35 3
      packages/pastojs/src/fppas2js.pp
  2. 7 1
      packages/pastojs/tests/tcmodules.pas
  3. 32 1
      utils/pas2js/dist/rtl.js

+ 35 - 3
packages/pastojs/src/fppas2js.pp

@@ -10783,8 +10783,8 @@ function TPasToJSConverter.ConvertBuiltIn_SetLength(El: TParamsExpr;
   AContext: TConvertContext): TJSElement;
 // convert "SetLength(a,Len)" to "a = rtl.arraySetLength(a,Len)"
 var
-  Param0: TPasExpr;
-  ResolvedParam0: TPasResolverResult;
+  Param0, Range: TPasExpr;
+  ResolvedParam0, RangeResolved: TPasResolverResult;
   ArrayType: TPasArrayType;
   Call: TJSCallExpression;
   ValInit: TJSElement;
@@ -10792,6 +10792,9 @@ var
   ElType, TypeEl: TPasType;
   i: Integer;
   aResolver: TPas2JSResolver;
+  DimSize: TMaxPrecInt;
+  StaticDims: TObjectList;
+  Lit: TJSLiteral;
 begin
   Result:=nil;
   Param0:=El.Params[0];
@@ -10813,6 +10816,7 @@ begin
 
     // ->  AnArray = rtl.setArrayLength(AnArray,defaultvalue,dim1,dim2,...)
     AssignContext:=TAssignContext.Create(El,nil,AContext);
+    StaticDims:=nil;
     try
       aResolver.ComputeElement(Param0,AssignContext.LeftResolved,[rcNoImplicitProc]);
       AssignContext.RightResolved:=ResolvedParam0;
@@ -10831,6 +10835,27 @@ begin
         ArrayType:=ElType as TPasArrayType;
         end;
       ElType:=aResolver.ResolveAliasType(aResolver.GetArrayElType(ArrayType));
+      while (ElType.ClassType=TPasArrayType) and (length(TPasArrayType(ElType).Ranges)>0) do
+        begin
+        // array of static array, Note: setlength reallocs static arrays
+        ArrayType:=ElType as TPasArrayType;
+        for i:=0 to length(ArrayType.Ranges)-1 do
+          begin
+          Range:=ArrayType.Ranges[i];
+          // compute size of this dimension
+          DimSize:=aResolver.GetRangeLength(Range);
+          if DimSize=0 then
+            begin
+            aResolver.ComputeElement(Range,RangeResolved,[rcConstant]);
+            RaiseNotSupported(Range,AContext,20190614171520,GetResolverResultDbg(RangeResolved));
+            end;
+          Lit:=CreateLiteralNumber(El,DimSize);
+          if StaticDims=nil then
+            StaticDims:=TObjectList.Create(true);
+          StaticDims.Add(Lit);
+          end;
+        ElType:=aResolver.ResolveAliasType(aResolver.GetArrayElType(ArrayType));
+        end;
       if ElType.ClassType=TPasRecordType then
         ValInit:=CreateReferencePathExpr(ElType,AContext)
       else
@@ -10839,12 +10864,19 @@ begin
       // add params: dim1, dim2, ...
       for i:=1 to length(El.Params)-1 do
         Call.AddArg(ConvertExpression(El.Params[i],AContext));
+      if StaticDims<>nil then
+        begin
+        for i:=0 to StaticDims.Count-1 do
+          Call.AddArg(TJSElement(StaticDims[i]));
+        StaticDims.OwnsObjects:=false;
+        end;
 
       // create left side:  array =
       Result:=CreateAssignStatement(Param0,AssignContext);
     finally
       AssignContext.RightSide.Free;
       AssignContext.Free;
+      StaticDims.Free;
     end;
     end
   else if ResolvedParam0.BaseType=btString then
@@ -15235,7 +15267,7 @@ begin
 
   Call:=CreateCallExpression(PosEl);
   Call.Expr:=CreateDotNameExpr(PosEl,Expr,
-                                       TJSString(GetBIName(pbifnRecordClone)));
+                                        TJSString(GetBIName(pbifnRecordClone)));
   Result:=Call;
   if RecordExpr<>nil then
     Call.AddArg(RecordExpr);

+ 7 - 1
packages/pastojs/tests/tcmodules.pas

@@ -9109,19 +9109,25 @@ begin
   Add([
   'type',
   '  TArrArrInt = array of array of longint;',
+  '  TArrStaInt = array of array[1..2] of longint;',
   'var',
   '  a: TArrArrInt;',
+  '  b: TArrStaInt;',
   'begin',
   '  SetLength(a,2);',
   '  SetLength(a,3,4);',
+  '  SetLength(b,5);',
   '']);
   ConvertProgram;
   CheckSource('TestArray_SetLengthMultiDim',
     LinesToStr([ // statements
-    'this.a = [];']),
+    'this.a = [];',
+    'this.b = [];',
+    '']),
     LinesToStr([
     '$mod.a = rtl.arraySetLength($mod.a, [], 2);',
     '$mod.a = rtl.arraySetLength($mod.a, 0, 3, 4);',
+    '$mod.b = rtl.arraySetLength($mod.b, 0, 5, 2);',
     '']));
 end;
 

+ 32 - 1
utils/pas2js/dist/rtl.js

@@ -797,6 +797,37 @@ var rtl = {
   },
 
   arraySetLength: function(arr,defaultvalue,newlength){
+    // multi dim: (arr,defaultvalue,dim1,dim2,...)
+    var p = arguments;
+    function setLength(src,argNo){
+      var newlen = p[argNo];
+      var a = [];
+      a.length = newlength;
+      if (argNo === p.length-1){
+        var oldlen = src?src.length:0;
+        if (rtl.isArray(defaultvalue)){
+          for (var i=0; i<newlen; i++) a[i]=(i<oldlen)?src[i]:[]; // array of dyn array
+        } else if (rtl.isObject(defaultvalue)) {
+          if (rtl.isTRecord(defaultvalue)){
+            for (var i=0; i<newlen; i++)
+              a[i]=(i<oldlen)?defaultvalue.$clone(src[i]):defaultvalue.$new(); // e.g. record
+          } else {
+            for (var i=0; i<newlen; i++) a[i]=(i<oldlen)?rtl.refSet(src[i]):{}; // e.g. set
+          }
+        } else {
+          for (var i=0; i<newlen; i++)
+            a[i]=(i<oldlen)?src[i]:defaultvalue;
+        }
+      } else {
+        // multi dim array
+        for (var i=0; i<newlen; i++) a[i]=setLength(src?src[i]:null,argNo+1);
+      }
+      return a;
+    }
+    return setLength(arr,2);
+  },
+
+  /*arrayChgLength: function(arr,defaultvalue,newlength){
     // multi dim: (arr,defaultvalue,dim1,dim2,...)
     if (arr == null) arr = [];
     var p = arguments;
@@ -828,7 +859,7 @@ var rtl = {
       return a;
     }
     return setLength(arr,2);
-  },
+  },*/
 
   arrayEq: function(a,b){
     if (a===null) return b===null;