Procházet zdrojové kódy

pastojs: generate elevated local types as vars

git-svn-id: trunk@40722 -
Mattias Gaertner před 6 roky
rodič
revize
9d079bfb97
2 změnil soubory, kde provedl 140 přidání a 66 odebrání
  1. 130 59
      packages/pastojs/src/fppas2js.pp
  2. 10 7
      packages/pastojs/tests/tcmodules.pas

+ 130 - 59
packages/pastojs/src/fppas2js.pp

@@ -12625,6 +12625,7 @@ var
   OrdType: TOrdType;
   Src: TJSSourceElements;
   ProcScope: TPas2JSProcedureScope;
+  VarSt: TJSVariableStatement;
 begin
   Result:=nil;
   for i:=0 to El.Values.Count-1 do
@@ -12637,6 +12638,9 @@ begin
   ok:=false;
   ObjectContect:=nil;
   Src:=nil;
+  Call:=nil;
+  VarSt:=nil;
+  ProcScope:=nil;
   try
     Obj:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
     if AContext is TObjectContext then
@@ -12651,21 +12655,22 @@ begin
     else if El.Parent is TProcedureBody then
       begin
       // add 'var TypeName = {}'
-      if (AContext<>nil) and (AContext.JSElement is TJSSourceElements) then
-        Src:=TJSSourceElements(AContext.JSElement)
+      VarSt:=CreateVarStatement(TransformVariableName(El,AContext),Obj,El);
+      if AContext.JSElement is TJSSourceElements then
+        begin
+        Src:=TJSSourceElements(AContext.JSElement);
+        AddToSourceElements(Src,VarSt); // keep Result=nil
+        end
       else
-        Result:=CreateVarStatement(TransformVariableName(El,AContext),Obj,El);
-      end;
-    if Result=nil then
+        Result:=VarSt;
+      end
+    else
       begin
       // add 'this.TypeName = {}'
       AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
       AssignSt.LHS:=CreateSubDeclNameExpr(El,AContext);
       AssignSt.Expr:=Obj;
-      if Src<>nil then
-        AddToSourceElements(Src,AssignSt) // keep Result=nil
-      else
-        Result:=AssignSt;
+      Result:=AssignSt;
       end;
 
     ObjectContect:=TObjectContext.Create(El,Obj,AContext);
@@ -12683,21 +12688,22 @@ begin
       ObjLit.Expr:=CreateLiteralNumber(El,i);
       end;
 
+    if Src<>nil then
+      begin
+      // store precompiled enum type in proc
+      ProcScope:=GetImplJSProcScope(El,Src,AContext);
+      if ProcScope<>nil then
+        ProcScope.AddGlobalJS(CreatePrecompiledJS(VarSt));
+      end;
+
     if HasTypeInfo(El,AContext) then
       begin
       // create typeinfo
       if not (AContext is TFunctionContext) then
         RaiseNotSupported(El,AContext,20170411210045,'typeinfo');
-      if Src<>nil then
-        RaiseNotSupported(El,AContext,20181231005005);
-      // create statement list
-      List:=TJSStatementList(CreateElement(TJSStatementList,El));
-      List.A:=Result;
-      Result:=List;
       OrdType:=GetOrdType(0,TMaxPrecInt(El.Values.Count)-1,El);
       // module.$rtti.$TIEnum("TMyEnum",{...});
       Call:=CreateRTTINewType(El,GetBIName(pbifnRTTINewEnum),false,AContext,TIObj);
-      List.B:=Call;
       // add  minvalue: number
       TIProp:=TIObj.Elements.AddElement;
       TIProp.Name:=TJSString(GetBIName(pbivnRTTIInt_MinValue));
@@ -12714,15 +12720,30 @@ begin
       TIProp:=TIObj.Elements.AddElement;
       TIProp.Name:=TJSString(GetBIName(pbivnRTTIEnum_EnumType));
       TIProp.Expr:=CreateSubDeclNameExpr(El,AContext);
-      end;
 
-    // store precompiled enum type in proc
-    ProcScope:=GetImplJSProcScope(El,Src,AContext);
-    if ProcScope<>nil then
-      ProcScope.AddGlobalJS(CreatePrecompiledJS(AssignSt));
+      if Src<>nil then
+        begin
+        // add to source elements
+        AddToSourceElements(Src,Call);
+        if ProcScope<>nil then
+          ProcScope.AddGlobalJS(CreatePrecompiledJS(Call));
+        end
+      else if Result=nil then
+        RaiseNotSupported(El,AContext,20190101130432)
+      else
+        begin
+        // create statement list
+        List:=TJSStatementList(CreateElement(TJSStatementList,El));
+        List.A:=Result;
+        Result:=List;
+        List.B:=Call;
+        end;
+      Call:=nil;
+      end;
 
     ok:=true;
   finally
+    Call.Free;
     ObjectContect.Free;
     if not ok then
       FreeAndNil(Result);
@@ -12996,9 +13017,22 @@ const
   CloneArrName = 'a';
   CloneResultName = 'r';
   CloneRunName = 'i';
+var
+  ProcScope: TPas2JSProcedureScope;
+  Src: TJSSourceElements;
+
+  procedure StorePrecompiledJS(JS: TJSElement);
+  begin
+    // store precompiled enum type in proc
+    if ProcScope=nil then
+      ProcScope:=GetImplJSProcScope(El,Src,AContext);
+    if ProcScope<>nil then
+      ProcScope.AddGlobalJS(CreatePrecompiledJS(JS));
+  end;
+
 var
   AssignSt: TJSSimpleAssignStatement;
-  CallName: String;
+  CallName, ArrName: String;
   Obj: TJSObjectLiteral;
   Prop: TJSObjectLiteralElement;
   ArrLit: TJSArrayLiteral;
@@ -13010,15 +13044,14 @@ var
   RgLen, RangeEnd: TMaxPrecInt;
   List: TJSStatementList;
   Func: TJSFunctionDeclarationStatement;
-  BodySrc, Src: TJSSourceElements;
+  BodySrc: TJSSourceElements;
   VarSt: TJSVariableStatement;
   ForLoop: TJSForStatement;
   ExprLT: TJSRelationalExpressionLT;
   PlusPlus: TJSUnaryPostPlusPlusExpression;
   BracketEx: TJSBracketMemberExpression;
-  CloneEl: TJSElement;
+  ArraySt, CloneEl: TJSElement;
   ReturnSt: TJSReturnStatement;
-  ProcScope: TPas2JSProcedureScope;
 begin
   Result:=nil;
   if El.PackMode<>pmNone then
@@ -13028,8 +13061,9 @@ begin
   writeln('TPasToJSConverter.ConvertArrayType ',GetObjName(El));
   {$ENDIF}
 
+  ProcScope:=nil;
   Src:=nil;
-  if (AContext<>nil) and (AContext.JSElement is TJSSourceElements) then
+  if AContext.JSElement is TJSSourceElements then
     Src:=TJSSourceElements(AContext.JSElement);
 
   if AContext.Resolver.HasStaticArrayCloneFunc(El) then
@@ -13041,17 +13075,13 @@ begin
     //    return r;
     //  };
     BracketEx:=nil;
-    AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
+    AssignSt:=nil;
+    Func:=nil;
     try
-      // add 'this.TypeName = function(){}'
-      AssignSt.LHS:=CreateSubDeclNameExpr(El,
-                       El.Name+GetBIName(pbifnArray_Static_Clone),AContext);
-
       Index:=0;
       RangeEl:=El.Ranges[Index];
       // function(a){...
       Func:=CreateFunctionSt(El,true,true);
-      AssignSt.Expr:=Func;
       Func.AFunction.Params.Add(CloneArrName);
       BodySrc:=Func.AFunction.Body.A as TJSSourceElements;
       // var r = [];
@@ -13102,29 +13132,43 @@ begin
       AddToSourceElements(BodySrc,ReturnSt);
       ReturnSt.Expr:=CreatePrimitiveDotExpr(CloneResultName,El);
 
+      ArrName:=El.Name+GetBIName(pbifnArray_Static_Clone);
+      if El.Parent is TProcedureBody then
+        begin
+        // local array type (elevated to global)
+        // -> add 'var TypeName = function(){}'
+        ArraySt:=CreateVarStatement(ArrName,Func,El);
+        end
+      else
+        begin
+        // global array type
+        // -> add 'this.TypeName = function(){}'
+        AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
+        ArraySt:=AssignSt;
+        AssignSt.LHS:=CreateSubDeclNameExpr(El,ArrName,AContext);
+        AssignSt.Expr:=Func;
+        end;
+      Func:=nil;
+
       if Src<>nil then
-        AddToSourceElements(Src,AssignSt)
+        AddToSourceElements(Src,ArraySt)
       else
-        Result:=AssignSt;
+        Result:=ArraySt;
 
       // store precompiled enum type in proc
-      ProcScope:=GetImplJSProcScope(El,Src,AContext);
-      if ProcScope<>nil then
-        ProcScope.AddGlobalJS(CreatePrecompiledJS(AssignSt));
+      StorePrecompiledJS(ArraySt);
 
-      AssignSt:=nil;
+      ArraySt:=nil;
     finally
       BracketEx.Free;
-      AssignSt.Free;
+      Func.Free;
+      ArraySt.Free;
     end;
     end;
 
   if HasTypeInfo(El,AContext) then
     begin
 
-    if El.Parent is TProcedureBody then
-      RaiseNotSupported(El,AContext,20181231113427);
-
     // module.$rtti.$DynArray("name",{...})
     if length(El.Ranges)>0 then
       CallName:=GetBIName(pbifnRTTINewStaticArray)
@@ -13164,7 +13208,14 @@ begin
       Prop:=Obj.Elements.AddElement;
       Prop.Name:=TJSString(GetBIName(pbivnRTTIArray_ElType));
       Prop.Expr:=CreateTypeInfoRef(ElType,AContext,El);
-      if Result=nil then
+
+      if Src<>nil then
+        begin
+        AddToSourceElements(Src,Call);
+        // store precompiled rtti call in proc
+        StorePrecompiledJS(Call);
+        end
+      else if Result=nil then
         Result:=Call
       else
         begin
@@ -19754,6 +19805,7 @@ var
   BodyFirst, BodyLast, ListFirst: TJSStatementList;
   FuncContext: TFunctionContext;
   ObjLit: TJSObjectLiteral;
+  VarSt: TJSVariableStatement;
   IfSt: TJSIfStatement;
   Call, Call2: TJSCallExpression;
   ok: Boolean;
@@ -19765,23 +19817,33 @@ begin
   Result:=nil;
   FuncContext:=nil;
   ListFirst:=nil;
+  VarSt:=nil;
   Src:=nil;
+  ProcScope:=nil;
   ok:=false;
   try
     FDS:=CreateFunctionSt(El);
     FD:=FDS.AFunction;
     // types are stored in interface/implementation
-    if (El.Parent is TProcedureBody)
-        and (AContext.JSElement is TJSSourceElements) then
-      Src:=TJSSourceElements(AContext.JSElement);
-    // add 'this.TypeName = function(){}'
-    AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
-    AssignSt.LHS:=CreateSubDeclNameExpr(El,AContext);
-    AssignSt.Expr:=FDS;
-    if Src<>nil then
-      AddToSourceElements(Src,AssignSt) // keep Result=nil
+    if El.Parent is TProcedureBody then
+      begin
+      // add 'var TypeName = function(){}'
+      if AContext.JSElement is TJSSourceElements then
+        Src:=TJSSourceElements(AContext.JSElement);
+      VarSt:=CreateVarStatement(TransformVariableName(El,AContext),FDS,El);
+      if Src<>nil then
+        AddToSourceElements(Src,VarSt) // keep Result=nil
+      else
+        Result:=VarSt;
+      end
     else
+      begin
+      // add 'this.TypeName = function(){}'
+      AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
+      AssignSt.LHS:=CreateSubDeclNameExpr(El,AContext);
+      AssignSt.Expr:=FDS;
       Result:=AssignSt;
+      end;
 
     // add param s
     FD.Params.Add(SrcParamName);
@@ -19808,13 +19870,19 @@ begin
     if FD.Body.A=nil then
       FD.Body.A:=BodyFirst;
 
+    if Src<>nil then
+      begin
+      // store precompiled record type in proc
+      ProcScope:=GetImplJSProcScope(El,Src,AContext);
+      if ProcScope<>nil then
+        ProcScope.AddGlobalJS(CreatePrecompiledJS(VarSt));
+      end;
+
     if HasTypeInfo(El,AContext) then
       begin
       // add $rtti as second statement
       if not (AContext is TFunctionContext) then
         RaiseNotSupported(El,AContext,20170412120012);
-      if Src<>nil then
-        RaiseNotSupported(El,AContext,20181231005023);
 
       // module.$rtti.$Record("typename",{});
       Call:=CreateRTTINewType(El,GetBIName(pbifnRTTINewRecord),false,AContext,ObjLit);
@@ -19831,9 +19899,16 @@ begin
         Call:=Call2;
         AddRTTIFields(Call.Args);
         end;
+
       if Src<>nil then
+        begin
         // add Call to global statements
-        AddToSourceElements(Src,Call)
+        AddToSourceElements(Src,Call);
+        if ProcScope<>nil then
+          ProcScope.AddGlobalJS(CreatePrecompiledJS(VarSt));
+        end
+      else if Result=nil then
+        RaiseNotSupported(El,AContext,20190101130409)
       else
         begin
         // combine Result and Call into a statement list
@@ -19846,10 +19921,6 @@ begin
 
       end;
 
-    // store precompiled record type in proc
-    ProcScope:=GetImplJSProcScope(El,Src,AContext);
-    if ProcScope<>nil then
-      ProcScope.AddGlobalJS(CreatePrecompiledJS(Result));
     ok:=true;
   finally
     FuncContext.Free;

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

@@ -456,6 +456,7 @@ type
     // ToDo: TestAdvRecord_PropertyDefault;
     // ToDo: TestAdvRecord_InFunction;
     // ToDo: pcu: record default property
+    // ToDo: class constructor
 
     // classes
     Procedure TestClass_TObjectDefaultConstructor;
@@ -4764,7 +4765,7 @@ begin
   CheckSource('TestEnum_InFunction',
     LinesToStr([ // statements
     'this.TEnum = 3;',
-    'this.TEnum$1 = {',
+    'var TEnum$1 = {',
     '  "0":"Red",',
     '  Red:0,',
     '  "1":"Green",',
@@ -4772,7 +4773,7 @@ begin
     '  "2":"Blue",',
     '  Blue:2',
     '  };',
-    'this.TEnumSub = {',
+    'var TEnumSub = {',
     '  "0": "Left",',
     '  Left: 0,',
     '  "1": "Right",',
@@ -5487,13 +5488,13 @@ begin
     'this.TEnum = 3;',
     'this.TSetOfEnum = 4;',
     'this.TSetOfAno = 5;',
-    'this.TEnum$1 = {',
+    'var TEnum$1 = {',
     '  "0": "red",',
     '  red: 0,',
     '  "1": "blue",',
     '  blue: 1',
     '};',
-    'this.TSetOfAno$a = {',
+    'var TSetOfAno$a = {',
     '  "0": "up",',
     '  up: 0,',
     '  "1": "down",',
@@ -7953,7 +7954,7 @@ begin
     LinesToStr([ // statements
     'this.TArrayInt = 3;',
     'this.TArrayArrayInt = 4;',
-    'this.TArrayArrayInt$1$clone = function (a) {',
+    'var TArrayArrayInt$1$clone = function (a) {',
     '  var r = [];',
     '  for (var i = 0; i < 2; i++) r.push(a[i].slice(0));',
     '  return r;',
@@ -9886,7 +9887,7 @@ begin
   CheckSource('TestRecord_InFunction',
     LinesToStr([ // statements
     'this.TPoint = 3;',
-    'this.TPoint$1 = function (s) {',
+    'var TPoint$1 = function (s) {',
     '  if (s) {',
     '    this.x = s.x;',
     '    this.y = s.y;',
@@ -22004,13 +22005,14 @@ begin
   '  TPoint = record',
   '    x,y: integer;',
   '  end;',
+  'var p: TPoint;',
   'begin',
   'end;',
   'begin']);
   ConvertProgram;
   CheckSource('TestRTTI_LocalTypes',
     LinesToStr([ // statements
-    'this.TPoint = function(s) {',
+    'var TPoint = function(s) {',
     '  if (s) {',
     '    this.x = s.x;',
     '    this.y = s.y;',
@@ -22023,6 +22025,7 @@ begin
     '  };',
     '};',
     'this.DoIt = function () {',
+    '  var p = new TPoint();',
     '};',
     '']),
     LinesToStr([ // $mod.$main