浏览代码

pastojs: parse units queued instead of recursively

git-svn-id: trunk@38415 -
Mattias Gaertner 7 年之前
父节点
当前提交
a8617f37c1

+ 2 - 1
packages/pastojs/src/fppas2js.pp

@@ -905,7 +905,8 @@ const
   po_Pas2js = po_Resolver+[
   po_Pas2js = po_Resolver+[
     po_AsmWhole,
     po_AsmWhole,
     po_ResolveStandardTypes,
     po_ResolveStandardTypes,
-    po_ExtClassConstWithoutExpr];
+    po_ExtClassConstWithoutExpr,
+    po_StopOnUnitInterface];
 
 
   btAllJSBaseTypes = [
   btAllJSBaseTypes = [
     btChar,
     btChar,

+ 90 - 24
packages/pastojs/src/pas2jscompiler.pp

@@ -230,7 +230,6 @@ type
     FShowDebug: boolean;
     FShowDebug: boolean;
     FUseAnalyzer: TPasAnalyzer;
     FUseAnalyzer: TPasAnalyzer;
     FUsedBy: array[TUsedBySection] of TFPList; // list of TPas2jsCompilerFile
     FUsedBy: array[TUsedBySection] of TFPList; // list of TPas2jsCompilerFile
-    procedure FPasResolverContinueParsing(Sender: TObject);
     function GetUsedBy(Section: TUsedBySection; Index: integer): TPas2jsCompilerFile;
     function GetUsedBy(Section: TUsedBySection; Index: integer): TPas2jsCompilerFile;
     function GetUsedByCount(Section: TUsedBySection): integer;
     function GetUsedByCount(Section: TUsedBySection): integer;
     function OnConverterIsElementUsed(Sender: TObject; El: TPasElement): boolean;
     function OnConverterIsElementUsed(Sender: TObject; El: TPasElement): boolean;
@@ -260,6 +259,7 @@ type
     procedure OnPasTreeCheckSrcName(const Element: TPasElement);
     procedure OnPasTreeCheckSrcName(const Element: TPasElement);
     procedure OpenFile(aFilename: string);// beware: this changes FileResolver.BaseDirectory
     procedure OpenFile(aFilename: string);// beware: this changes FileResolver.BaseDirectory
     procedure ParsePascal;
     procedure ParsePascal;
+    procedure ParsePascalContinue;
     procedure CreateJS;
     procedure CreateJS;
     function GetPasFirstSection: TPasSection;
     function GetPasFirstSection: TPasSection;
     function GetPasImplSection: TPasSection;
     function GetPasImplSection: TPasSection;
@@ -309,6 +309,7 @@ type
     FFileCache: TPas2jsFilesCache;
     FFileCache: TPas2jsFilesCache;
     FFileCacheAutoFree: boolean;
     FFileCacheAutoFree: boolean;
     FFiles: TAVLTree; // tree of TPas2jsCompilerFile sorted for PasFilename
     FFiles: TAVLTree; // tree of TPas2jsCompilerFile sorted for PasFilename
+    FParsingModules: TFPList; // list of TPas2jsCompilerFile ordered by uses sections
     FHasShownLogo: boolean;
     FHasShownLogo: boolean;
     FLog: TPas2jsLogger;
     FLog: TPas2jsLogger;
     FMainFile: TPas2jsCompilerFile;
     FMainFile: TPas2jsCompilerFile;
@@ -340,6 +341,8 @@ type
       ): boolean;
       ): boolean;
     procedure AddDefinesForTargetPlatform;
     procedure AddDefinesForTargetPlatform;
     procedure AddDefinesForTargetProcessor;
     procedure AddDefinesForTargetProcessor;
+    procedure AddParsingModule(aFile: TPas2jsCompilerFile);
+    procedure RemoveParsingModule(aFile: TPas2jsCompilerFile);
     procedure CfgSyntaxError(const Msg: string);
     procedure CfgSyntaxError(const Msg: string);
     procedure ConditionEvalLog(Sender: TCondDirectiveEvaluator;
     procedure ConditionEvalLog(Sender: TCondDirectiveEvaluator;
       Args: array of const);
       Args: array of const);
@@ -373,6 +376,7 @@ type
     // DoWriteJSFile: return false to use the default write function.
     // DoWriteJSFile: return false to use the default write function.
     function DoWriteJSFile(const DestFilename: String; aWriter: TPas2JSMapper): Boolean; virtual;
     function DoWriteJSFile(const DestFilename: String; aWriter: TPas2JSMapper): Boolean; virtual;
     procedure Compile(StartTime: TDateTime);
     procedure Compile(StartTime: TDateTime);
+    procedure ParseQueue;
     function MarkNeedBuilding(aFile: TPas2jsCompilerFile; Checked: TAVLTree;
     function MarkNeedBuilding(aFile: TPas2jsCompilerFile; Checked: TAVLTree;
       var SrcFileCount: integer): boolean;
       var SrcFileCount: integer): boolean;
     procedure OptimizeProgram(aFile: TPas2jsCompilerFile); virtual;
     procedure OptimizeProgram(aFile: TPas2jsCompilerFile); virtual;
@@ -671,7 +675,6 @@ begin
   FPasFilename:=aPasFilename;
   FPasFilename:=aPasFilename;
   FPasResolver:=TPas2jsCompilerResolver.Create;
   FPasResolver:=TPas2jsCompilerResolver.Create;
   FPasResolver.Owner:=Self;
   FPasResolver.Owner:=Self;
-  FPasResolver.OnContinueParsing:=@FPasResolverContinueParsing;
   FPasResolver.OnFindModule:=@OnPasTreeFindModule;
   FPasResolver.OnFindModule:=@OnPasTreeFindModule;
   FPasResolver.OnCheckSrcName:=@OnPasTreeCheckSrcName;
   FPasResolver.OnCheckSrcName:=@OnPasTreeCheckSrcName;
   FPasResolver.OnLog:=@OnPasResolverLog;
   FPasResolver.OnLog:=@OnPasResolverLog;
@@ -808,19 +811,6 @@ begin
   Result:=TPas2jsCompilerFile(FUsedBy[Section][Index]);
   Result:=TPas2jsCompilerFile(FUsedBy[Section][Index]);
 end;
 end;
 
 
-procedure TPas2jsCompilerFile.FPasResolverContinueParsing(Sender: TObject);
-begin
-  try
-    Parser.ParseContinueImplementation;
-  except
-    on E: ECompilerTerminate do
-      raise;
-    on E: Exception do
-      HandleException(E);
-  end;
-  ParserFinished;
-end;
-
 function TPas2jsCompilerFile.GetUsedByCount(Section: TUsedBySection): integer;
 function TPas2jsCompilerFile.GetUsedByCount(Section: TUsedBySection): integer;
 begin
 begin
   Result:=FUsedBy[Section].Count;
   Result:=FUsedBy[Section].Count;
@@ -997,6 +987,8 @@ end;
 procedure TPas2jsCompilerFile.ParserFinished;
 procedure TPas2jsCompilerFile.ParserFinished;
 begin
 begin
   try
   try
+    Compiler.RemoveParsingModule(Self);
+
     if ShowDebug then
     if ShowDebug then
     begin
     begin
       Log.LogPlain('Pas-Module:');
       Log.LogPlain('Pas-Module:');
@@ -1031,20 +1023,16 @@ begin
   if ShowDebug then
   if ShowDebug then
     Log.LogPlain(['Debug: Parsing Pascal "',PasFilename,'"...']);
     Log.LogPlain(['Debug: Parsing Pascal "',PasFilename,'"...']);
   if FPasModule<>nil then
   if FPasModule<>nil then
-    raise ECompilerTerminate.Create('TPas2jsCompilerFile.ParsePascal '+PasFilename);
+    Compiler.RaiseInternalError(20180305190321,PasFilename);
   try
   try
-    // parse Pascal
+    Compiler.AddParsingModule(Self);
     PascalResolver.InterfaceOnly:=IsForeign;
     PascalResolver.InterfaceOnly:=IsForeign;
     if IsMainFile then
     if IsMainFile then
       Parser.ParseMain(FPasModule)
       Parser.ParseMain(FPasModule)
     else
     else
       Parser.ParseSubModule(FPasModule);
       Parser.ParseSubModule(FPasModule);
-    if PasModule.CustomData=nil then
-      PasModule.CustomData:=Self;
-    if (FPasModule.ImplementationSection<>nil)
-        and (FPasModule.ImplementationSection.PendingUsedIntf<>nil) then
-      exit;
-    ParserFinished;
+    if Parser.CurModule=nil then
+      ParserFinished;
   except
   except
     on E: ECompilerTerminate do
     on E: ECompilerTerminate do
       raise;
       raise;
@@ -1055,6 +1043,24 @@ begin
     PasModule.CustomData:=Self;
     PasModule.CustomData:=Self;
 end;
 end;
 
 
+procedure TPas2jsCompilerFile.ParsePascalContinue;
+begin
+  if ShowDebug then
+    Log.LogPlain(['Debug: Continue parsing Pascal "',PasFilename,'"...']);
+  if FPasModule=nil then
+    Compiler.RaiseInternalError(20180305190338,PasFilename);
+  try
+    Parser.ParseContinue;
+    if Parser.CurModule=nil then
+      ParserFinished;
+  except
+    on E: ECompilerTerminate do
+      raise;
+    on E: Exception do
+      HandleException(E);
+  end;
+end;
+
 procedure TPas2jsCompilerFile.CreateJS;
 procedure TPas2jsCompilerFile.CreateJS;
 begin
 begin
   try
   try
@@ -1404,7 +1410,7 @@ begin
 
 
     // parse Pascal
     // parse Pascal
     aFile.ParsePascal;
     aFile.ParsePascal;
-    // beware: the parser may not yet have finished due to unit cycles
+    // beware: the parser may not yet have finished
   end;
   end;
 
 
   Result:=aFile.PasModule;
   Result:=aFile.PasModule;
@@ -1451,6 +1457,18 @@ begin
   end;
   end;
 end;
 end;
 
 
+procedure TPas2jsCompiler.AddParsingModule(aFile: TPas2jsCompilerFile);
+begin
+  if FParsingModules.IndexOf(aFile)>=0 then
+    exit;
+  FParsingModules.Add(aFile);
+end;
+
+procedure TPas2jsCompiler.RemoveParsingModule(aFile: TPas2jsCompilerFile);
+begin
+  FParsingModules.Remove(aFile);
+end;
+
 procedure TPas2jsCompiler.ConditionEvalLog(Sender: TCondDirectiveEvaluator;
 procedure TPas2jsCompiler.ConditionEvalLog(Sender: TCondDirectiveEvaluator;
   Args: array of const);
   Args: array of const);
 begin
 begin
@@ -1510,6 +1528,7 @@ begin
     if MainFile=nil then exit;
     if MainFile=nil then exit;
     // parse and load Pascal files recursively
     // parse and load Pascal files recursively
     FMainFile.ParsePascal;
     FMainFile.ParsePascal;
+    ParseQueue;
 
 
     // whole program optimization
     // whole program optimization
     if MainFile.PasModule is TPasProgram then
     if MainFile.PasModule is TPasProgram then
@@ -1547,6 +1566,50 @@ begin
   end;
   end;
 end;
 end;
 
 
+procedure TPas2jsCompiler.ParseQueue;
+var
+  i: Integer;
+  aFile: TPas2jsCompilerFile;
+  Found: Boolean;
+  Section: TPasSection;
+begin
+  // parse til exception or all modules have finished
+  repeat
+    {$IFDEF VerbosePasResolver}
+    writeln('TPas2jsCompiler.ParseQueue FParsingModules.Count=',FParsingModules.Count);
+    {$ENDIF}
+    Found:=false;
+    for i:=0 to FParsingModules.Count-1 do
+      begin
+      aFile:=TPas2jsCompilerFile(FParsingModules[i]);
+      if not aFile.Parser.CanParseContinue(Section) then
+        continue;
+      Found:=true;
+      {$IFDEF VerbosePasResolver}
+      writeln('TPas2jsCompiler.ParseQueue aFile=',aFile.PasFilename,' Section=',GetObjName(Section));
+      {$ENDIF}
+      aFile.ParsePascalContinue;
+      break;
+      end;
+  until not Found;
+  {$IFDEF VerbosePasResolver}
+  writeln('TPas2jsCompiler.ParseQueue END FParsingModules.Count=',FParsingModules.Count);
+  {$ENDIF}
+
+  // check consistency
+  for i:=0 to FParsingModules.Count-1 do
+    begin
+    aFile:=TPas2jsCompilerFile(FParsingModules[i]);
+    if aFile.Parser.CurModule<>nil then
+      begin
+      {$IFDEF VerbosePasResolver}
+      writeln('TPas2jsCompiler.ParseQueue aFile=',aFile.PasFilename,' was not finished');
+      {$ENDIF}
+      RaiseInternalError(20180305185342,aFile.PasFilename);
+      end;
+    end;
+end;
+
 function TPas2jsCompiler.MarkNeedBuilding(aFile: TPas2jsCompilerFile;
 function TPas2jsCompiler.MarkNeedBuilding(aFile: TPas2jsCompilerFile;
   Checked: TAVLTree; var SrcFileCount: integer): boolean;
   Checked: TAVLTree; var SrcFileCount: integer): boolean;
 
 
@@ -3014,6 +3077,7 @@ begin
   //FConditionEval.OnEvalFunction:=@ConditionEvalFunction;
   //FConditionEval.OnEvalFunction:=@ConditionEvalFunction;
 
 
   FFiles:=TAVLTree.Create(@CompareCompilerFilesPasFile);
   FFiles:=TAVLTree.Create(@CompareCompilerFilesPasFile);
+  FParsingModules:=TFPList.Create;
   FUnits:=TAVLTree.Create(@CompareCompilerFilesPasUnitname);
   FUnits:=TAVLTree.Create(@CompareCompilerFilesPasUnitname);
 
 
   InitParamMacros;
   InitParamMacros;
@@ -3026,6 +3090,7 @@ begin
 
 
   FMainFile:=nil;
   FMainFile:=nil;
   FreeAndNil(FUnits);
   FreeAndNil(FUnits);
+  FreeAndNil(FParsingModules);
   FFiles.FreeAndClear;
   FFiles.FreeAndClear;
   FreeAndNil(FFiles);
   FreeAndNil(FFiles);
 
 
@@ -3116,6 +3181,7 @@ begin
 
 
   FMainFile:=nil;
   FMainFile:=nil;
   FUnits.Clear;
   FUnits.Clear;
+  FParsingModules.Clear;
   FFiles.FreeAndClear;
   FFiles.FreeAndClear;
 
 
   FCompilerExe:='';
   FCompilerExe:='';

+ 3 - 1
packages/pastojs/src/pas2jsfiler.pp

@@ -78,7 +78,8 @@ const
     'CheckModeSwitches',
     'CheckModeSwitches',
     'CheckCondFunction',
     'CheckCondFunction',
     'StopOnErrorDirective',
     'StopOnErrorDirective',
-    'ExtClassConstWithoutExpr');
+    'ExtClassConstWithoutExpr',
+    'StopOnUnitInterface');
 
 
   PJUDefaultModeSwitches: TModeSwitches = [
   PJUDefaultModeSwitches: TModeSwitches = [
     msObjfpc,
     msObjfpc,
@@ -4234,6 +4235,7 @@ var
   i: Integer;
   i: Integer;
 begin
 begin
   Section:=Scope.Element as TPasSection;
   Section:=Scope.Element as TPasSection;
+  Scope.UsesFinished:=true;
   Scope.Finished:=true;
   Scope.Finished:=true;
   Data:=Obj.Find('Uses');
   Data:=Obj.Find('Uses');
   if Data<>nil then
   if Data<>nil then

+ 35 - 9
packages/pastojs/tests/tcmodules.pas

@@ -108,6 +108,7 @@ type
     Procedure Add(Line: string); virtual;
     Procedure Add(Line: string); virtual;
     Procedure Add(const Lines: array of string);
     Procedure Add(const Lines: array of string);
     Procedure StartParsing; virtual;
     Procedure StartParsing; virtual;
+    procedure ParseModuleQueue; virtual;
     procedure ParseModule; virtual;
     procedure ParseModule; virtual;
     procedure ParseProgram; virtual;
     procedure ParseProgram; virtual;
     procedure ParseUnit; virtual;
     procedure ParseUnit; virtual;
@@ -140,7 +141,7 @@ type
     procedure HandlePasResolveError(E: EPasResolve);
     procedure HandlePasResolveError(E: EPasResolve);
     procedure HandlePas2JSError(E: EPas2JS);
     procedure HandlePas2JSError(E: EPas2JS);
     procedure HandleException(E: Exception);
     procedure HandleException(E: Exception);
-    procedure RaiseException(E: Exception);
+    procedure FailException(E: Exception);
     procedure WriteSources(const aFilename: string; aRow, aCol: integer);
     procedure WriteSources(const aFilename: string; aRow, aCol: integer);
     function IndexOfResolver(const Filename: string): integer;
     function IndexOfResolver(const Filename: string): integer;
     function GetResolver(const Filename: string): TTestEnginePasResolver;
     function GetResolver(const Filename: string): TTestEnginePasResolver;
@@ -922,8 +923,10 @@ begin
   InitScanner(FScanner);
   InitScanner(FScanner);
 
 
   FEngine:=AddModule(Filename);
   FEngine:=AddModule(Filename);
+  FEngine.Scanner:=FScanner;
 
 
   FParser:=TTestPasParser.Create(FScanner,FFileResolver,FEngine);
   FParser:=TTestPasParser.Create(FScanner,FFileResolver,FEngine);
+  FEngine.Parser:=FParser;
   Parser.Options:=po_tcmodules;
   Parser.Options:=po_tcmodules;
 
 
   FModule:=Nil;
   FModule:=Nil;
@@ -968,8 +971,6 @@ begin
     FModule:=nil;
     FModule:=nil;
     end;
     end;
   FreeAndNil(FSource);
   FreeAndNil(FSource);
-  FreeAndNil(FParser);
-  FreeAndNil(FScanner);
   FreeAndNil(FFileResolver);
   FreeAndNil(FFileResolver);
   if FModules<>nil then
   if FModules<>nil then
     begin
     begin
@@ -1005,6 +1006,30 @@ begin
   Writeln(Src);
   Writeln(Src);
 end;
 end;
 
 
+procedure TCustomTestModule.ParseModuleQueue;
+var
+  i: Integer;
+  CurResolver: TTestEnginePasResolver;
+  Found: Boolean;
+  Section: TPasSection;
+begin
+  // parse til exception or all modules finished
+  while not SkipTests do
+    begin
+    Found:=false;
+    for i:=0 to ResolverCount-1 do
+      begin
+      CurResolver:=Resolvers[i];
+      if CurResolver.CurrentParser=nil then continue;
+      if not CurResolver.CurrentParser.CanParseContinue(Section) then continue;
+      CurResolver.Parser.ParseContinue;
+      Found:=true;
+      break;
+      end;
+    if not Found then break;
+    end;
+end;
+
 procedure TCustomTestModule.ParseModule;
 procedure TCustomTestModule.ParseModule;
 begin
 begin
   if SkipTests then exit;
   if SkipTests then exit;
@@ -1012,6 +1037,7 @@ begin
   try
   try
     StartParsing;
     StartParsing;
     Parser.ParseMain(FModule);
     Parser.ParseMain(FModule);
+    ParseModuleQueue;
   except
   except
     on E: Exception do
     on E: Exception do
       HandleException(E);
       HandleException(E);
@@ -1475,7 +1501,7 @@ begin
   writeln('ERROR: TCustomTestModule.HandleScannerError '+E.ClassName+':'+E.Message
   writeln('ERROR: TCustomTestModule.HandleScannerError '+E.ClassName+':'+E.Message
     +' '+Scanner.CurFilename
     +' '+Scanner.CurFilename
     +'('+IntToStr(Scanner.CurRow)+','+IntToStr(Scanner.CurColumn)+')');
     +'('+IntToStr(Scanner.CurRow)+','+IntToStr(Scanner.CurColumn)+')');
-  RaiseException(E);
+  FailException(E);
 end;
 end;
 
 
 procedure TCustomTestModule.HandleParserError(E: EParserError);
 procedure TCustomTestModule.HandleParserError(E: EParserError);
@@ -1486,7 +1512,7 @@ begin
     +' '+E.Filename+'('+IntToStr(E.Row)+','+IntToStr(E.Column)+')'
     +' '+E.Filename+'('+IntToStr(E.Row)+','+IntToStr(E.Column)+')'
     +' MainModuleScannerLine="'+Scanner.CurLine+'"'
     +' MainModuleScannerLine="'+Scanner.CurLine+'"'
     );
     );
-  RaiseException(E);
+  FailException(E);
 end;
 end;
 
 
 procedure TCustomTestModule.HandlePasResolveError(E: EPasResolve);
 procedure TCustomTestModule.HandlePasResolveError(E: EPasResolve);
@@ -1498,7 +1524,7 @@ begin
   WriteSources(P.FileName,P.Row,P.Column);
   WriteSources(P.FileName,P.Row,P.Column);
   writeln('ERROR: TCustomTestModule.HandlePasResolveError '+E.ClassName+':'+E.Message
   writeln('ERROR: TCustomTestModule.HandlePasResolveError '+E.ClassName+':'+E.Message
     +' '+P.FileName+'('+IntToStr(P.Row)+','+IntToStr(P.Column)+')');
     +' '+P.FileName+'('+IntToStr(P.Row)+','+IntToStr(P.Column)+')');
-  RaiseException(E);
+  FailException(E);
 end;
 end;
 
 
 procedure TCustomTestModule.HandlePas2JSError(E: EPas2JS);
 procedure TCustomTestModule.HandlePas2JSError(E: EPas2JS);
@@ -1511,7 +1537,7 @@ begin
   writeln('ERROR: TCustomTestModule.HandlePas2JSError '+E.ClassName+':'+E.Message
   writeln('ERROR: TCustomTestModule.HandlePas2JSError '+E.ClassName+':'+E.Message
     +' '+E.PasElement.SourceFilename
     +' '+E.PasElement.SourceFilename
     +'('+IntToStr(Row)+','+IntToStr(Col)+')');
     +'('+IntToStr(Row)+','+IntToStr(Col)+')');
-  RaiseException(E);
+  FailException(E);
 end;
 end;
 
 
 procedure TCustomTestModule.HandleException(E: Exception);
 procedure TCustomTestModule.HandleException(E: Exception);
@@ -1532,11 +1558,11 @@ begin
       WriteSources('',0,0);
       WriteSources('',0,0);
       writeln('ERROR: TCustomTestModule.HandleException '+E.ClassName+':'+E.Message);
       writeln('ERROR: TCustomTestModule.HandleException '+E.ClassName+':'+E.Message);
       end;
       end;
-    RaiseException(E);
+    FailException(E);
     end;
     end;
 end;
 end;
 
 
-procedure TCustomTestModule.RaiseException(E: Exception);
+procedure TCustomTestModule.FailException(E: Exception);
 var
 var
   MsgNumber: Integer;
   MsgNumber: Integer;
 begin
 begin

+ 12 - 1
packages/pastojs/tests/tcunitsearch.pas

@@ -127,6 +127,7 @@ type
   TTestCLI_UnitSearch = class(TCustomTestCLI)
   TTestCLI_UnitSearch = class(TCustomTestCLI)
   published
   published
     procedure TestUS_Program;
     procedure TestUS_Program;
+    procedure TestUS_UsesEmptyFileFail;
 
 
     procedure TestUS_UsesInFile;
     procedure TestUS_UsesInFile;
     procedure TestUS_UsesInFile_Duplicate;
     procedure TestUS_UsesInFile_Duplicate;
@@ -522,6 +523,16 @@ begin
   Compile(['test1.pas','-va']);
   Compile(['test1.pas','-va']);
 end;
 end;
 
 
+procedure TTestCLI_UnitSearch.TestUS_UsesEmptyFileFail;
+begin
+  AddFile('system.pp','');
+  AddFile('test1.pas',[
+    'begin',
+    'end.']);
+  Compile(['test1.pas',''],ExitCodeSyntaxError);
+  AssertEquals('ErrorMsg','Expected "unit"',ErrorMsg);
+end;
+
 procedure TTestCLI_UnitSearch.TestUS_UsesInFile;
 procedure TTestCLI_UnitSearch.TestUS_UsesInFile;
 begin
 begin
   AddUnit('system.pp',[''],['']);
   AddUnit('system.pp',[''],['']);
@@ -577,7 +588,7 @@ begin
     'begin',
     'begin',
     'end.']);
     'end.']);
   Compile(['test1.pas','-Jc'],ExitCodeSyntaxError);
   Compile(['test1.pas','-Jc'],ExitCodeSyntaxError);
-  AssertEquals('ErrorMsg','Duplicate file found: "/home/user/sub/unit1.pas" and "/home/user/unit1.pas"',ErrorMsg);
+  AssertEquals('ErrorMsg','Duplicate file found: "/home/user/unit1.pas" and "/home/user/sub/unit1.pas"',ErrorMsg);
 end;
 end;
 
 
 Initialization
 Initialization