* Moved LoadUsedUnit from compilerfile to compiler

git-svn-id: trunk@40447 -
This commit is contained in:
michael 2018-12-02 08:27:05 +00:00
parent 99c5c79327
commit e8a8046d3e

View File

@ -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