From d34e9b79bff016d1fc38329f2dab9f7c5c5c8b4b Mon Sep 17 00:00:00 2001 From: Mattias Gaertner Date: Mon, 5 Mar 2018 20:58:04 +0000 Subject: [PATCH] fcl-passrc: optional parse units queued instead of recursively git-svn-id: trunk@38414 - --- packages/fcl-passrc/src/pasresolver.pp | 90 +++++++---- packages/fcl-passrc/src/pparser.pp | 177 ++++++++++++++++++--- packages/fcl-passrc/src/pscanner.pp | 9 +- packages/fcl-passrc/tests/tcbaseparser.pas | 2 +- packages/fcl-passrc/tests/tcresolver.pas | 54 +++++-- 5 files changed, 263 insertions(+), 69 deletions(-) diff --git a/packages/fcl-passrc/src/pasresolver.pp b/packages/fcl-passrc/src/pasresolver.pp index 97e16fe1ba..4bd6aeea14 100644 --- a/packages/fcl-passrc/src/pasresolver.pp +++ b/packages/fcl-passrc/src/pasresolver.pp @@ -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; diff --git a/packages/fcl-passrc/src/pparser.pp b/packages/fcl-passrc/src/pparser.pp index 733cc98ceb..f0ecac521d 100644 --- a/packages/fcl-passrc/src/pparser.pp +++ b/packages/fcl-passrc/src/pparser.pp @@ -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 diff --git a/packages/fcl-passrc/src/pscanner.pp b/packages/fcl-passrc/src/pscanner.pp index 47e3873c62..083eb5c113 100644 --- a/packages/fcl-passrc/src/pscanner.pp +++ b/packages/fcl-passrc/src/pscanner.pp @@ -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; diff --git a/packages/fcl-passrc/tests/tcbaseparser.pas b/packages/fcl-passrc/tests/tcbaseparser.pas index e4de184697..a4e29908fb 100644 --- a/packages/fcl-passrc/tests/tcbaseparser.pas +++ b/packages/fcl-passrc/tests/tcbaseparser.pas @@ -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; diff --git a/packages/fcl-passrc/tests/tcresolver.pas b/packages/fcl-passrc/tests/tcresolver.pas index effff0e159..6bef490c63 100644 --- a/packages/fcl-passrc/tests/tcresolver.pas +++ b/packages/fcl-passrc/tests/tcresolver.pas @@ -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);