Jelajahi Sumber

pastojs: export variable

mattias 3 tahun lalu
induk
melakukan
540fd5e58d
2 mengubah file dengan 122 tambahan dan 17 penghapusan
  1. 100 15
      packages/pastojs/src/fppas2js.pp
  2. 22 2
      packages/pastojs/tests/tcmodules.pas

+ 100 - 15
packages/pastojs/src/fppas2js.pp

@@ -677,6 +677,7 @@ type
     pbivnMessageInt,
     pbivnMessageInt,
     pbivnMessageStr,
     pbivnMessageStr,
     pbivnLibrary, // library
     pbivnLibrary, // library
+    pbivnLibraryVars, // library vars
     pbivnLocalModuleRef,
     pbivnLocalModuleRef,
     pbivnLocalProcRef,
     pbivnLocalProcRef,
     pbivnLocalTypeRef,
     pbivnLocalTypeRef,
@@ -865,6 +866,7 @@ const
     '$msgint', // pbivnMessageInt
     '$msgint', // pbivnMessageInt
     '$msgstr', // pbivnMessageStr
     '$msgstr', // pbivnMessageStr
     'library', //  pbivnLibrary  pas.library
     'library', //  pbivnLibrary  pas.library
+    'vars', //  pbivnLibraryVars  vars
     '$lm', // pbivnLocalModuleRef
     '$lm', // pbivnLocalModuleRef
     '$lp', // pbivnLocalProcRef
     '$lp', // pbivnLocalProcRef
     '$lt', // pbivnLocalTypeRef
     '$lt', // pbivnLocalTypeRef
@@ -2049,6 +2051,7 @@ type
       AContext: TConvertContext): TJSElement; virtual;
       AContext: TConvertContext): TJSElement; virtual;
     Function CreateCallRTLFreeLoc(Setter, Getter: TJSElement; Src: TPasElement): TJSElement; virtual;
     Function CreateCallRTLFreeLoc(Setter, Getter: TJSElement; Src: TPasElement): TJSElement; virtual;
     Function CreateDotSplit(El: TPasElement; Expr: TJSElement): TJSElement; virtual;
     Function CreateDotSplit(El: TPasElement; Expr: TJSElement): TJSElement; virtual;
+    Function CreateExportStatement(VarType: TJSVarType; AliasName: TJSString; InitJS: TJSElement; PosEl: TPasElement): TJSExportStatement; virtual;
     Function CreatePrecompiledJS(El: TJSElement): string; virtual;
     Function CreatePrecompiledJS(El: TJSElement): string; virtual;
     Procedure AddRTLVersionCheck(FuncContext: TFunctionContext; PosEl: TPasElement);
     Procedure AddRTLVersionCheck(FuncContext: TFunctionContext; PosEl: TPasElement);
     // JS literals
     // JS literals
@@ -4913,6 +4916,7 @@ procedure TPas2JSResolver.FinishExportSymbol(El: TPasExportSymbol);
 var
 var
   ResolvedEl: TPasResolverResult;
   ResolvedEl: TPasResolverResult;
   DeclEl: TPasElement;
   DeclEl: TPasElement;
+  C: TClass;
   Proc: TPasProcedure;
   Proc: TPasProcedure;
   V: TPasVariable;
   V: TPasVariable;
 begin
 begin
@@ -4933,6 +4937,7 @@ begin
       sSymbolCannotBeExportedFromALibrary,[],El);
       sSymbolCannotBeExportedFromALibrary,[],El);
   if DeclEl is TPasResultElement then
   if DeclEl is TPasResultElement then
     DeclEl:=DeclEl.Parent.Parent;
     DeclEl:=DeclEl.Parent.Parent;
+  C:=DeclEl.ClassType;
 
 
   if DeclEl.Parent=nil then
   if DeclEl.Parent=nil then
     RaiseMsg(20220206142534,nSymbolCannotBeExportedFromALibrary,
     RaiseMsg(20220206142534,nSymbolCannotBeExportedFromALibrary,
@@ -4950,14 +4955,14 @@ begin
     RaiseMsg(20211022224239,nSymbolCannotBeExportedFromALibrary,
     RaiseMsg(20211022224239,nSymbolCannotBeExportedFromALibrary,
       sSymbolCannotBeExportedFromALibrary,[],El);
       sSymbolCannotBeExportedFromALibrary,[],El);
 
 
-  if DeclEl is TPasProcedure then
+  if C.InheritsFrom(TPasProcedure) then
     begin
     begin
     Proc:=TPasProcedure(DeclEl);
     Proc:=TPasProcedure(DeclEl);
     if Proc.IsExternal or Proc.IsAbstract then
     if Proc.IsExternal or Proc.IsAbstract then
       RaiseMsg(20211021225630,nSymbolCannotBeExportedFromALibrary,
       RaiseMsg(20211021225630,nSymbolCannotBeExportedFromALibrary,
         sSymbolCannotBeExportedFromALibrary,[],El);
         sSymbolCannotBeExportedFromALibrary,[],El);
     end
     end
-  else if DeclEl is TPasVariable then
+  else if (C=TPasVariable) or (C=TPasConst) then
     begin
     begin
     V:=TPasVariable(DeclEl);
     V:=TPasVariable(DeclEl);
     if vmExternal in V.VarModifiers then
     if vmExternal in V.VarModifiers then
@@ -4965,8 +4970,13 @@ begin
         sSymbolCannotBeExportedFromALibrary,[],El);
         sSymbolCannotBeExportedFromALibrary,[],El);
     end
     end
   else
   else
+    begin
+    {$IFDEF VerbosePas2JS}
+    writeln('TPas2JSResolver.FinishExportSymbol ',GetObjPath(El));
+    {$ENDIF}
     RaiseMsg(20210106223621,nSymbolCannotBeExportedFromALibrary,
     RaiseMsg(20210106223621,nSymbolCannotBeExportedFromALibrary,
       sSymbolCannotBeExportedFromALibrary,[],El);
       sSymbolCannotBeExportedFromALibrary,[],El);
+    end;
 end;
 end;
 
 
 procedure TPas2JSResolver.FindCreatorArrayOfConst(Args: TFPList;
 procedure TPas2JSResolver.FindCreatorArrayOfConst(Args: TFPList;
@@ -18050,10 +18060,27 @@ procedure TPasToJSConverter.CreateExportsSection(El: TPasLibrary;
 //       set: function(v){pas.unit1.Var1 = v;},
 //       set: function(v){pas.unit1.Var1 = v;},
 //     }
 //     }
 //   });
 //   });
+
+  procedure AddPropFunction(ObjLit: TJSObjectLiteral; AliasName, Arg1: TJSString;
+    BodyJS: TJSElement; PosEl: TPasElement);
+  var
+    Lit: TJSObjectLiteralElement;
+    FuncSt: TJSFunctionDeclarationStatement;
+  begin
+    Lit:=ObjLit.Elements.AddElement;
+    Lit.Name:=AliasName;
+    FuncSt:=CreateFunctionSt(PosEl,true,false);
+    Lit.Expr:=FuncSt;
+    if Arg1<>'' then
+      FuncSt.AFunction.TypedParams.AddParam(Arg1);
+    FuncSt.AFunction.Body.A:=BodyJS;
+  end;
+
+
 var
 var
   ExportSymbols: TFPList;
   ExportSymbols: TFPList;
   aResolver: TPas2JSResolver;
   aResolver: TPas2JSResolver;
-  ExpSt: TJSExportStatement;
+  VarsExpSt, ExpSt: TJSExportStatement;
   i: Integer;
   i: Integer;
   Symb: TPasExportSymbol;
   Symb: TPasExportSymbol;
   Ref: TResolvedReference;
   Ref: TResolvedReference;
@@ -18062,13 +18089,17 @@ var
   EvalValue: TResEvalValue;
   EvalValue: TResEvalValue;
   Decl: TPasElement;
   Decl: TPasElement;
   ResolvedEl: TPasResolverResult;
   ResolvedEl: TPasResolverResult;
-  VarSt: TJSVariableStatement;
-  VarDecl: TJSVarDeclaration;
+  Call: TJSCallExpression;
+  VarsObjLit, VarObjLit: TJSObjectLiteral;
+  Lit, SubLit: TJSObjectLiteralElement;
+  RetSt: TJSReturnStatement;
+  AssignSt: TJSSimpleAssignStatement;
 begin
 begin
   ExportSymbols:=El.LibrarySection.ExportSymbols;
   ExportSymbols:=El.LibrarySection.ExportSymbols;
   if ExportSymbols.Count=0 then exit;
   if ExportSymbols.Count=0 then exit;
   aResolver:=AContext.Resolver;
   aResolver:=AContext.Resolver;
 
 
+  VarsExpSt:=nil;
   for i:=0 to ExportSymbols.Count-1 do
   for i:=0 to ExportSymbols.Count-1 do
     begin
     begin
     Symb:=TObject(ExportSymbols[i]) as TPasExportSymbol;
     Symb:=TObject(ExportSymbols[i]) as TPasExportSymbol;
@@ -18114,16 +18145,53 @@ begin
       AliasName:=TJSString(Decl.Name);
       AliasName:=TJSString(Decl.Name);
       end;
       end;
 
 
-    // "export const AliasName = NamePath;"
-    ExpSt:=TJSExportStatement(CreateElement(TJSExportStatement,Symb));
-    AddToSourceElements(Src,ExpSt);
-    VarSt:=TJSVariableStatement(CreateElement(TJSVariableStatement,Symb));
-    ExpSt.Declaration:=VarSt;
-    VarSt.VarType:=vtConst;
-    VarDecl:=TJSVarDeclaration(CreateElement(TJSVarDeclaration,Symb));
-    VarSt.VarDecl:=VarDecl;
-    VarDecl.Name:=AliasName;
-    VarDecl.Init:=CreatePrimitiveDotExpr(NamePath,Symb);
+    if Decl.ClassType=TPasVariable then
+      begin
+      if VarsExpSt=nil then
+        begin
+        // add "export const vars = {};"
+        VarsExpSt:=CreateExportStatement(vtConst,
+                   TJSString(GetBIName(pbivnLibraryVars)),
+                   TJSObjectLiteral(CreateElement(TJSObjectLiteral,Symb)),Symb);
+        AddToSourceElements(Src,VarsExpSt);
+
+        // add "Object.defineProperties(vars, { });"
+        Call:=CreateCallExpression(Symb);
+        AddToSourceElements(Src,Call);
+        Call.Expr:=CreatePrimitiveDotExpr('Object.defineProperties',Symb);
+        Call.AddArg(CreatePrimitiveDotExpr(GetBIName(pbivnLibraryVars),Symb));
+        VarsObjLit:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,Symb));
+        Call.AddArg(VarsObjLit);
+        end;
+      // add "Var1: {},"
+      Lit:=VarsObjLit.Elements.AddElement;
+      Lit.Name:=AliasName;
+      VarObjLit:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,Symb));
+      Lit.Expr:=VarObjLit;
+
+      // enumerable: true
+      SubLit:=VarObjLit.Elements.AddElement;
+      SubLit.Name:='enumerable';
+      SubLit.Expr:=CreateLiteralBoolean(Symb,true);
+
+      //       get: function(){return pas.unit1.Var1;},
+      RetSt:=TJSReturnStatement(CreateElement(TJSReturnStatement,Symb));
+      RetSt.Expr:=CreatePrimitiveDotExpr(NamePath,Symb);
+      AddPropFunction(VarObjLit,'get','',RetSt,Symb);
+
+      //       set: function(v){pas.unit1.Var1 = v;},
+      AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,Symb));
+      AssignSt.LHS:=CreatePrimitiveDotExpr(NamePath,Symb);
+      AssignSt.Expr:=CreatePrimitiveDotExpr(TempRefObjSetterArgName,Symb);
+      AddPropFunction(VarObjLit,'set',TJSString(TempRefObjSetterArgName),AssignSt,Symb);
+
+      end
+    else
+      begin
+      // "export const AliasName = NamePath;"
+      ExpSt:=CreateExportStatement(vtConst,AliasName,CreatePrimitiveDotExpr(NamePath,Symb),Symb);
+      AddToSourceElements(Src,ExpSt);
+      end;
     end;
     end;
 end;
 end;
 
 
@@ -20087,6 +20155,23 @@ begin
   Result:=Call;
   Result:=Call;
 end;
 end;
 
 
+function TPasToJSConverter.CreateExportStatement(VarType: TJSVarType;
+  AliasName: TJSString; InitJS: TJSElement; PosEl: TPasElement
+  ): TJSExportStatement;
+var
+  VarSt: TJSVariableStatement;
+  VarDecl: TJSVarDeclaration;
+begin
+  Result:=TJSExportStatement(CreateElement(TJSExportStatement,PosEl));
+  VarSt:=TJSVariableStatement(CreateElement(TJSVariableStatement,PosEl));
+  Result.Declaration:=VarSt;
+  VarSt.VarType:=VarType;
+  VarDecl:=TJSVarDeclaration(CreateElement(TJSVarDeclaration,PosEl));
+  VarSt.VarDecl:=VarDecl;
+  VarDecl.Name:=AliasName;
+  VarDecl.Init:=InitJS;
+end;
+
 function TPasToJSConverter.CreatePrecompiledJS(El: TJSElement): string;
 function TPasToJSConverter.CreatePrecompiledJS(El: TJSElement): string;
 var
 var
   aWriter: TBufferWriter;
   aWriter: TBufferWriter;

+ 22 - 2
packages/pastojs/tests/tcmodules.pas

@@ -34838,7 +34838,7 @@ begin
   Add([
   Add([
   'var Wing: word;',
   'var Wing: word;',
   'exports',
   'exports',
-  '  Wing;',
+  '  Wing, wing name ''BirdArm'';',
   '']);
   '']);
   ConvertLibrary;
   ConvertLibrary;
   CheckFullSource('TestLibrary_ExportVar',
   CheckFullSource('TestLibrary_ExportVar',
@@ -34850,7 +34850,27 @@ begin
     '  };',
     '  };',
     '});',
     '});',
     'rtl.run("library");',
     'rtl.run("library");',
-    'export const Wing = pas.library.Wing;',
+    'export const vars = {};',
+    'Object.defineProperties(vars, {',
+    '  Wing: {',
+    '      enumerable: true,',
+    '      get: function () {',
+    '          return pas.library.Wing;',
+    '        },',
+    '      set: function (v) {',
+    '          pas.library.Wing = v;',
+    '        }',
+    '    },',
+    '  BirdArm: {',
+    '      enumerable: true,',
+    '      get: function () {',
+    '          return pas.library.Wing;',
+    '        },',
+    '      set: function (v) {',
+    '          pas.library.Wing = v;',
+    '        }',
+    '    }',
+    '});',
     '']));
     '']));
   CheckResolverUnexpectedHints();
   CheckResolverUnexpectedHints();
 end;
 end;