mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-09-11 13:49:07 +02:00
fcl-passrc: optional parse units queued instead of recursively
git-svn-id: trunk@38414 -
This commit is contained in:
parent
77b97abe61
commit
d34e9b79bf
@ -665,6 +665,7 @@ type
|
||||
Data: Pointer; var Abort: boolean);
|
||||
public
|
||||
UsesScopes: TFPList; // list of TPasSectionScope
|
||||
UsesFinished: boolean;
|
||||
Finished: boolean;
|
||||
constructor Create; override;
|
||||
destructor Destroy; override;
|
||||
@ -1434,8 +1435,9 @@ type
|
||||
function GetVisibilityContext: TPasElement;
|
||||
procedure FinishScope(ScopeType: TPasScopeType; El: TPasElement); override;
|
||||
function IsUnitIntfFinished(AModule: TPasModule): boolean;
|
||||
procedure NotifyPendingUsedInterfaces; virtual;
|
||||
function GetPendingUsedInterface(Section: TPasSection): TPasUsesUnit;
|
||||
procedure CheckPendingUsedInterface(Section: TPasSection); override;
|
||||
function CheckPendingUsedInterface(Section: TPasSection): boolean; override;
|
||||
procedure ContinueParsing; virtual;
|
||||
function NeedArrayValues(El: TPasElement): boolean; override;
|
||||
function GetDefaultClassVisibility(AClass: TPasClassType
|
||||
@ -4045,6 +4047,10 @@ begin
|
||||
{$IFDEF VerbosePasResolver}
|
||||
writeln('TPasResolver.FinishUsesClause Section=',Section.ClassName,' Section.UsesList.Count=',Section.UsesList.Count);
|
||||
{$ENDIF}
|
||||
if Scope.UsesFinished then
|
||||
RaiseInternalError(20180305145220);
|
||||
Scope.UsesFinished:=true;
|
||||
|
||||
for i:=0 to Section.UsesList.Count-1 do
|
||||
begin
|
||||
UseUnit:=Section.UsesClause[i];
|
||||
@ -4055,8 +4061,8 @@ begin
|
||||
|
||||
// check used unit
|
||||
PublicEl:=nil;
|
||||
if (UseModule.ClassType=TLibrarySection) then
|
||||
PublicEl:=UseModule
|
||||
if (UseModule.ClassType=TPasLibrary) then
|
||||
PublicEl:=TPasLibrary(UseModule).LibrarySection
|
||||
else if (UseModule.ClassType=TPasModule) then
|
||||
PublicEl:=TPasModule(UseModule).InterfaceSection
|
||||
else
|
||||
@ -4131,29 +4137,12 @@ begin
|
||||
end;
|
||||
|
||||
procedure TPasResolver.FinishInterfaceSection(Section: TPasSection);
|
||||
var
|
||||
ModuleScope: TPasModuleScope;
|
||||
PendingResolver: TPasResolver;
|
||||
PendingParser: TPasParser;
|
||||
PendingModule: TPasModule;
|
||||
PendingImpl: TImplementationSection;
|
||||
begin
|
||||
{$IFDEF VerbosePasResolver}
|
||||
if not IsUnitIntfFinished(Section.GetModule) then
|
||||
RaiseInternalError(20171214004323,'TPasResolver.FinishInterfaceSection "'+CurrentParser.CurModule.Name+'" "'+Section.GetModule.Name+'" IsUnitIntfFinished=false');
|
||||
{$ENDIF}
|
||||
ModuleScope:=CurrentParser.CurModule.CustomData as TPasModuleScope;
|
||||
while ModuleScope.PendingResolvers.Count>0 do
|
||||
begin
|
||||
PendingResolver:=TObject(ModuleScope.PendingResolvers[0]) as TPasResolver;
|
||||
PendingParser:=PendingResolver.CurrentParser;
|
||||
PendingModule:=PendingParser.CurModule;
|
||||
PendingImpl:=PendingModule.ImplementationSection;
|
||||
{$IFDEF VerbosePasResolver}
|
||||
writeln('TPasResolver.FinishInterfaceSection "',ModuleScope.Element.Name,'" Pending="',PendingModule.Name,'"');
|
||||
{$ENDIF}
|
||||
PendingResolver.CheckPendingUsedInterface(PendingImpl);
|
||||
end;
|
||||
NotifyPendingUsedInterfaces;
|
||||
if Section=nil then ;
|
||||
end;
|
||||
|
||||
@ -11835,6 +11824,45 @@ begin
|
||||
and TPasSectionScope(CurIntf.CustomData).Finished;
|
||||
end;
|
||||
|
||||
procedure TPasResolver.NotifyPendingUsedInterfaces;
|
||||
// called after unit interface is ready to be used by other modules
|
||||
var
|
||||
ModuleScope: TPasModuleScope;
|
||||
i: Integer;
|
||||
PendingResolver: TPasResolver;
|
||||
PendingParser: TPasParser;
|
||||
PendingSection: TPasSection;
|
||||
Changed: Boolean;
|
||||
begin
|
||||
// call all PendingResolvers
|
||||
// Note that a waiting resolver might continue parsing, so this
|
||||
// recursively solves all unit cycles
|
||||
ModuleScope:=RootElement.CustomData as TPasModuleScope;
|
||||
i:=ModuleScope.PendingResolvers.Count-1;
|
||||
while i>=0 do
|
||||
begin
|
||||
PendingResolver:=TObject(ModuleScope.PendingResolvers[i]) as TPasResolver;
|
||||
PendingParser:=PendingResolver.CurrentParser;
|
||||
PendingSection:=PendingParser.GetLastSection;
|
||||
{$IFDEF VerbosePasResolver}
|
||||
writeln('TPasResolver.FinishInterfaceSection "',ModuleScope.Element.Name,'" Pending="',PendingResolver.RootElement.Name,'"');
|
||||
{$ENDIF}
|
||||
if PendingSection=nil then
|
||||
RaiseInternalError(20180305141421);
|
||||
Changed:=PendingResolver.CheckPendingUsedInterface(PendingSection); // beware: this might alter the ModuleScope.PendingResolvers
|
||||
if Changed and (PendingSection.PendingUsedIntf=nil) then
|
||||
begin
|
||||
{$IFDEF VerbosePasResolver}
|
||||
writeln('TPasResolver.FinishInterfaceSection "',ModuleScope.Element.Name,'" Continue="',PendingResolver.RootElement.Name,'"');
|
||||
{$ENDIF}
|
||||
PendingParser.ParseContinue;
|
||||
end;
|
||||
dec(i);
|
||||
if i>=ModuleScope.PendingResolvers.Count then
|
||||
i:=ModuleScope.PendingResolvers.Count-1;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TPasResolver.GetPendingUsedInterface(Section: TPasSection
|
||||
): TPasUsesUnit;
|
||||
var
|
||||
@ -11842,7 +11870,6 @@ var
|
||||
UseUnit: TPasUsesUnit;
|
||||
begin
|
||||
Result:=nil;
|
||||
if not (Section is TImplementationSection) then exit;
|
||||
for i:=0 to length(Section.UsesClause)-1 do
|
||||
begin
|
||||
UseUnit:=Section.UsesClause[i];
|
||||
@ -11852,7 +11879,7 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TPasResolver.CheckPendingUsedInterface(Section: TPasSection);
|
||||
function TPasResolver.CheckPendingUsedInterface(Section: TPasSection): boolean;
|
||||
var
|
||||
PendingModule: TPasModule;
|
||||
PendingModuleScope: TPasModuleScope;
|
||||
@ -11860,7 +11887,7 @@ var
|
||||
WasPending: Boolean;
|
||||
begin
|
||||
{$IFDEF VerbosePasResolver}
|
||||
//writeln('TPasResolver.CheckPendingUsedInterface START "',CurrentParser.CurModule.Name,'"');
|
||||
//writeln('TPasResolver.CheckPendingUsedInterface START "',CurrentParser.CurModule.Name,'" Section.PendingUsedIntf=',Section.PendingUsedIntf<>nil);
|
||||
{$ENDIF}
|
||||
WasPending:=Section.PendingUsedIntf<>nil;
|
||||
if WasPending then
|
||||
@ -11869,6 +11896,9 @@ begin
|
||||
if not IsUnitIntfFinished(PendingModule) then
|
||||
exit; // still pending
|
||||
// other unit interface is finished
|
||||
{$IFDEF VerbosePasResolver}
|
||||
writeln('TPasResolver.CheckPendingUsedInterface "',CurrentParser.CurModule.Name,'" UnitIntf finished of "',PendingModule.Name,'"');
|
||||
{$ENDIF}
|
||||
PendingModuleScope:=NoNil(PendingModule.CustomData) as TPasModuleScope;
|
||||
PendingModuleScope.PendingResolvers.Remove(Self);
|
||||
Section.PendingUsedIntf:=nil;
|
||||
@ -11877,7 +11907,7 @@ begin
|
||||
Section.PendingUsedIntf:=GetPendingUsedInterface(Section);
|
||||
if Section.PendingUsedIntf<>nil then
|
||||
begin
|
||||
// unit not yet finished due to pending used interfaces
|
||||
// module not yet finished due to pending used interfaces
|
||||
PendingModule:=Section.PendingUsedIntf.Module as TPasModule;
|
||||
PendingModuleScope:=NoNil(PendingModule.CustomData) as TPasModuleScope;
|
||||
{$IFDEF VerbosePasResolver}
|
||||
@ -11886,12 +11916,16 @@ begin
|
||||
List:=PendingModuleScope.PendingResolvers;
|
||||
if List.IndexOf(Self)<0 then
|
||||
List.Add(Self);
|
||||
Result:=not WasPending;
|
||||
end
|
||||
else
|
||||
begin
|
||||
{$IFDEF VerbosePasResolver}
|
||||
if WasPending then
|
||||
// can now continue parsing
|
||||
ContinueParsing;
|
||||
writeln('TPasResolver.CheckPendingUsedInterface "',CurrentParser.CurModule.Name,'" uses section complete: ',Section.ClassName);
|
||||
{$ENDIF}
|
||||
|
||||
Result:=WasPending;
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -11902,7 +11936,7 @@ begin
|
||||
{$IFDEF VerbosePasResolver}
|
||||
writeln('TPasResolver.ContinueParsing "',CurrentParser.CurModule.Name,'"...');
|
||||
{$ENDIF}
|
||||
CurrentParser.ParseContinueImplementation;
|
||||
CurrentParser.ParseContinue;
|
||||
end;
|
||||
|
||||
function TPasResolver.NeedArrayValues(El: TPasElement): boolean;
|
||||
|
@ -192,7 +192,7 @@ type
|
||||
procedure FinishScope(ScopeType: TPasScopeType; El: TPasElement); virtual;
|
||||
function FindModule(const AName: String): TPasModule; virtual;
|
||||
function FindModule(const AName: String; NameExpr, InFileExpr: TPasExpr): TPasModule; virtual;
|
||||
procedure CheckPendingUsedInterface(Section: TPasSection); virtual;
|
||||
function CheckPendingUsedInterface(Section: TPasSection): boolean; virtual; // true if changed
|
||||
function NeedArrayValues(El: TPasElement): boolean; virtual;
|
||||
function GetDefaultClassVisibility(AClass: TPasClassType): TPasMemberVisibility; virtual;
|
||||
property Package: TPasPackage read FPackage;
|
||||
@ -401,7 +401,9 @@ type
|
||||
// Main scope parsing
|
||||
procedure ParseMain(var Module: TPasModule);
|
||||
procedure ParseUnit(var Module: TPasModule);
|
||||
procedure ParseContinueImplementation;
|
||||
function GetLastSection: TPasSection; virtual;
|
||||
function CanParseContinue(out Section: TPasSection): boolean; virtual;
|
||||
procedure ParseContinue; virtual;
|
||||
procedure ParseProgram(var Module: TPasModule; SkipHeader : Boolean = False);
|
||||
procedure ParseLibrary(var Module: TPasModule);
|
||||
procedure ParseOptionalUsesList(ASection: TPasSection);
|
||||
@ -778,9 +780,11 @@ begin
|
||||
if InFileExpr=nil then ;
|
||||
end;
|
||||
|
||||
procedure TPasTreeContainer.CheckPendingUsedInterface(Section: TPasSection);
|
||||
function TPasTreeContainer.CheckPendingUsedInterface(Section: TPasSection
|
||||
): boolean;
|
||||
begin
|
||||
if Section=nil then ; // avoid compiler warning
|
||||
Result:=false;
|
||||
end;
|
||||
|
||||
function TPasTreeContainer.NeedArrayValues(El: TPasElement): boolean;
|
||||
@ -2727,39 +2731,137 @@ begin
|
||||
end;
|
||||
CheckHint(Module,True);
|
||||
ExpectToken(tkInterface);
|
||||
If LogEvent(pleInterface) then
|
||||
DoLog(mtInfo,nLogStartInterface,SLogStartInterface);
|
||||
if po_StopOnUnitInterface in Options then
|
||||
begin
|
||||
HasFinished:=false;
|
||||
{$IFDEF VerbosePasResolver}
|
||||
writeln('TPasParser.ParseUnit pause parsing after unit name ',CurModule.Name);
|
||||
{$ENDIF}
|
||||
exit;
|
||||
end;
|
||||
ParseInterface;
|
||||
if (Module.InterfaceSection<>nil)
|
||||
and (Module.InterfaceSection.PendingUsedIntf<>nil) then
|
||||
begin
|
||||
HasFinished:=false;
|
||||
{$IFDEF VerbosePasResolver}
|
||||
writeln('TPasParser.ParseUnit pause parsing after interface uses list ',CurModule.Name);
|
||||
{$ENDIF}
|
||||
end;
|
||||
if (Module.ImplementationSection<>nil)
|
||||
and (Module.ImplementationSection.PendingUsedIntf<>nil) then
|
||||
begin
|
||||
HasFinished:=false;
|
||||
{$IFDEF VerbosePasResolver}
|
||||
writeln('TPasParser.ParseUnit pause parsing after implementation uses list ',CurModule.Name);
|
||||
{$ENDIF}
|
||||
end;
|
||||
if HasFinished then
|
||||
Engine.FinishScope(stModule,Module);
|
||||
finally
|
||||
if HasFinished then
|
||||
FCurModule:=nil;
|
||||
FCurModule:=nil; // clear module if there is an error or finished parsing
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TPasParser.ParseContinueImplementation;
|
||||
function TPasParser.GetLastSection: TPasSection;
|
||||
begin
|
||||
Result:=nil;
|
||||
if FCurModule=nil then
|
||||
exit; // parse completed
|
||||
if CurModule is TPasProgram then
|
||||
Result:=TPasProgram(CurModule).ProgramSection
|
||||
else if CurModule is TPasLibrary then
|
||||
Result:=TPasLibrary(CurModule).LibrarySection
|
||||
else if (CurModule.ClassType=TPasModule) or (CurModule is TPasUnitModule) then
|
||||
begin
|
||||
if CurModule.ImplementationSection<>nil then
|
||||
Result:=CurModule.ImplementationSection
|
||||
else
|
||||
Result:=CurModule.InterfaceSection; // might be nil
|
||||
end;
|
||||
end;
|
||||
|
||||
function TPasParser.CanParseContinue(out Section: TPasSection): boolean;
|
||||
begin
|
||||
Result:=false;
|
||||
Section:=nil;
|
||||
if FCurModule=nil then
|
||||
exit; // parse completed
|
||||
if (LastMsg<>'') and (LastMsgType<=mtError) then
|
||||
begin
|
||||
{$IFDEF VerbosePasResolver}
|
||||
writeln('TPasParser.CanParseContinue ',CurModule.Name,' LastMsg="',LastMsgType,':',LastMsg,'"');
|
||||
{$ENDIF}
|
||||
exit;
|
||||
end;
|
||||
if (Scanner.LastMsg<>'') and (Scanner.LastMsgType<=mtError) then
|
||||
begin
|
||||
{$IFDEF VerbosePasResolver}
|
||||
writeln('TPasParser.CanParseContinue ',CurModule.Name,' Scanner.LastMsg="',Scanner.LastMsgType,':',Scanner.LastMsg,'"');
|
||||
{$ENDIF}
|
||||
exit;
|
||||
end;
|
||||
|
||||
Section:=GetLastSection;
|
||||
if Section=nil then
|
||||
if (po_StopOnUnitInterface in Options)
|
||||
and ((CurModule is TPasUnitModule) or (CurModule.ClassType=TPasModule))
|
||||
and (CurModule.InterfaceSection=nil) then
|
||||
exit(true)
|
||||
else
|
||||
exit(false);
|
||||
Result:=Section.PendingUsedIntf=nil;
|
||||
end;
|
||||
|
||||
procedure TPasParser.ParseContinue;
|
||||
// continue parsing after stopped due to pending uses
|
||||
var
|
||||
Section: TPasSection;
|
||||
HasFinished: Boolean;
|
||||
begin
|
||||
if CurModule=nil then
|
||||
ParseExcTokenError('TPasParser.ParseContinue missing module');
|
||||
{$IFDEF VerbosePasParser}
|
||||
writeln('TPasParser.ParseContinue ',CurModule.Name);
|
||||
{$ENDIF}
|
||||
if not CanParseContinue(Section) then
|
||||
ParseExcTokenError('TPasParser.ParseContinue missing section');
|
||||
HasFinished:=true;
|
||||
try
|
||||
ParseDeclarations(CurModule.ImplementationSection);
|
||||
Engine.FinishScope(stModule,CurModule);
|
||||
if Section=nil then
|
||||
begin
|
||||
// continue after unit name
|
||||
ParseInterface;
|
||||
end
|
||||
else
|
||||
begin
|
||||
// continue after uses clause
|
||||
Engine.FinishScope(stUsesClause,Section);
|
||||
ParseDeclarations(Section);
|
||||
end;
|
||||
Section:=GetLastSection;
|
||||
if (Section<>nil) and (Section.PendingUsedIntf<>nil) then
|
||||
HasFinished:=false;
|
||||
if HasFinished then
|
||||
Engine.FinishScope(stModule,CurModule);
|
||||
finally
|
||||
FCurModule:=nil;
|
||||
if HasFinished then
|
||||
FCurModule:=nil; // clear module if there is an error or finished parsing
|
||||
end;
|
||||
end;
|
||||
|
||||
// Starts after the "program" token
|
||||
procedure TPasParser.ParseProgram(var Module: TPasModule; SkipHeader : Boolean = False);
|
||||
|
||||
Var
|
||||
PP : TPasProgram;
|
||||
Section : TProgramSection;
|
||||
N : String;
|
||||
StartPos: TPasSourcePos;
|
||||
|
||||
HasFinished: Boolean;
|
||||
{$IFDEF VerbosePasResolver}
|
||||
aSection: TPasSection;
|
||||
{$ENDIF}
|
||||
begin
|
||||
StartPos:=CurTokenPos;
|
||||
if SkipHeader then
|
||||
@ -2779,6 +2881,7 @@ begin
|
||||
Module := nil;
|
||||
PP:=TPasProgram(CreateElement(TPasProgram, N, Engine.Package, StartPos));
|
||||
Module :=PP;
|
||||
HasFinished:=true;
|
||||
FCurModule:=Module;
|
||||
try
|
||||
if Assigned(Engine.Package) then
|
||||
@ -2806,10 +2909,26 @@ begin
|
||||
Section := TProgramSection(CreateElement(TProgramSection, '', CurModule));
|
||||
PP.ProgramSection := Section;
|
||||
ParseOptionalUsesList(Section);
|
||||
HasFinished:=Section.PendingUsedIntf=nil;
|
||||
if not HasFinished then
|
||||
begin
|
||||
{$IFDEF VerbosePasResolver}
|
||||
writeln('TPasParser.ParseProgram pause parsing after uses list of "',CurModule.Name,'"');
|
||||
if CanParseContinue(aSection) then
|
||||
begin
|
||||
writeln('TPasParser.ParseProgram Section=',Section.ClassName,' Section.PendingUsedIntf=',Section.PendingUsedIntf<>nil);
|
||||
if aSection<>nil then
|
||||
writeln('TPasParser.ParseProgram aSection=',aSection.ClassName,' ',Section=aSection);
|
||||
ParseExc(nErrNoSourceGiven,'[20180305172432] ');
|
||||
end;
|
||||
{$ENDIF}
|
||||
exit;
|
||||
end;
|
||||
ParseDeclarations(Section);
|
||||
Engine.FinishScope(stModule,Module);
|
||||
finally
|
||||
FCurModule:=nil;
|
||||
if HasFinished then
|
||||
FCurModule:=nil; // clear module if there is an error or finished parsing
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -2820,6 +2939,7 @@ Var
|
||||
Section : TLibrarySection;
|
||||
N: String;
|
||||
StartPos: TPasSourcePos;
|
||||
HasFinished: Boolean;
|
||||
|
||||
begin
|
||||
StartPos:=CurTokenPos;
|
||||
@ -2835,6 +2955,7 @@ begin
|
||||
Module := nil;
|
||||
PP:=TPasLibrary(CreateElement(TPasLibrary, N, Engine.Package, StartPos));
|
||||
Module :=PP;
|
||||
HasFinished:=true;
|
||||
FCurModule:=Module;
|
||||
try
|
||||
if Assigned(Engine.Package) then
|
||||
@ -2848,10 +2969,14 @@ begin
|
||||
Section := TLibrarySection(CreateElement(TLibrarySection, '', CurModule));
|
||||
PP.LibrarySection := Section;
|
||||
ParseOptionalUsesList(Section);
|
||||
HasFinished:=Section.PendingUsedIntf=nil;
|
||||
if not HasFinished then
|
||||
exit;
|
||||
ParseDeclarations(Section);
|
||||
Engine.FinishScope(stModule,Module);
|
||||
finally
|
||||
FCurModule:=nil;
|
||||
if HasFinished then
|
||||
FCurModule:=nil; // clear module if there is an error or finished parsing
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -2859,13 +2984,15 @@ procedure TPasParser.ParseOptionalUsesList(ASection: TPasSection);
|
||||
// checks if next token is Uses keyword and reads the uses list
|
||||
begin
|
||||
NextToken;
|
||||
CheckImplicitUsedUnits(ASection);
|
||||
if CurToken=tkuses then
|
||||
ParseUsesList(ASection)
|
||||
else begin
|
||||
CheckImplicitUsedUnits(ASection);
|
||||
Engine.FinishScope(stUsesClause,ASection);
|
||||
else
|
||||
UngetToken;
|
||||
end;
|
||||
Engine.CheckPendingUsedInterface(ASection);
|
||||
if ASection.PendingUsedIntf<>nil then
|
||||
exit;
|
||||
Engine.FinishScope(stUsesClause,ASection);
|
||||
end;
|
||||
|
||||
// Starts after the "interface" token
|
||||
@ -2873,9 +3000,13 @@ procedure TPasParser.ParseInterface;
|
||||
var
|
||||
Section: TInterfaceSection;
|
||||
begin
|
||||
If LogEvent(pleInterface) then
|
||||
DoLog(mtInfo,nLogStartInterface,SLogStartInterface);
|
||||
Section := TInterfaceSection(CreateElement(TInterfaceSection, '', CurModule));
|
||||
CurModule.InterfaceSection := Section;
|
||||
ParseOptionalUsesList(Section);
|
||||
if Section.PendingUsedIntf<>nil then
|
||||
exit;
|
||||
ParseDeclarations(Section); // this also parses the Implementation section
|
||||
end;
|
||||
|
||||
@ -2887,7 +3018,6 @@ begin
|
||||
Section := TImplementationSection(CreateElement(TImplementationSection, '', CurModule));
|
||||
CurModule.ImplementationSection := Section;
|
||||
ParseOptionalUsesList(Section);
|
||||
Engine.CheckPendingUsedInterface(Section);
|
||||
if Section.PendingUsedIntf<>nil then
|
||||
exit;
|
||||
ParseDeclarations(Section);
|
||||
@ -3412,8 +3542,6 @@ var
|
||||
NamePos, SrcPos: TPasSourcePos;
|
||||
aModule: TPasModule;
|
||||
begin
|
||||
CheckImplicitUsedUnits(ASection);
|
||||
|
||||
NameExpr:=nil;
|
||||
InFileExpr:=nil;
|
||||
FreeExpr:=true;
|
||||
@ -3439,8 +3567,9 @@ begin
|
||||
if (msDelphi in CurrentModeswitches) then
|
||||
begin
|
||||
aModule:=ASection.GetModule;
|
||||
if (aModule<>nil) and ((aModule.ClassType=TPasModule) or (aModule is TPasUnitModule)) then
|
||||
CheckToken(tkSemicolon); // delphi does not allow it in units
|
||||
if (aModule<>nil)
|
||||
and ((aModule.ClassType=TPasModule) or (aModule is TPasUnitModule)) then
|
||||
CheckToken(tkSemicolon); // delphi does not allow in-filename in units
|
||||
end;
|
||||
ExpectToken(tkString);
|
||||
InFileExpr:=CreatePrimitiveExpr(ASection,pekString,CurTokenString);
|
||||
@ -3461,8 +3590,6 @@ begin
|
||||
ReleaseAndNil(TPasElement(InFileExpr));
|
||||
end;
|
||||
end;
|
||||
|
||||
Engine.FinishScope(stUsesClause,ASection);
|
||||
end;
|
||||
|
||||
// Starts after the variable name
|
||||
|
@ -558,10 +558,11 @@ type
|
||||
po_KeepClassForward, // disabled: delete class fowards when there is a class declaration
|
||||
po_ArrayRangeExpr, // enable: create TPasArrayType.IndexRange, disable: create TPasArrayType.Ranges
|
||||
po_SelfToken, // Self is a token. For backward compatibility.
|
||||
po_CheckModeSwitches, // stop on unknown modeswitch with an error
|
||||
po_CheckCondFunction, // stop on unknown function in conditional expression, default: return '0'
|
||||
po_StopOnErrorDirective, // stop on user $Error, $message error|fatal
|
||||
po_ExtClassConstWithoutExpr // allow const without expression in external class
|
||||
po_CheckModeSwitches, // error on unknown modeswitch with an error
|
||||
po_CheckCondFunction, // error on unknown function in conditional expression, default: return '0'
|
||||
po_StopOnErrorDirective, // error on user $Error, $message error|fatal
|
||||
po_ExtClassConstWithoutExpr, // allow const without expression in external class
|
||||
po_StopOnUnitInterface // parse only a unit name and stop at interface keyword
|
||||
);
|
||||
TPOptions = set of TPOption;
|
||||
|
||||
|
@ -62,7 +62,7 @@ Type
|
||||
Procedure Add(Const Lines : array of String);
|
||||
Procedure StartParsing;
|
||||
Procedure ParseDeclarations;
|
||||
Procedure ParseModule;
|
||||
Procedure ParseModule; virtual;
|
||||
procedure ResetParser;
|
||||
Procedure CheckHint(AHint : TPasMemberHint);
|
||||
Function AssertExpression(Const Msg: String; AExpr : TPasExpr; aKind : TPasExprKind; AClass : TClass) : TPasExpr;
|
||||
|
@ -56,7 +56,6 @@ type
|
||||
private
|
||||
FFilename: string;
|
||||
FModule: TPasModule;
|
||||
FOnContinueParsing: TOnContinueParsing;
|
||||
FOnFindUnit: TOnFindUnit;
|
||||
FParser: TPasParser;
|
||||
FStreamResolver: TStreamResolver;
|
||||
@ -72,8 +71,6 @@ type
|
||||
overload; override;
|
||||
function FindUnit(const AName, InFilename: String; NameExpr,
|
||||
InFileExpr: TPasExpr): TPasModule; override;
|
||||
procedure ContinueParsing; override;
|
||||
property OnContinueParsing: TOnContinueParsing read FOnContinueParsing write FOnContinueParsing;
|
||||
property OnFindUnit: TOnFindUnit read FOnFindUnit write FOnFindUnit;
|
||||
property Filename: string read FFilename write FFilename;
|
||||
property StreamResolver: TStreamResolver read FStreamResolver write FStreamResolver;
|
||||
@ -135,6 +132,7 @@ type
|
||||
Procedure SetUp; override;
|
||||
Procedure TearDown; override;
|
||||
procedure CreateEngine(var TheEngine: TPasTreeContainer); override;
|
||||
procedure ParseModule; override;
|
||||
procedure ParseProgram; virtual;
|
||||
procedure ParseUnit; virtual;
|
||||
procedure CheckReferenceDirectives; virtual;
|
||||
@ -777,11 +775,6 @@ begin
|
||||
Result:=OnFindUnit(Self,AName,InFilename,NameExpr,InFileExpr);
|
||||
end;
|
||||
|
||||
procedure TTestEnginePasResolver.ContinueParsing;
|
||||
begin
|
||||
OnContinueParsing(Self);
|
||||
end;
|
||||
|
||||
{ TCustomTestResolver }
|
||||
|
||||
procedure TCustomTestResolver.SetUp;
|
||||
@ -830,6 +823,45 @@ begin
|
||||
TheEngine:=ResolverEngine;
|
||||
end;
|
||||
|
||||
procedure TCustomTestResolver.ParseModule;
|
||||
var
|
||||
Section: TPasSection;
|
||||
i: Integer;
|
||||
CurResolver: TTestEnginePasResolver;
|
||||
Found: Boolean;
|
||||
begin
|
||||
inherited ParseModule;
|
||||
repeat
|
||||
Found:=false;
|
||||
for i:=0 to ModuleCount-1 do
|
||||
begin
|
||||
CurResolver:=Modules[i];
|
||||
if CurResolver.Parser=nil then continue;
|
||||
if CurResolver.Parser.CanParseContinue(Section) then
|
||||
begin
|
||||
{$IFDEF VerbosePasResolver}
|
||||
writeln('TCustomTestResolver.ParseModule continue parsing section=',GetObjName(Section),' of ',CurResolver.Filename);
|
||||
{$ENDIF}
|
||||
Found:=true;
|
||||
CurResolver.Parser.ParseContinue;
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
until not Found;
|
||||
|
||||
for i:=0 to ModuleCount-1 do
|
||||
begin
|
||||
CurResolver:=Modules[i];
|
||||
if CurResolver.CurrentParser.CurModule<>nil then
|
||||
begin
|
||||
{$IFDEF VerbosePasResolver}
|
||||
writeln('TCustomTestResolver.ParseModule module not finished "',CurResolver.RootElement.Name,'"');
|
||||
{$ENDIF}
|
||||
Fail('module not finished "'+CurResolver.RootElement.Name+'"');
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TCustomTestResolver.ParseProgram;
|
||||
var
|
||||
aFilename: String;
|
||||
@ -1592,7 +1624,7 @@ begin
|
||||
ErrFilename:=CurEngine.Scanner.CurFilename;
|
||||
ErrRow:=CurEngine.Scanner.CurRow;
|
||||
ErrCol:=CurEngine.Scanner.CurColumn;
|
||||
writeln('ERROR: TTestResolver.OnPasResolverFindUnit during parsing: '+E.ClassName+':'+E.Message
|
||||
writeln('ERROR: TCustomTestResolver.HandleError during parsing: '+E.ClassName+':'+E.Message
|
||||
+' File='+ErrFilename
|
||||
+' LineNo='+IntToStr(ErrRow)
|
||||
+' Col='+IntToStr(ErrCol)
|
||||
@ -1636,7 +1668,6 @@ begin
|
||||
Result.Filename:=aFilename;
|
||||
Result.AddObjFPCBuiltInIdentifiers;
|
||||
Result.OnFindUnit:=@OnPasResolverFindUnit;
|
||||
Result.OnContinueParsing:=@OnPasResolverContinueParsing;
|
||||
Result.OnLog:=@OnPasResolverLog;
|
||||
FModules.Add(Result);
|
||||
end;
|
||||
@ -1787,6 +1818,7 @@ function TCustomTestResolver.OnPasResolverFindUnit(SrcResolver: TPasResolver;
|
||||
CurEngine.Scanner.CurrentBoolSwitches:=[bsHints,bsNotes,bsWarnings];
|
||||
CurEngine.Parser:=TPasParser.Create(CurEngine.Scanner,
|
||||
CurEngine.StreamResolver,CurEngine);
|
||||
CurEngine.Parser.Options:=CurEngine.Parser.Options+[po_StopOnUnitInterface];
|
||||
if CompareText(ExtractFileUnitName(CurEngine.Filename),'System')=0 then
|
||||
CurEngine.Parser.ImplicitUses.Clear;
|
||||
CurEngine.Scanner.OpenFile(CurEngine.Filename);
|
||||
@ -2056,7 +2088,7 @@ begin
|
||||
writeln('TCustomTestResolver.OnPasResolverContinueParsing "',CurEngine.Module.Name,'"...');
|
||||
{$ENDIF}
|
||||
try
|
||||
CurEngine.Parser.ParseContinueImplementation;
|
||||
CurEngine.Parser.ParseContinue;
|
||||
except
|
||||
on E: Exception do
|
||||
HandleError(CurEngine,E);
|
||||
|
Loading…
Reference in New Issue
Block a user