浏览代码

* Moved LoadUsedUnit from compilerfile to compiler

git-svn-id: trunk@40447 -
michael 6 年之前
父节点
当前提交
e8a8046d3e
共有 1 个文件被更改,包括 188 次插入166 次删除
  1. 188 166
      packages/pastojs/src/pas2jscompiler.pp

+ 188 - 166
packages/pastojs/src/pas2jscompiler.pp

@@ -288,6 +288,15 @@ type
     isForeign : Boolean;
   end;
 
+  TLoadInfo = Record
+    UseFilename,
+    UseUnitname,
+    InFilename: String;
+    NameExpr,
+    InFileExpr: TPasExpr;
+    UseIsForeign: boolean;
+    IsPCU : Boolean;
+  end;
   { TPas2jsCompilerFile }
 
   TPas2jsCompilerFile = class
@@ -345,7 +354,7 @@ type
     procedure CreateConverter;
     function OnResolverFindModule(const UseUnitName, InFilename: String; NameExpr,
       InFileExpr: TPasExpr): TPasModule;
-    function LoadUsedUnit(const UseFilename, UseUnitname, InFilename: String; NameExpr, InFileExpr: TPasExpr; UseIsForeign: boolean; IsPCU : Boolean): TPas2jsCompilerFile;
+//    function LoadUsedUnit(Info : TLoadInfo): TPas2jsCompilerFile;
     procedure OnResolverCheckSrcName(const Element: TPasElement);
     procedure OpenFile(aFilename: string);// beware: this changes FileResolver.BaseDirectory
     procedure ReadUnit;
@@ -442,6 +451,7 @@ type
     function HandleOptionOptimization(C: Char; aValue: String): Boolean;
     function IndexOfInsertJSFilename(const aFilename: string): integer;
     procedure InsertCustomJSFiles(aWriter: TPas2JSMapper);
+    function LoadUsedUnit(Info: TLoadInfo; Context: TPas2jsCompilerFile): TPas2jsCompilerFile;
     function OnMacroCfgDir(Sender: TObject; var Params: string; Lvl: integer
       ): boolean;
     function OnMacroEnv(Sender: TObject; var Params: string; Lvl: integer
@@ -1578,7 +1588,7 @@ function TPas2jsCompilerFile.OnResolverFindModule(const UseUnitName,
 var
   aFile: TPas2jsCompilerFile;
   UnitInfo : TFindUnitInfo;
-
+  LoadInfo : TLoadInfo;
 begin
   Result:=nil;
   aFile:=Nil;
@@ -1588,10 +1598,23 @@ begin
   UnitInfo:=Compiler.GetUnitInfo(UseUnitName,InFileName,PCUSupport);
   if UnitInfo.FileName<>'' then
     begin
+    LoadInfo.UseFilename:=UnitInfo.FileName;
+    LoadInfo.UseUnitname:=UnitInfo.UnitName;
+    LoadInfo.NameExpr:=NameExpr;
+    LoadInfo.IsPCU:=UnitInfo.isPCU;
     if UnitInfo.isPCU then
-      aFile:=LoadUsedUnit(UnitInfo.FileName,UnitInfo.UnitName,'',NameExpr,nil,false,True)
+      begin
+      LoadInfo.InFilename:='';
+      LoadInfo.InFileExpr:=Nil;
+      LoadInfo.UseIsForeign:=False;
+      end
     else
-      aFile:=LoadUsedUnit(UnitInfo.FileName,UnitInfo.UnitName,InFilename,NameExpr,InFileExpr,UnitInfo.IsForeign,False);
+      begin
+      LoadInfo.InFilename:=InFileName;
+      LoadInfo.InFileExpr:=InFileExpr;
+      LoadInfo.UseIsForeign:=UnitInfo.isForeign;
+      end;
+    aFile:=Compiler.LoadUsedUnit(LoadInfo,Self);
     end;
   if aFile<>nil then
     Result:=aFile.PasModule;
@@ -1600,168 +1623,6 @@ end;
 
 
 
-function TPas2jsCompilerFile.LoadUsedUnit(const UseFilename, UseUnitname,
-  InFilename: String; NameExpr, InFileExpr: TPasExpr; UseIsForeign: boolean; IsPCU : Boolean
-  ): TPas2jsCompilerFile;
-
-  function FindCycle(aFile, SearchFor: TPas2jsCompilerFile;
-    var Cycle: TFPList): boolean;
-  var
-    i: Integer;
-    aParent: TPas2jsCompilerFile;
-  begin
-    for i:=0 to aFile.UsedByCount[ubMainSection]-1 do begin
-      aParent:=aFile.UsedBy[ubMainSection,i];
-      if aParent=SearchFor then
-      begin
-        // unit cycle found
-        Cycle:=TFPList.Create;
-        Cycle.Add(aParent);
-        Cycle.Add(aFile);
-        exit(true);
-      end;
-      if FindCycle(aParent,SearchFor,Cycle) then
-      begin
-        Cycle.Add(aFile);
-        exit(true);
-      end;
-    end;
-    Result:=false;
-  end;
-
-var
-  aFile: TPas2jsCompilerFile;
-
-  procedure CheckCycle;
-  var
-    i: Integer;
-    Cycle: TFPList;
-    CyclePath: String;
-  begin
-    if PasModule.ImplementationSection=nil then
-    begin
-      // main uses section (e.g. interface or program, not implementation)
-      // -> check for cycles
-
-      aFile.FUsedBy[ubMainSection].Add(Self);
-
-      Cycle:=nil;
-      try
-        if FindCycle(aFile,aFile,Cycle) then
-        begin
-          CyclePath:='';
-          for i:=0 to Cycle.Count-1 do begin
-            if i>0 then CyclePath+=',';
-            CyclePath+=TPas2jsCompilerFile(Cycle[i]).GetModuleName;
-          end;
-          PascalResolver.RaiseMsg(20180223141537,nUnitCycle,sUnitCycle,[CyclePath],NameExpr);
-        end;
-      finally
-        Cycle.Free;
-      end;
-    end else begin
-      // implementation uses section
-      aFile.FUsedBy[ubImplSection].Add(Self);
-    end;
-  end;
-
-var
-  UseJSFilename: String;
-  OtherFile: TPas2jsCompilerFile;
-begin
-  Result:=nil;
-
-  aFile:=Compiler.FindUnitWithFile(UseFilename);
-
-  if aFile<>nil then
-  begin
-    // known unit
-    if (aFile.PasUnitName<>'') and (CompareText(aFile.PasUnitName,UseUnitname)<>0) then
-    begin
-      Log.LogPlain(['Debug: TPas2jsPasTree.FindUnit unitname MISMATCH aFile.PasUnitname="',aFile.PasUnitName,'"',
-         ' Self=',FileResolver.Cache.FormatPath(PasFilename),
-         ' Uses=',UseUnitname,
-         ' IsForeign=',IsForeign]);
-      RaiseInternalError(20170504161412,'TPas2jsPasTree.FindUnit unit name mismatch');
-    end;
-    CheckCycle;
-  end else begin
-    // new unit
-
-    if InFilename<>'' then
-    begin
-      aFile:=Compiler.FindLoadedUnit(UseUnitname);
-      if aFile<>nil then
-      begin
-        {$IF defined(VerbosePasResolver) or defined(VerbosePas2JS)}
-        writeln('TPas2jsCompilerFile.FindUnit in-file unit name duplicate: New=',UseFilename,' Old=',aFile.PasFilename);
-        {$ENDIF}
-        PascalResolver.RaiseMsg(20180223141323,nDuplicateFileFound,sDuplicateFileFound,
-          [UseFilename,aFile.PasFilename],InFileExpr);
-      end;
-    end;
-
-    UseJSFilename:='';
-    if (not IsForeign) then
-      UseJSFilename:=Compiler.FindUnitJSFileName(UseFilename);
-    //  Log.LogPlain(['Debug: TPas2jsPasTree.FindUnit Self=',FileResolver.Cache.FormatPath(PasFilename),
-    //    ' Uses=',ActualUnitname,' Found="',FileResolver.Cache.FormatPath(UseFilename),'"',
-    //    ' IsForeign=',IsForeign,' JSFile="',FileResolver.Cache.FormatPath(useJSFilename),'"']);
-    // load Pascal or PCU file
-    Compiler.LoadPasFile(UseFilename,UseUnitname,aFile,IsPCU);
-
-    // consistency checks
-    if aFile.PasUnitName<>UseUnitname then
-      RaiseInternalError(20170922143329,'aFile.PasUnitName='+aFile.PasUnitName+' UseUnitname='+UseUnitname);
-    if isPCU then
-    begin
-      if CompareFilenames(aFile.PCUFilename,UseFilename)<>0 then
-        RaiseInternalError(20180312122331,'aFile.PCUFilename='+aFile.PCUFilename+' UseFilename='+UseFilename);
-    end else
-    begin
-      if CompareFilenames(aFile.PasFilename,UseFilename)<>0 then
-        RaiseInternalError(20170922143330,'aFile.PasFilename='+aFile.PasFilename+' UseFilename='+UseFilename);
-    end;
-
-    if aFile=Self then
-    begin
-      // unit uses itself -> cycle
-      Parser.RaiseParserError(nUnitCycle,[UseUnitname]);
-    end;
-
-    // add file to trees
-    Compiler.AddUsedUnit(aFile);
-    // consistency checks
-    OtherFile:=Compiler.FindLoadedUnit(UseUnitname);
-    if aFile<>OtherFile then
-    begin
-      if OtherFile=nil then
-        RaiseInternalError(20170922143405,'UseUnitname='+UseUnitname)
-      else
-        RaiseInternalError(20170922143511,'UseUnitname='+UseUnitname+' Found='+OtherFile.PasUnitName);
-    end;
-    OtherFile:=Compiler.FindUnitWithFile(UseFilename);
-    if aFile<>OtherFile then
-    begin
-      if OtherFile=nil then
-        RaiseInternalError(20180224094625,'UsePasFilename='+UseFilename)
-      else
-        RaiseInternalError(20180224094627,'UsePasFilename='+UseFilename+' Found='+OtherFile.PasFilename);
-    end;
-
-    CheckCycle;
-
-    aFile.JSFilename:=UseJSFilename;
-    aFile.IsForeign:=UseIsForeign;
-
-    // read
-    aFile.ReadUnit;
-    // beware: the parser may not yet have finished
-  end;
-
-  Result:=aFile;
-end;
-
 { TPas2jsCompiler }
 
 procedure TPas2jsCompiler.SetFileCache(AValue: TPas2jsFilesCache);
@@ -4861,6 +4722,167 @@ begin
     end;
 end;
 
+
+function TPas2JSCompiler.LoadUsedUnit(Info : TLoadInfo; Context : TPas2jsCompilerFile): TPas2jsCompilerFile;
+
+  function FindCycle(aFile, SearchFor: TPas2jsCompilerFile;
+    var Cycle: TFPList): boolean;
+  var
+    i: Integer;
+    aParent: TPas2jsCompilerFile;
+  begin
+    for i:=0 to aFile.UsedByCount[ubMainSection]-1 do begin
+      aParent:=aFile.UsedBy[ubMainSection,i];
+      if aParent=SearchFor then
+      begin
+        // unit cycle found
+        Cycle:=TFPList.Create;
+        Cycle.Add(aParent);
+        Cycle.Add(aFile);
+        exit(true);
+      end;
+      if FindCycle(aParent,SearchFor,Cycle) then
+      begin
+        Cycle.Add(aFile);
+        exit(true);
+      end;
+    end;
+    Result:=false;
+  end;
+
+var
+  aFile: TPas2jsCompilerFile;
+
+  procedure CheckCycle;
+  var
+    i: Integer;
+    Cycle: TFPList;
+    CyclePath: String;
+  begin
+    if Context.PasModule.ImplementationSection=nil then
+    begin
+      // main uses section (e.g. interface or program, not implementation)
+      // -> check for cycles
+
+      aFile.FUsedBy[ubMainSection].Add(Context);
+
+      Cycle:=nil;
+      try
+        if FindCycle(aFile,aFile,Cycle) then
+        begin
+          CyclePath:='';
+          for i:=0 to Cycle.Count-1 do begin
+            if i>0 then CyclePath+=',';
+            CyclePath+=TPas2jsCompilerFile(Cycle[i]).GetModuleName;
+          end;
+          Context.PascalResolver.RaiseMsg(20180223141537,nUnitCycle,sUnitCycle,[CyclePath],Info.NameExpr);
+        end;
+      finally
+        Cycle.Free;
+      end;
+    end else begin
+      // implementation uses section
+      aFile.FUsedBy[ubImplSection].Add(Context);
+    end;
+  end;
+
+var
+  UseJSFilename: String;
+  OtherFile: TPas2jsCompilerFile;
+begin
+  Result:=nil;
+
+  aFile:=FindUnitWithFile(Info.UseFilename);
+
+  if aFile<>nil then
+  begin
+    // known unit
+    if (aFile.PasUnitName<>'') and (CompareText(aFile.PasUnitName,Info.UseUnitname)<>0) then
+    begin
+      Log.LogPlain(['Debug: TPas2jsPasTree.FindUnit unitname MISMATCH aFile.PasUnitname="',aFile.PasUnitName,'"',
+         ' Self=',Context.FileResolver.Cache.FormatPath(Context.PasFilename),
+         ' Uses=',Info.UseUnitname,
+         ' IsForeign=',Context.IsForeign]);
+      RaiseInternalError(20170504161412,'TPas2jsPasTree.FindUnit unit name mismatch');
+    end;
+    CheckCycle;
+  end else begin
+    // new unit
+
+    if Info.InFilename<>'' then
+    begin
+      aFile:=FindLoadedUnit(Info.UseUnitname);
+      if aFile<>nil then
+      begin
+        {$IF defined(VerbosePasResolver) or defined(VerbosePas2JS)}
+        writeln('TPas2jsCompilerFile.FindUnit in-file unit name duplicate: New=',Info.UseFilename,' Old=',aFile.PasFilename);
+        {$ENDIF}
+        Context.PascalResolver.RaiseMsg(20180223141323,nDuplicateFileFound,sDuplicateFileFound,
+          [Info.UseFilename,aFile.PasFilename],Info.InFileExpr);
+      end;
+    end;
+
+    UseJSFilename:='';
+    if (not Context.IsForeign) then
+      UseJSFilename:=FindUnitJSFileName(Info.UseFilename);
+    //  Log.LogPlain(['Debug: TPas2jsPasTree.FindUnit Self=',FileResolver.Cache.FormatPath(PasFilename),
+    //    ' Uses=',ActualUnitname,' Found="',FileResolver.Cache.FormatPath(UseFilename),'"',
+    //    ' IsForeign=',IsForeign,' JSFile="',FileResolver.Cache.FormatPath(useJSFilename),'"']);
+    // load Pascal or PCU file
+    LoadPasFile(Info.UseFilename,Info.UseUnitname,aFile,Info.IsPCU);
+
+    // consistency checks
+    if aFile.PasUnitName<>Info.UseUnitname then
+      RaiseInternalError(20170922143329,'aFile.PasUnitName='+aFile.PasUnitName+' UseUnitname='+Info.UseUnitname);
+    if Info.isPCU then
+    begin
+      if CompareFilenames(aFile.PCUFilename,Info.UseFilename)<>0 then
+        RaiseInternalError(20180312122331,'aFile.PCUFilename='+aFile.PCUFilename+' UseFilename='+Info.UseFilename);
+    end else
+    begin
+      if CompareFilenames(aFile.PasFilename,Info.UseFilename)<>0 then
+        RaiseInternalError(20170922143330,'aFile.PasFilename='+aFile.PasFilename+' UseFilename='+Info.UseFilename);
+    end;
+
+    if aFile=Context then
+    begin
+      // unit uses itself -> cycle
+      Context.Parser.RaiseParserError(nUnitCycle,[Info.UseUnitname]);
+    end;
+
+    // add file to trees
+    AddUsedUnit(aFile);
+    // consistency checks
+    OtherFile:=FindLoadedUnit(Info.UseUnitname);
+    if aFile<>OtherFile then
+    begin
+      if OtherFile=nil then
+        RaiseInternalError(20170922143405,'UseUnitname='+Info.UseUnitname)
+      else
+        RaiseInternalError(20170922143511,'UseUnitname='+Info.UseUnitname+' Found='+OtherFile.PasUnitName);
+    end;
+    OtherFile:=FindUnitWithFile(Info.UseFilename);
+    if aFile<>OtherFile then
+    begin
+      if OtherFile=nil then
+        RaiseInternalError(20180224094625,'UsePasFilename='+Info.UseFilename)
+      else
+        RaiseInternalError(20180224094627,'UsePasFilename='+Info.UseFilename+' Found='+OtherFile.PasFilename);
+    end;
+
+    CheckCycle;
+
+    aFile.JSFilename:=UseJSFilename;
+    aFile.IsForeign:=Info.UseIsForeign;
+
+    // read
+    aFile.ReadUnit;
+    // beware: the parser may not yet have finished
+  end;
+
+  Result:=aFile;
+end;
+
 function TPas2jsCompiler.ResolvedMainJSFile: string;
 
 Var