Browse Source

pastojs: store and use precompiled initilialization JS, filer: write/read initialization JS+references

git-svn-id: trunk@38395 -
Mattias Gaertner 7 years ago
parent
commit
835c0f4a79
3 changed files with 272 additions and 146 deletions
  1. 44 25
      packages/pastojs/src/fppas2js.pp
  2. 164 98
      packages/pastojs/src/pas2jsfiler.pp
  3. 64 23
      packages/pastojs/tests/tcfiler.pas

+ 44 - 25
packages/pastojs/src/fppas2js.pp

@@ -816,6 +816,19 @@ type
   end;
   TPas2JsElementDataClass = class of TPas2JsElementData;
 
+  { TPas2JSModuleScope }
+
+  TPas2JSModuleScope = class(TPasModuleScope)
+  public
+  end;
+
+  { TPas2JSInitialFinalizationScope }
+
+  TPas2JSInitialFinalizationScope = class(TPasInitialFinalizationScope)
+  public
+    JS: string; // Option coStoreProcJS
+  end;
+
   { TPas2JSClassScope }
 
   TPas2JSClassScope = class(TPasClassScope)
@@ -828,9 +841,8 @@ type
   TPas2JSProcedureScope = class(TPasProcedureScope)
   public
     ResultVarName: string; // valid in implementation ProcScope, empty means use ResolverResultVar
-    // Option coStoreProcJS
-    BodyJS: string; // stored in ImplScope
-    GlobalJS: TStringList; // stored in ImplScope
+    BodyJS: string; // Option coStoreProcJS: stored in ImplScope
+    GlobalJS: TStringList; // Option coStoreProcJS: stored in ImplScope
     procedure AddGlobalJS(const JS: string);
     destructor Destroy; override;
   end;
@@ -1174,7 +1186,7 @@ type
     coUseStrict,   // insert 'use strict'
     coNoTypeInfo,  // do not generate RTTI
     coEliminateDeadCode,  // skip code that is never executed
-    coStoreProcJS  // store references to JS code in procscopes
+    coStoreImplJS  // store references to JS code in procscopes
     );
   TPasToJsConverterOptions = set of TPasToJsConverterOption;
 
@@ -1362,7 +1374,6 @@ type
     Function CreateCallRTLFreeLoc(Setter, Getter: TJSElement; Src: TPasElement): TJSElement; virtual;
     Function CreatePropertyGet(Prop: TPasProperty; Ref: TResolvedReference;
       AContext: TConvertContext; PosEl: TPasElement): TJSElement; virtual;
-    Procedure StorePrecompiledProcedure(ImplProc: TPasProcedure; JS: TJSElement); virtual;
     Function StorePrecompiledJS(El: TJSElement): string; virtual;
     // Statements
     Function ConvertImplBlockElements(El: TPasImplBlock; AContext: TConvertContext; NilIfEmpty: boolean): TJSElement; virtual;
@@ -3061,6 +3072,8 @@ begin
   StoreSrcColumns:=true;
   Options:=Options+DefaultPasResolverOptions;
   ScopeClass_Class:=TPas2JSClassScope;
+  ScopeClass_InitialFinalization:=TPas2JSInitialFinalizationScope;
+  ScopeClass_Module:=TPas2JSModuleScope;
   ScopeClass_Procedure:=TPas2JSProcedureScope;
   ScopeClass_WithExpr:=TPas2JSWithExprScope;
   for bt in [pbtJSValue] do
@@ -9683,10 +9696,10 @@ begin
     end;
     end;
 
-  if (coStoreProcJS in Options) and (AContext.Resolver<>nil) then
+  if (coStoreImplJS in Options) and (AContext.Resolver<>nil) then
     begin
     if AContext.Resolver.GetTopLvlProc(El)=El then
-      StorePrecompiledProcedure(ImplProc,Result);
+      ImplProcScope.BodyJS:=StorePrecompiledJS(Result);
     end;
 end;
 
@@ -9736,12 +9749,27 @@ function TPasToJSConverter.ConvertInitializationSection(
 var
   FDS: TJSFunctionDeclarationStatement;
   FunName: String;
-  IsMain, ok: Boolean;
+  IsMain: Boolean;
   AssignSt: TJSSimpleAssignStatement;
   FuncContext: TFunctionContext;
   Body: TJSFunctionBody;
+  Scope: TPas2JSInitialFinalizationScope;
+  Line, Col: integer;
+  Lit: TJSLiteral;
 begin
   // create: '$mod.$init=function(){}'
+  Result:=nil;
+  Scope:=TPas2JSInitialFinalizationScope(El.CustomData);
+
+  if Scope.JS<>'' then
+    begin
+    // precompiled JS
+    TPasResolver.UnmangleSourceLineNumber(El.Parent.SourceLinenumber,Line,Col);
+    Lit:=TJSLiteral.Create(Line,Col,El.Parent.SourceFilename);
+    Lit.Value.CustomValue:=UTF8Decode(Scope.JS);
+    Result:=Lit;
+    exit;
+    end;
 
   IsMain:=(El.Parent<>nil) and (El.Parent is TPasProgram);
   if IsMain then
@@ -9749,10 +9777,8 @@ begin
   else
     FunName:=FBuiltInNames[pbifnUnitInit];
 
-  AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
-  Result:=AssignSt;
   FuncContext:=nil;
-  ok:=false;
+  AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
   try
     AssignSt.LHS:=CreateMemberExpression([FBuiltInNames[pbivnModule],FunName]);
     FDS:=CreateFunctionSt(El,El.Elements.Count>0);
@@ -9765,11 +9791,15 @@ begin
       //   simply refer to $mod, so no need to set ThisPas here
       Body.A:=ConvertImplBlockElements(El,FuncContext,false);
       end;
-    ok:=true;
+    Result:=AssignSt;
   finally
     FuncContext.Free;
-    if not ok then FreeAndNil(Result);
+    if Result=nil then
+      AssignSt.Free;
   end;
+
+  if (coStoreImplJS in Options) and (AContext.Resolver<>nil) then
+    Scope.JS:=StorePrecompiledJS(Result);
 end;
 
 function TPasToJSConverter.ConvertFinalizationSection(El: TFinalizationSection;
@@ -11079,17 +11109,6 @@ begin
     end;
 end;
 
-procedure TPasToJSConverter.StorePrecompiledProcedure(ImplProc: TPasProcedure;
-  JS: TJSElement);
-var
-  ImplScope: TPas2JSProcedureScope;
-begin
-  ImplScope:=TPas2JSProcedureScope(ImplProc.CustomData);
-  if ImplScope.ImplProc<>nil then
-    RaiseInconsistency(20180228124545,ImplProc);
-  ImplScope.BodyJS:=StorePrecompiledJS(JS);
-end;
-
 function TPasToJSConverter.StorePrecompiledJS(El: TJSElement): string;
 var
   aWriter: TBufferWriter;
@@ -13768,7 +13787,7 @@ begin
     V.A:=C;
     AddToSourceElements(Src,V);
 
-    if (coStoreProcJS in Options) and (AContext.Resolver<>nil) then
+    if (coStoreImplJS in Options) and (AContext.Resolver<>nil) then
       begin
       Proc:=AContext.Resolver.GetTopLvlProc(AContext.PasElement);
       if Proc<>nil then

+ 164 - 98
packages/pastojs/src/pas2jsfiler.pp

@@ -31,11 +31,11 @@ Works:
 - converter: use precompiled body
 - store/restore/use precompiled JS of proc bodies
 - store/restore/use precompiled JS of proc local const
+- store/restore/use precompiled JS of initialization plus references
+- useanalyzer: generate + use initialization/finalization references
 
 ToDo:
 - WPO uses Proc.References
-- store converted initialization/finalization
-- use stored converted initialization/finalization
 - uses section
 - external references
 - stop after uses section and continue reading
@@ -182,7 +182,7 @@ const
     'ObjectChecks'
     );
 
-  PJUDefaultConvertOptions: TPasToJsConverterOptions = [coStoreProcJS];
+  PJUDefaultConvertOptions: TPasToJsConverterOptions = [coStoreImplJS];
   PJUConverterOptions: array[TPasToJsConverterOption] of string = (
     'LowerCase',
     'SwitchStatement',
@@ -190,7 +190,7 @@ const
     'UseStrict',
     'NoTypeInfo',
     'EliminateDeadCode',
-    'StoreProcJS'
+    'StoreImplJS'
     );
 
   PJUDefaultTargetPlatform = PlatformBrowser;
@@ -617,7 +617,7 @@ type
     procedure WritePasScope(Obj: TJSONObject; Scope: TPasScope; aContext: TPJUWriterContext); virtual;
     procedure WriteIdentifierScope(Obj: TJSONObject; Scope: TPasIdentifierScope; aContext: TPJUWriterContext); virtual;
     procedure WriteModuleScopeFlags(Obj: TJSONObject; const Value, DefaultValue: TPasModuleScopeFlags); virtual;
-    procedure WriteModuleScope(Obj: TJSONObject; Scope: TPasModuleScope; aContext: TPJUWriterContext); virtual;
+    procedure WriteModuleScope(Obj: TJSONObject; Scope: TPas2JSModuleScope; aContext: TPJUWriterContext); virtual;
     procedure WritePasElement(Obj: TJSONObject; El: TPasElement; aContext: TPJUWriterContext); virtual;
     procedure WriteModule(Obj: TJSONObject; aModule: TPasModule; aContext: TPJUWriterContext); virtual;
     procedure WriteSection(ParentJSON: TJSONObject; Section: TPasSection;
@@ -639,6 +639,8 @@ type
       DefaultKind: TPasExprKind; DefaultOpCode: TExprOpCode; aContext: TPJUWriterContext); virtual;
     procedure WritePasExprArray(Obj: TJSONObject; Parent: TPasElement;
       const PropName: string; const ExprArr: TPasExprArray; aContext: TPJUWriterContext); virtual;
+    procedure WriteScopeReferences(Obj: TJSONObject; References: TPasScopeReferences;
+      const PropName: string; aContext: TPJUWriterContext); virtual;
     procedure WriteUnaryExpr(Obj: TJSONObject; Expr: TUnaryExpr; aContext: TPJUWriterContext); virtual;
     procedure WriteBinaryExpr(Obj: TJSONObject; Expr: TBinaryExpr; aContext: TPJUWriterContext); virtual;
     procedure WritePrimitiveExpr(Obj: TJSONObject; Expr: TPrimitiveExpr; aContext: TPJUWriterContext); virtual;
@@ -805,10 +807,12 @@ type
     procedure ReadPasExprArray(Obj: TJSONObject; Parent: TPasElement;
       const PropName: string; var ExprArr: TPasExprArray; aContext: TPJUReaderContext); virtual;
     procedure ReadPasScope(Obj: TJSONObject; Scope: TPasScope; aContext: TPJUReaderContext); virtual;
+    procedure ReadScopeReferences(Obj: TJSONObject; Scope: TPasScope;
+      const PropName: string; var References: TPasScopeReferences); virtual;
     procedure ReadIdentifierScopeArray(Arr: TJSONArray; Scope: TPasIdentifierScope); virtual;
     procedure ReadIdentifierScope(Obj: TJSONObject; Scope: TPasIdentifierScope; aContext: TPJUReaderContext); virtual;
     function ReadModuleScopeFlags(Obj: TJSONObject; El: TPasElement; const DefaultValue: TPasModuleScopeFlags): TPasModuleScopeFlags; virtual;
-    procedure ReadModuleScope(Obj: TJSONObject; Scope: TPasModuleScope; aContext: TPJUReaderContext); virtual;
+    procedure ReadModuleScope(Obj: TJSONObject; Scope: TPas2JSModuleScope; aContext: TPJUReaderContext); virtual;
     procedure ReadModule(Data: TJSONData; aContext: TPJUReaderContext); virtual;
     procedure ReadUnaryExpr(Obj: TJSONObject; Expr: TUnaryExpr; aContext: TPJUReaderContext); virtual;
     procedure ReadBinaryExpr(Obj: TJSONObject; Expr: TBinaryExpr; aContext: TPJUReaderContext); virtual;
@@ -1777,8 +1781,19 @@ procedure TPJUWriter.WriteModule(Obj: TJSONObject; aModule: TPasModule;
     WriteSection(Obj,Section,PropName,aContext);
   end;
 
+  procedure WImplBlock(Block: TPasImplBlock; const PropPrefix: string);
+  var
+    Scope: TPas2JSInitialFinalizationScope;
+  begin
+    if Block=nil then exit;
+    Scope:=Block.CustomData as TPas2JSInitialFinalizationScope;
+    if Scope.JS<>'' then
+      Obj.Add(PropPrefix+'JS',Scope.JS);
+    WriteScopeReferences(Obj,Scope.References,PropPrefix+'Refs',aContext);
+  end;
+
 var
-  ModScope: TPasModuleScope;
+  ModScope: TPas2JSModuleScope;
 begin
   WritePasElement(Obj,aModule,aContext);
 
@@ -1792,7 +1807,7 @@ begin
     RaiseMsg(20180203163923);
 
   // module scope
-  ModScope:=TPasModuleScope(CheckElScope(aModule,20180206113855,TPasModuleScope));
+  ModScope:=TPas2JSModuleScope(CheckElScope(aModule,20180206113855,TPas2JSModuleScope));
   WriteModuleScope(Obj,ModScope,aContext);
 
   // write sections
@@ -1800,11 +1815,20 @@ begin
 
   WSection(aModule.ImplementationSection,'Implementation');
   if aModule.ClassType=TPasProgram then
-    WSection(TPasProgram(aModule).ProgramSection,'Program')
+    begin
+    WSection(TPasProgram(aModule).ProgramSection,'Program');
+    WImplBlock(aModule.InitializationSection,'begin');
+    end
   else if aModule.ClassType=TPasLibrary then
+    begin
     WSection(TPasLibrary(aModule).LibrarySection,'Library');
-  // ToDo: write precompiled aModule.InitializationSection
-  // ToDo: write precompiled aModule.FinalizationSection
+    WImplBlock(aModule.InitializationSection,'begin');
+    end
+  else
+    begin
+    WImplBlock(aModule.InitializationSection,'Init');
+    WImplBlock(aModule.FinalizationSection,'Final');
+    end;
 
   WriteExternalReferences(Obj);
 end;
@@ -1896,8 +1920,8 @@ begin
   end;
 end;
 
-procedure TPJUWriter.WriteModuleScope(Obj: TJSONObject; Scope: TPasModuleScope;
-  aContext: TPJUWriterContext);
+procedure TPJUWriter.WriteModuleScope(Obj: TJSONObject;
+  Scope: TPas2JSModuleScope; aContext: TPJUWriterContext);
 var
   aModule: TPasModule;
 begin
@@ -2405,6 +2429,43 @@ begin
     end;
 end;
 
+procedure TPJUWriter.WriteScopeReferences(Obj: TJSONObject;
+  References: TPasScopeReferences; const PropName: string;
+  aContext: TPJUWriterContext);
+var
+  Refs: TFPList;
+  Arr: TJSONArray;
+  i: Integer;
+  PSRef: TPasScopeReference;
+  Ref: TPJUFilerElementRef;
+  SubObj: TJSONObject;
+begin
+  if References=nil then exit;
+  Refs:=References.GetList;
+  try
+    if Refs.Count>0 then
+      begin
+      Arr:=TJSONArray.Create;
+      Obj.Add(PropName,Arr);
+      for i:=0 to Refs.Count-1 do
+        begin
+        PSRef:=TPasScopeReference(Refs[i]);
+        Ref:=GetElementReference(PSRef.Element);
+        if (Ref.Id=0) and not (Ref.Element is TPasUnresolvedSymbolRef) then
+          RaiseMsg(20180221170307,References.Scope.Element,GetObjName(Ref.Element));
+        SubObj:=TJSONObject.Create;
+        Arr.Add(SubObj);
+        if PSRef.Access<>PJUDefaultPSRefAccess then
+          SubObj.Add('Access',PJUPSRefAccessNames[PSRef.Access]);
+        AddReferenceToObj(SubObj,'Id',PSRef.Element);
+        end;
+      end;
+  finally
+    Refs.Free;
+  end;
+  if aContext=nil then ;
+end;
+
 procedure TPJUWriter.WriteUnaryExpr(Obj: TJSONObject; Expr: TUnaryExpr;
   aContext: TPJUWriterContext);
 begin
@@ -2857,14 +2918,10 @@ procedure TPJUWriter.WriteProcedure(Obj: TJSONObject; El: TPasProcedure;
 var
   DefProcMods: TProcedureModifiers;
   Scope: TPas2JSProcedureScope;
-  Refs: TFPList;
   Arr: TJSONArray;
   i: Integer;
-  PSRef: TPasProcScopeReference;
-  SubObj: TJSONObject;
   DeclProc: TPasProcedure;
   DeclScope: TPas2JsProcedureScope;
-  Ref: TPJUFilerElementRef;
 begin
   WritePasElement(Obj,El,aContext);
   Scope:=El.CustomData as TPas2JSProcedureScope;
@@ -2903,32 +2960,7 @@ begin
     if DeclProc=nil then
       DeclProc:=El;
     DeclScope:=NoNil(DeclProc.CustomData) as TPas2JSProcedureScope;
-    // write references
-    if DeclScope.References<>nil then
-      begin
-      Refs:=DeclScope.GetReferences;
-      try
-        if Refs.Count>0 then
-          begin
-          Arr:=TJSONArray.Create;
-          Obj.Add('ProcRefs',Arr);
-          for i:=0 to Refs.Count-1 do
-            begin
-            PSRef:=TPasProcScopeReference(Refs[i]);
-            Ref:=GetElementReference(PSRef.Element);
-            if (Ref.Id=0) and not (Ref.Element is TPasUnresolvedSymbolRef) then
-              RaiseMsg(20180221170307,El,GetObjName(Ref.Element));
-            SubObj:=TJSONObject.Create;
-            Arr.Add(SubObj);
-            if PSRef.Access<>PJUDefaultPSRefAccess then
-              SubObj.Add('Access',PJUPSRefAccessNames[PSRef.Access]);
-            AddReferenceToObj(SubObj,'Id',PSRef.Element);
-            end;
-          end;
-      finally
-        Refs.Free;
-      end;
-      end;
+    WriteScopeReferences(Obj,DeclScope.References,'Refs',aContext);
 
     // precompiled body
     if Scope.BodyJS<>'' then
@@ -3427,7 +3459,7 @@ end;
 procedure TPJUReader.Set_ModScope_AssertClass(RefEl: TPasElement; Data: TObject
   );
 var
-  Scope: TPasModuleScope absolute Data;
+  Scope: TPas2JSModuleScope absolute Data;
 begin
   if RefEl is TPasClassType then
     Scope.AssertClass:=TPasClassType(RefEl)
@@ -3438,7 +3470,7 @@ end;
 procedure TPJUReader.Set_ModScope_AssertDefConstructor(RefEl: TPasElement;
   Data: TObject);
 var
-  Scope: TPasModuleScope absolute Data;
+  Scope: TPas2JSModuleScope absolute Data;
 begin
   if RefEl is TPasConstructor then
     Scope.AssertDefConstructor:=TPasConstructor(RefEl)
@@ -3449,7 +3481,7 @@ end;
 procedure TPJUReader.Set_ModScope_AssertMsgConstructor(RefEl: TPasElement;
   Data: TObject);
 var
-  Scope: TPasModuleScope absolute Data;
+  Scope: TPas2JSModuleScope absolute Data;
 begin
   if RefEl is TPasConstructor then
     Scope.AssertMsgConstructor:=TPasConstructor(RefEl)
@@ -3460,7 +3492,7 @@ end;
 procedure TPJUReader.Set_ModScope_RangeErrorClass(RefEl: TPasElement;
   Data: TObject);
 var
-  Scope: TPasModuleScope absolute Data;
+  Scope: TPas2JSModuleScope absolute Data;
 begin
   if RefEl is TPasClassType then
     Scope.RangeErrorClass:=TPasClassType(RefEl)
@@ -3471,7 +3503,7 @@ end;
 procedure TPJUReader.Set_ModScope_RangeErrorConstructor(RefEl: TPasElement;
   Data: TObject);
 var
-  Scope: TPasModuleScope absolute Data;
+  Scope: TPas2JSModuleScope absolute Data;
 begin
   if RefEl is TPasConstructor then
     Scope.RangeErrorConstructor:=TPasConstructor(RefEl)
@@ -4830,6 +4862,57 @@ begin
   if aContext=nil then ;
 end;
 
+procedure TPJUReader.ReadScopeReferences(Obj: TJSONObject; Scope: TPasScope;
+  const PropName: string; var References: TPasScopeReferences);
+var
+  Arr: TJSONArray;
+  i, Id: Integer;
+  Data: TJSONData;
+  SubObj: TJSONObject;
+  Ref: TPJUFilerElementRef;
+  s: string;
+  Found: Boolean;
+  Access: TPSRefAccess;
+  El: TPasElement;
+begin
+  El:=Scope.Element;
+  if References<>nil then
+    RaiseMsg(20180302145101,El);
+  if not ReadArray(Obj,PropName,Arr,El) then exit;
+  References:=TPasScopeReferences.Create(Scope);
+  for i:=0 to Arr.Count-1 do
+    begin
+    Data:=Arr[i];
+    if not (Data is TJSONObject) then
+      RaiseMsg(20180221164800,El,GetObjName(Data));
+    SubObj:=TJSONObject(Data);
+    Data:=SubObj.Find('Id');
+    if not (Data is TJSONIntegerNumber) then
+      RaiseMsg(20180221171546,El,GetObjName(Data));
+    Id:=Data.AsInteger;
+    Ref:=GetElReference(Id,El);
+    if Ref=nil then
+      RaiseMsg(20180221171940,El,IntToStr(Id));
+    if Ref.Element=nil then
+      RaiseMsg(20180221171940,El,IntToStr(Id));
+    if ReadString(SubObj,'Access',s,El) then
+      begin
+      Found:=false;
+      for Access in TPSRefAccess do
+        if s=PJUPSRefAccessNames[Access] then
+          begin
+          Found:=true;
+          break;
+          end;
+      if not Found then
+        RaiseMsg(20180221172333,El,'Access "'+s+'"');
+      end
+    else
+      Access:=PJUDefaultPSRefAccess;
+    References.Add(Ref.Element,Access);
+    end;
+end;
+
 procedure TPJUReader.ReadIdentifierScopeArray(Arr: TJSONArray;
   Scope: TPasIdentifierScope);
 // called after reading module, i.e. all elements are created
@@ -4940,8 +5023,8 @@ begin
     end;
 end;
 
-procedure TPJUReader.ReadModuleScope(Obj: TJSONObject; Scope: TPasModuleScope;
-  aContext: TPJUReaderContext);
+procedure TPJUReader.ReadModuleScope(Obj: TJSONObject;
+  Scope: TPas2JSModuleScope; aContext: TPJUReaderContext);
 var
   aModule: TPasModule;
 begin
@@ -4958,6 +5041,8 @@ begin
 end;
 
 procedure TPJUReader.ReadModule(Data: TJSONData; aContext: TPJUReaderContext);
+var
+  aModule: TPasModule;
 
   function PreReadSection(ParentJSON: TJSONObject; const PropName: string): TJSONObject;
   var
@@ -4968,11 +5053,23 @@ procedure TPJUReader.ReadModule(Data: TJSONData; aContext: TPJUReaderContext);
     Result:=CheckJSONObject(PropData,20180205121719);
   end;
 
+  procedure ReadInitialFinal(Obj: TJSONObject; Block: TPasImplBlock;
+    const PropPrefix: string);
+  var
+    Scope: TPas2JSInitialFinalizationScope;
+    s: string;
+  begin
+    Scope:=TPas2JSInitialFinalizationScope(Resolver.CreateScope(Block,Resolver.ScopeClass_InitialFinalization));
+    Block.CustomData:=Scope;
+    if not ReadString(Obj,PropPrefix+'JS',s,Block) then exit;
+    Scope.JS:=s;
+    ReadScopeReferences(Obj,Scope,PropPrefix+'Refs',Scope.References);
+  end;
+
 var
   Obj, SubObj: TJSONObject;
   aType, aName: String;
-  aModule: TPasModule;
-  ModScope: TPasModuleScope;
+  ModScope: TPas2JSModuleScope;
   OldBoolSwitches: TBoolSwitches;
 begin
   {$IFDEF VerbosePJUFiler}
@@ -4994,7 +5091,7 @@ begin
   Resolver.RootElement:=aModule;
   ReadPasElement(Obj,aModule,aContext);
 
-  ModScope:=TPasModuleScope(Resolver.CreateScope(aModule,TPasModuleScope));
+  ModScope:=TPas2JSModuleScope(Resolver.CreateScope(aModule,Resolver.ScopeClass_Module));
   ReadModuleScope(Obj,ModScope,aContext);
 
   ReadSystemSymbols(Obj,aModule);
@@ -5035,8 +5132,16 @@ begin
         ReadSection(SubObj,TPasLibrary(aModule).LibrarySection,aContext);
         end;
       end;
-    // ToDo: read precompiled aModule.InitializationSection
-    // ToDo: read precompiled aModule.FinalizationSection
+    if Obj.Find('InitJS')<>nil then
+      begin
+      aModule.InitializationSection:=TInitializationSection.Create('',aModule);
+      ReadInitialFinal(Obj,aModule.InitializationSection,'Init');
+      end;
+    if Obj.Find('FinalJS')<>nil then
+      begin
+      aModule.FinalizationSection:=TFinalizationSection.Create('',aModule);
+      ReadInitialFinal(Obj,aModule.FinalizationSection,'Final');
+      end;
   finally
     aContext.BoolSwitches:=OldBoolSwitches;
   end;
@@ -5383,7 +5488,7 @@ var
   Data: TJSONData;
   Scope: TPas2JSClassScope;
 begin
-  Scope:=TPas2JSClassScope(Resolver.CreateScope(El,TPas2JSClassScope));
+  Scope:=TPas2JSClassScope(Resolver.CreateScope(El,Resolver.ScopeClass_Class));
   El.CustomData:=Scope;
 
   ReadPasElement(Obj,El,aContext);
@@ -5739,16 +5844,8 @@ end;
 procedure TPJUReader.ReadProcScopeReferences(Obj: TJSONObject;
   ImplScope: TPas2JSProcedureScope);
 var
-  i, Id: Integer;
-  Arr: TJSONArray;
-  Data: TJSONData;
-  SubObj: TJSONObject;
-  DeclProc: TPasProcedure;
-  Ref: TPJUFilerElementRef;
-  Found: Boolean;
-  Access: TPSRefAccess;
-  s: string;
   DeclScope: TPasProcedureScope;
+  DeclProc: TPasProcedure;
 begin
   // Note: the References are stored in the declaration scope,
   //       and in the JSON of the implementation scope, so that
@@ -5759,38 +5856,7 @@ begin
   DeclScope:=DeclProc.CustomData as TPasProcedureScope;
   if DeclScope.References<>nil then
     RaiseMsg(20180221172403,DeclProc);
-  if not ReadArray(Obj,'ProcRefs',Arr,DeclProc) then exit;
-  for i:=0 to Arr.Count-1 do
-    begin
-    Data:=Arr[i];
-    if not (Data is TJSONObject) then
-      RaiseMsg(20180221164800,DeclProc,GetObjName(Data));
-    SubObj:=TJSONObject(Data);
-    Data:=SubObj.Find('Id');
-    if not (Data is TJSONIntegerNumber) then
-      RaiseMsg(20180221171546,DeclProc,GetObjName(Data));
-    Id:=Data.AsInteger;
-    Ref:=GetElReference(Id,DeclProc);
-    if Ref=nil then
-      RaiseMsg(20180221171940,DeclProc,IntToStr(Id));
-    if Ref.Element=nil then
-      RaiseMsg(20180221171940,DeclProc,IntToStr(Id));
-    if ReadString(SubObj,'Access',s,DeclProc) then
-      begin
-      Found:=false;
-      for Access in TPSRefAccess do
-        if s=PJUPSRefAccessNames[Access] then
-          begin
-          Found:=true;
-          break;
-          end;
-      if not Found then
-        RaiseMsg(20180221172333,DeclProc,'Access "'+s+'"');
-      end
-    else
-      Access:=PJUDefaultPSRefAccess;
-    DeclScope.AddReference(Ref.Element,Access);
-    end;
+  ReadScopeReferences(Obj,DeclScope,'Refs',DeclScope.References);
 end;
 
 procedure TPJUReader.ReadProcedureBody(Obj: TJSONObject; El: TPasProcedure;
@@ -5835,7 +5901,7 @@ var
   Ref: TPJUFilerElementRef;
   DeclProc: TPasProcedure;
 begin
-  Scope:=TPas2JSProcedureScope(Resolver.CreateScope(El,TPas2JSProcedureScope));
+  Scope:=TPas2JSProcedureScope(Resolver.CreateScope(El,Resolver.ScopeClass_Procedure));
   El.CustomData:=Scope;
 
   ReadPasElement(Obj,El,aContext);

+ 64 - 23
packages/pastojs/tests/tcfiler.pas

@@ -63,14 +63,15 @@ type
     procedure CheckRestoredElementBase(const Path: string; Orig, Rest: TPasElementBase); virtual;
     procedure CheckRestoredResolveData(const Path: string; Orig, Rest: TResolveData); virtual;
     procedure CheckRestoredPasScope(const Path: string; Orig, Rest: TPasScope); virtual;
-    procedure CheckRestoredModuleScope(const Path: string; Orig, Rest: TPasModuleScope); virtual;
+    procedure CheckRestoredModuleScope(const Path: string; Orig, Rest: TPas2JSModuleScope); virtual;
     procedure CheckRestoredIdentifierScope(const Path: string; Orig, Rest: TPasIdentifierScope); virtual;
     procedure CheckRestoredSectionScope(const Path: string; Orig, Rest: TPasSectionScope); virtual;
+    procedure CheckRestoredInitialFinalizationScope(const Path: string; Orig, Rest: TPas2JSInitialFinalizationScope); virtual;
     procedure CheckRestoredEnumTypeScope(const Path: string; Orig, Rest: TPasEnumTypeScope); virtual;
     procedure CheckRestoredRecordScope(const Path: string; Orig, Rest: TPasRecordScope); virtual;
     procedure CheckRestoredClassScope(const Path: string; Orig, Rest: TPas2JSClassScope); virtual;
     procedure CheckRestoredProcScope(const Path: string; Orig, Rest: TPas2JSProcedureScope); virtual;
-    procedure CheckRestoredProcScopeRefs(const Path: string; Orig, Rest: TPas2JSProcedureScope); virtual;
+    procedure CheckRestoredScopeRefs(const Path: string; Orig, Rest: TPasScopeReferences); virtual;
     procedure CheckRestoredPropertyScope(const Path: string; Orig, Rest: TPasPropertyScope); virtual;
     procedure CheckRestoredResolvedReference(const Path: string; Orig, Rest: TResolvedReference); virtual;
     procedure CheckRestoredEvalValue(const Path: string; Orig, Rest: TResEvalValue); virtual;
@@ -142,6 +143,7 @@ type
     procedure TestPC_Proc_LocalConst;
     procedure TestPC_Proc_UTF8;
     procedure TestPC_Class;
+    procedure TestPC_Initialization;
   end;
 
 function CompareListOfProcScopeRef(Item1, Item2: Pointer): integer;
@@ -150,8 +152,8 @@ implementation
 
 function CompareListOfProcScopeRef(Item1, Item2: Pointer): integer;
 var
-  Ref1: TPasProcScopeReference absolute Item1;
-  Ref2: TPasProcScopeReference absolute Item2;
+  Ref1: TPasScopeReference absolute Item1;
+  Ref2: TPasScopeReference absolute Item2;
 begin
   Result:=CompareText(Ref1.Element.Name,Ref2.Element.Name);
   if Result<>0 then exit;
@@ -207,7 +209,7 @@ begin
   FInitialFlags:=TPJUInitialFlags.Create;
   FAnalyzer:=TPasAnalyzer.Create;
   Analyzer.Resolver:=Engine;
-  Analyzer.Options:=Analyzer.Options+[paoProcImplReferences];
+  Analyzer.Options:=Analyzer.Options+[paoImplReferences];
   Converter.OnIsElementUsed:=@OnConverterIsElementUsed;
   Converter.OnIsTypeInfoUsed:=@OnConverterIsTypeInfoUsed;
 end;
@@ -224,7 +226,7 @@ end;
 function TCustomTestPrecompile.CreateConverter: TPasToJSConverter;
 begin
   Result:=inherited CreateConverter;
-  Result.Options:=Result.Options+[coStoreProcJS];
+  Result.Options:=Result.Options+[coStoreImplJS];
 end;
 
 procedure TCustomTestPrecompile.ParseUnit;
@@ -461,8 +463,16 @@ end;
 
 procedure TCustomTestPrecompile.CheckRestoredModule(const Path: string; Orig,
   Rest: TPasModule);
+
+  procedure CheckInitFinal(const Path: string; OrigBlock, RestBlock: TPasImplBlock);
+  begin
+    CheckRestoredObject(Path,OrigBlock,RestBlock);
+    if OrigBlock=nil then exit;
+    CheckRestoredCustomData(Path+'.CustomData',RestBlock,OrigBlock.CustomData,RestBlock.CustomData);
+  end;
+
 begin
-  if not (Orig.CustomData is TPasModuleScope) then
+  if not (Orig.CustomData is TPas2JSModuleScope) then
     Fail(Path+'.CustomData is not TPasModuleScope'+GetObjName(Orig.CustomData));
 
   CheckRestoredElement(Path+'.InterfaceSection',Orig.InterfaceSection,Rest.InterfaceSection);
@@ -471,8 +481,9 @@ begin
     CheckRestoredElement(Path+'.ProgramSection',TPasProgram(Orig).ProgramSection,TPasProgram(Rest).ProgramSection)
   else if Orig is TPasLibrary then
     CheckRestoredElement(Path+'.LibrarySection',TPasLibrary(Orig).LibrarySection,TPasLibrary(Rest).LibrarySection);
-  CheckRestoredElement(Path+'.InitializationSection',Orig.InitializationSection,Rest.InitializationSection);
-  CheckRestoredElement(Path+'.FinalizationSection',Orig.FinalizationSection,Rest.FinalizationSection);
+
+  CheckInitFinal(Path+'.InitializationSection',Orig.InitializationSection,Rest.InitializationSection);
+  CheckInitFinal(Path+'.FnializationSection',Orig.FinalizationSection,Rest.FinalizationSection);
 end;
 
 procedure TCustomTestPrecompile.CheckRestoredScopeReference(const Path: string;
@@ -502,7 +513,7 @@ begin
 end;
 
 procedure TCustomTestPrecompile.CheckRestoredModuleScope(const Path: string;
-  Orig, Rest: TPasModuleScope);
+  Orig, Rest: TPas2JSModuleScope);
 begin
   AssertEquals(Path+'.FirstName',Orig.FirstName,Rest.FirstName);
   if Orig.Flags<>Rest.Flags then
@@ -581,6 +592,14 @@ begin
   CheckRestoredIdentifierScope(Path,Orig,Rest);
 end;
 
+procedure TCustomTestPrecompile.CheckRestoredInitialFinalizationScope(
+  const Path: string; Orig, Rest: TPas2JSInitialFinalizationScope);
+begin
+  CheckRestoredScopeRefs(Path+'.References',Orig.References,Rest.References);
+  if Orig.JS<>Rest.JS then
+    CheckRestoredJS(Path+'.JS',Orig.JS,Rest.JS);
+end;
+
 procedure TCustomTestPrecompile.CheckRestoredEnumTypeScope(const Path: string;
   Orig, Rest: TPasEnumTypeScope);
 begin
@@ -620,7 +639,7 @@ var
 begin
   CheckRestoredReference(Path+'.DeclarationProc',Orig.DeclarationProc,Rest.DeclarationProc);
   CheckRestoredReference(Path+'.ImplProc',Orig.ImplProc,Rest.ImplProc);
-  CheckRestoredProcScopeRefs(Path+'.References',Orig,Rest);
+  CheckRestoredScopeRefs(Path+'.References',Orig.References,Rest.References);
   if Orig.BodyJS<>Rest.BodyJS then
     CheckRestoredJS(Path+'.BodyJS',Orig.BodyJS,Rest.BodyJS);
 
@@ -658,28 +677,28 @@ begin
     end;
 end;
 
-procedure TCustomTestPrecompile.CheckRestoredProcScopeRefs(const Path: string;
-  Orig, Rest: TPas2JSProcedureScope);
+procedure TCustomTestPrecompile.CheckRestoredScopeRefs(const Path: string;
+  Orig, Rest: TPasScopeReferences);
 var
   OrigList, RestList: TFPList;
   i: Integer;
-  OrigRef, RestRef: TPasProcScopeReference;
+  OrigRef, RestRef: TPasScopeReference;
 begin
-  // check References of a proc with implementation
-  CheckRestoredObject(Path,Orig.References,Rest.References);
+  CheckRestoredObject(Path,Orig,Rest);
+  if Orig=nil then exit;
   OrigList:=nil;
   RestList:=nil;
   try
-    OrigList:=Orig.GetReferences;
-    RestList:=Rest.GetReferences;
+    OrigList:=Orig.GetList;
+    RestList:=Rest.GetList;
     OrigList.Sort(@CompareListOfProcScopeRef);
     RestList.Sort(@CompareListOfProcScopeRef);
     for i:=0 to OrigList.Count-1 do
       begin
-      OrigRef:=TPasProcScopeReference(OrigList[i]);
+      OrigRef:=TPasScopeReference(OrigList[i]);
       if i>=RestList.Count then
         Fail(Path+'['+IntToStr(i)+'] Missing in Rest: "'+OrigRef.Element.Name+'"');
-      RestRef:=TPasProcScopeReference(RestList[i]);
+      RestRef:=TPasScopeReference(RestList[i]);
       CheckRestoredReference(Path+'['+IntToStr(i)+'].Name="'+OrigRef.Element.Name+'"',OrigRef.Element,RestRef.Element);
       if OrigRef.Access<>RestRef.Access then
         AssertEquals(Path+'['+IntToStr(i)+']"'+OrigRef.Element.Name+'".Access',
@@ -688,7 +707,7 @@ begin
     if RestList.Count>OrigList.Count then
       begin
       i:=OrigList.Count;
-      RestRef:=TPasProcScopeReference(RestList[i]);
+      RestRef:=TPasScopeReference(RestList[i]);
       Fail(Path+'['+IntToStr(i)+'] Too many in Rest: "'+RestRef.Element.Name+'"');
       end;
   finally
@@ -799,10 +818,12 @@ begin
   C:=Orig.ClassType;
   if C=TResolvedReference then
     CheckRestoredResolvedReference(Path+'[TResolvedReference]',TResolvedReference(Orig),TResolvedReference(Rest))
-  else if C=TPasModuleScope then
-    CheckRestoredModuleScope(Path+'[TPasModuleScope]',TPasModuleScope(Orig),TPasModuleScope(Rest))
+  else if C=TPas2JSModuleScope then
+    CheckRestoredModuleScope(Path+'[TPas2JSModuleScope]',TPas2JSModuleScope(Orig),TPas2JSModuleScope(Rest))
   else if C=TPasSectionScope then
     CheckRestoredSectionScope(Path+'[TPasSectionScope]',TPasSectionScope(Orig),TPasSectionScope(Rest))
+  else if C=TPas2JSInitialFinalizationScope then
+    CheckRestoredInitialFinalizationScope(Path+'[TPas2JSInitialFinalizationScope]',TPas2JSInitialFinalizationScope(Orig),TPas2JSInitialFinalizationScope(Rest))
   else if C=TPasEnumTypeScope then
     CheckRestoredEnumTypeScope(Path+'[TPasEnumTypeScope]',TPasEnumTypeScope(Orig),TPasEnumTypeScope(Rest))
   else if C=TPasRecordScope then
@@ -1622,6 +1643,26 @@ begin
   WriteReadUnit;
 end;
 
+procedure TTestPrecompile.TestPC_Initialization;
+begin
+  StartUnit(false);
+  Add([
+  'interface',
+  'implementation',
+  'type',
+  '  TCaption = string;',
+  '  TRec = record h: string; end;',
+  'var',
+  '  s: TCaption;',
+  '  r: TRec;',
+  'initialization',
+  '  s:=''ö😊'';',
+  '  r.h:=''Ä😊'';',
+  'end.',
+  '']);
+  WriteReadUnit;
+end;
+
 Initialization
   RegisterTests([TTestPrecompile]);
 end.