Browse Source

pastojs: for e in TArrEnum do, for VT in TArrOfT do

git-svn-id: trunk@37768 -
Mattias Gaertner 7 years ago
parent
commit
7324fda194

+ 92 - 18
packages/pastojs/src/fppas2js.pp

@@ -10574,11 +10574,13 @@ function TPasToJSConverter.ConvertForStatement(El: TPasImplForLoop;
 type
   TInKind = (
     ikNone,
+    ikEnum,
     ikChar,
-    ikString
+    ikString,
+    ikArray
   );
 
-  function ConvExpr(Expr: TPasExpr): TJSElement;
+  function ConvExpr(Expr: TPasExpr): TJSElement; overload;
   var
     ResolvedEl: TPasResolverResult;
     JSUnaryPlus: TJSUnaryPlusExpression;
@@ -10621,7 +10623,7 @@ type
       end;
   end;
 
-  function GetOrd(Value: TResEvalValue; ErrorEl: TPasElement): MaxPrecInt;
+  function GetOrd(Value: TResEvalValue; ErrorEl: TPasElement): MaxPrecInt; overload;
   var
     OrdValue: TResEvalValue;
   begin
@@ -10637,6 +10639,14 @@ type
       ReleaseEvalValue(OrdValue);
   end;
 
+  function GetEnumValue(EnumType: TPasEnumType; Int: MaxPrecInt): TResEvalValue; overload;
+  begin
+    if (coEnumNumbers in Options) or (Int<0) or (Int>=EnumType.Values.Count) then
+      Result:=TResEvalInt.CreateValue(Int)
+    else
+      Result:=TResEvalEnum.CreateValue(Int,TObject(EnumType.Values[Int]) as TPasEnumValue);
+  end;
+
 var
   ResolvedVar, ResolvedIn: TPasResolverResult;
   StartValue, EndValue, InValue: TResEvalValue;
@@ -10645,6 +10655,9 @@ var
   InKind: TInKind;
 
   procedure InitWithResolver;
+  var
+    EnumType: TPasEnumType;
+    TypeEl: TPasType;
   begin
     AContext.Resolver.ComputeElement(El.VariableName,ResolvedVar,[rcNoImplicitProc]);
     if not (ResolvedVar.IdentEl is TPasVariable) then
@@ -10664,6 +10677,18 @@ var
       HasInVar:=true;
       AContext.Resolver.ComputeElement(El.StartExpr,ResolvedIn,[]);
       InValue:=AContext.Resolver.Eval(El.StartExpr,[],false);
+      if InValue=nil then
+        begin
+        if ResolvedIn.IdentEl is TPasType then
+          begin
+          TypeEl:=AContext.Resolver.ResolveAliasType(TPasType(ResolvedIn.IdentEl));
+          if TypeEl is TPasArrayType then
+            begin
+            if length(TPasArrayType(TypeEl).Ranges)=1 then
+              InValue:=AContext.Resolver.Eval(TPasArrayType(TypeEl).Ranges[0],[refConst]);
+            end;
+          end;
+        end;
       if InValue<>nil then
         begin
         // for in <constant> do
@@ -10687,7 +10712,18 @@ var
           EndInt:=TResEvalRangeInt(InValue).RangeEnd;
           HasInVar:=false;
           case TResEvalRangeInt(InValue).ElKind of
-          revskChar: InKind:=ikChar;
+          revskEnum:
+            if coEnumNumbers in Options then
+              InKind:=ikNone
+            else
+              begin
+              InKind:=ikEnum;
+              EnumType:=TPasEnumType(TResEvalRangeInt(InValue).ElType);
+              StartValue:=GetEnumValue(EnumType,StartInt);
+              EndValue:=GetEnumValue(EnumType,EndInt);
+              end;
+          revskChar:
+            InKind:=ikChar;
           else
             {$IFDEF VerbosePas2JS}
             writeln('TPasToJSConverter.ConvertForStatement ',GetObjName(El.StartExpr),' InValue=',InValue.AsDebugString);
@@ -10707,21 +10743,40 @@ var
         // for v in <variable> do
         if ResolvedIn.BaseType in btAllStrings then
           begin
-          StartInt:=0;
           InKind:=ikString;
+          StartInt:=0;
           end
         else if ResolvedIn.BaseType=btContext then
           begin
-          {$IFDEF VerbosePas2JS}
-          writeln('TPasToJSConverter.ConvertForStatement ',GetObjName(El.StartExpr),' StartValue=',StartValue.AsDebugString);
-          {$ENDIF}
-          RaiseNotSupported(El.StartExpr,AContext,20171113012226);
+          TypeEl:=AContext.Resolver.ResolveAliasType(ResolvedIn.TypeEl);
+          if TypeEl is TPasArrayType then
+            begin
+            if length(TPasArrayType(TypeEl).Ranges)<=1 then
+              begin
+              InKind:=ikArray;
+              StartInt:=0;
+              end
+            else
+              begin
+              {$IFDEF VerbosePas2JS}
+              writeln('TPasToJSConverter.ConvertForStatement.InitWithResolver ResolvedIn=',GetResolverResultDbg(ResolvedIn),' length(Ranges)=',length(TPasArrayType(TypeEl).Ranges));
+              {$ENDIF}
+              RaiseNotSupported(El.StartExpr,AContext,20171220010147);
+              end;
+            end
+          else
+            begin
+            {$IFDEF VerbosePas2JS}
+            writeln('TPasToJSConverter.ConvertForStatement.InitWithResolver El.StartExpr=',GetObjName(El.StartExpr),' ResolvedIn=',GetResolverResultDbg(ResolvedIn));
+            {$ENDIF}
+            RaiseNotSupported(El.StartExpr,AContext,20171113012226);
+            end;
           end;
         end
       else
         begin
         {$IFDEF VerbosePas2JS}
-        writeln('InitWithResolver ResolvedIn=',GetResolverResultDbg(ResolvedIn));
+        writeln('TPasToJSConverter.ConvertForStatement.InitWithResolver ResolvedIn=',GetResolverResultDbg(ResolvedIn));
         {$ENDIF}
         RaiseNotSupported(El.StartExpr,AContext,20171112195629);
         end;
@@ -10761,6 +10816,7 @@ Var
   Statements, V: TJSElement;
   NotEqual: TJSEqualityExpressionNE;
   Call: TJSCallExpression;
+  Br: TJSBracketMemberExpression;
 begin
   Result:=Nil;
   if AContext.Access<>caRead then
@@ -10856,7 +10912,7 @@ begin
           V:=CreateLiteralNumber(PosEl,StartInt)
         else if El.LoopType=ltIn then
           case InKind of
-          ikChar, ikString: V:=CreateLiteralNumber(PosEl,StartInt);
+          ikChar, ikString, ikArray: V:=CreateLiteralNumber(PosEl,StartInt);
           end
         else
           V:=ConvExpr(El.StartExpr);
@@ -10876,11 +10932,21 @@ begin
           ikChar: V:=CreateLiteralNumber(PosEl,EndInt);
           ikString:
             begin
-            // add "$end=$in.length-1"
+            // add "$in.length-1"
             V:=TJSAdditiveExpressionMinus(CreateElement(TJSAdditiveExpressionMinus,PosEl));
             TJSAdditiveExpressionMinus(V).A:=CreatePrimitiveDotExpr(CurInVarName+'.length',PosEl);
             TJSAdditiveExpressionMinus(V).B:=CreateLiteralNumber(PosEl,1);
             end;
+          ikArray:
+            begin
+            // add "rtl.length($in)-1"
+            Call:=CreateCallExpression(PosEl);
+            Call.Expr:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[pbifnArray_Length],PosEl);
+            Call.AddArg(CreatePrimitiveDotExpr(CurInVarName,PosEl));
+            V:=TJSAdditiveExpressionMinus(CreateElement(TJSAdditiveExpressionMinus,PosEl));
+            TJSAdditiveExpressionMinus(V).A:=Call;
+            TJSAdditiveExpressionMinus(V).B:=CreateLiteralNumber(PosEl,1);
+            end
           else
             RaiseNotSupported(El.StartExpr,AContext,20171113015445);
           end
@@ -10959,7 +11025,15 @@ begin
               CreatePrimitiveDotExpr('charAt',PosEl));
             Call.AddArg(SimpleAss.Expr);
             SimpleAss.Expr:=Call;
-            end
+            end;
+          ikArray:
+            begin
+            // $in[$l]
+            Br:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,PosEl));
+            Br.MExpr:=CreatePrimitiveDotExpr(CurInVarName,El.StartExpr);
+            Br.Name:=SimpleAss.Expr;
+            SimpleAss.Expr:=Br;
+            end;
           else
             {$IFDEF VerbosePas2JS}
             writeln('TPasToJSConverter.ConvertForStatement InKind=',InKind);
@@ -11351,16 +11425,16 @@ end;
 procedure TPasToJSConverter.AddToVarStatement(VarStat: TJSVariableStatement;
   Add: TJSElement; Src: TPasElement);
 var
-  Comma: TJSCommaExpression;
+  List: TJSVariableDeclarationList;
 begin
   if VarStat.A=nil then
     VarStat.A:=Add
   else
     begin
-    Comma:=TJSCommaExpression(CreateElement(TJSCommaExpression,Src));
-    Comma.A:=VarStat.A;
-    Comma.B:=Add;
-    VarStat.A:=Comma;
+    List:=TJSVariableDeclarationList(CreateElement(TJSVariableDeclarationList,Src));
+    List.A:=VarStat.A;
+    List.B:=Add;
+    VarStat.A:=List;
     end;
 end;
 

+ 52 - 3
packages/pastojs/tests/tcmodules.pas

@@ -269,6 +269,7 @@ type
     Procedure TestEnum_Functions;
     Procedure TestEnum_AsParams;
     Procedure TestEnumRange_Array;
+    Procedure TestEnum_ForIn;
     Procedure TestSet;
     Procedure TestSet_Operators;
     Procedure TestSet_Operator_In;
@@ -292,7 +293,7 @@ type
     Procedure TestFunctionInt;
     Procedure TestFunctionString;
     Procedure TestForLoop;
-    Procedure TestForLoopInFunction;
+    Procedure TestForLoopInsideFunction;
     Procedure TestForLoop_ReadVarAfter;
     Procedure TestForLoop_Nested;
     Procedure TestRepeatUntil;
@@ -3256,6 +3257,54 @@ begin
     '']));
 end;
 
+procedure TTestModule.TestEnum_ForIn;
+begin
+  StartProgram(false);
+  Add([
+  'type',
+  '  TEnum = (Red, Green, Blue);',
+  '  TEnumRg = green..blue;',
+  '  TArr = array[TEnum] of byte;',
+  '  TArrRg = array[TEnumRg] of byte;',
+  'var',
+  '  e: TEnum;',
+  '  a1: TArr = (3,4,5);',
+  '  a2: TArrRg = (11,12);',
+  '  b: byte;',
+  'begin',
+  '  for e in TEnum do ;',
+  '  for e in TEnumRg do ;',
+  '  for e in TArr do ;',
+  '  for e in TArrRg do ;',
+  '  for b in a1 do ;',
+  '  for b in a2 do ;',
+  '']);
+  ConvertProgram;
+  CheckSource('TestEnum_ForIn',
+    LinesToStr([ // statements
+    'this.TEnum = {',
+    '  "0": "Red",',
+    '  Red: 0,',
+    '  "1": "Green",',
+    '  Green: 1,',
+    '  "2": "Blue",',
+    '  Blue: 2',
+    '};',
+    'this.e = 0;',
+    'this.a1 = [3, 4, 5];',
+    'this.a2 = [11, 12];',
+    'this.b = 0;',
+    '']),
+    LinesToStr([
+    '  for ($mod.e = 0; $mod.e <= 2; $mod.e++) ;',
+    '  for ($mod.e = 1; $mod.e <= 2; $mod.e++) ;',
+    '  for ($mod.e = 0; $mod.e <= 2; $mod.e++) ;',
+    '  for ($mod.e = 1; $mod.e <= 2; $mod.e++) ;',
+    '  for (var $in1 = $mod.a1, $l2 = 0, $end3 = rtl.length($in1) - 1; $l2 <= $end3; $l2++) $mod.b = $in1[$l2];',
+    '  for (var $in4 = $mod.a2, $l5 = 0, $end6 = rtl.length($in4) - 1; $l5 <= $end6; $l5++) $mod.b = $in4[$l5];',
+    '']));
+end;
+
 procedure TTestModule.TestSet;
 begin
   StartProgram(false);
@@ -4790,7 +4839,7 @@ begin
     '']));
 end;
 
-procedure TTestModule.TestForLoopInFunction;
+procedure TTestModule.TestForLoopInsideFunction;
 begin
   StartProgram(false);
   Add('function SumNumbers(Count: longint): longint;');
@@ -4806,7 +4855,7 @@ begin
   Add('begin');
   Add('  sumnumbers(3);');
   ConvertProgram;
-  CheckSource('TestForLoopInFunction',
+  CheckSource('TestForLoopInsideFunction',
     LinesToStr([ // statements
     'this.SumNumbers = function (Count) {',
     '  var Result = 0;',

+ 5 - 4
packages/pastojs/tests/testpas2js.lpi

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <CONFIG>
   <ProjectOptions>
-    <Version Value="10"/>
+    <Version Value="11"/>
     <General>
       <SessionStorage Value="InProjectDir"/>
       <MainUnit Value="0"/>
@@ -19,9 +19,10 @@
       <Version Value="2"/>
     </PublishOptions>
     <RunParams>
-      <local>
-        <FormatVersion Value="1"/>
-      </local>
+      <FormatVersion Value="2"/>
+      <Modes Count="1">
+        <Mode0 Name="default"/>
+      </Modes>
     </RunParams>
     <RequiredPackages Count="2">
       <Item1>