IMPLEMENTATION MODULE YaflProject;

FROM Conversions IMPORT IntConversions;
FROM Directories IMPORT Operations, DirectoryEntry;
FROM Streams IMPORT StdOut, StdErr;
IMPORT String;
IMPORT SYSTEM;
FROM YaflDictionary IMPORT ClassReference, MethodReference, EntryReference,
                           ClassDictionary, CallDictionary, MethodDictionary,
                           ModuleDictionary, MethodQueue;
FROM YaflWorlds IMPORT WorldList;
FROM YaflModules IMPORT ImplementationModule;
FROM YaflClDefinition IMPORT ClassDefinition;
IMPORT YaflWorlds;
FROM Ycc IMPORT Yc, CompilationRun;
FROM YaflCfg IMPORT YaflCfg, CurrentSpot;
IMPORT Space;

  CLASS ProjectFile;    
  
    CONST
      CommentChar = '#';
      EscapeChar = '\';
      Version = Yc.Version;
      
    VAR
      TheModules: StringList(ProjectModule);
      TheWorlds: StringList(ProjectWorld);
      TheRootModule: ProjectModule;
      TheRootModuleName,
      TheRootClassName: ARRAY OF CHAR;
      
    REDEFINE METHOD CREATE(RootClass: ARRAY OF CHAR);
      BEGIN
      TheModules.CREATE;     
      TheWorlds.CREATE;
      TheRootClassName := RootClass;
      END CREATE;
                            
    METHOD SetRootModule(TheModule: ProjectModule);
      BEGIN
      TheRootModule := TheModule;
      END SetRootModule;
      
    METHOD GetEntireLine (Input: InputStream): ARRAY OF CHAR;
      BEGIN             
      IF NOT Input.Eof THEN
        RESULT := Input.ReadLine;
        WHILE ((RESULT.SIZE > 0) AND (RESULT[RESULT.SIZE - 1] = EscapeChar))
            AND NOT Input.Eof DO
          RESULT := RESULT.SLICE (0, RESULT.SIZE - 1) + Input.ReadLine;
          END;
        END;
      IF RESULT <> VOID THEN
        FOR i IN 0 TO RESULT.SIZE - 1 | RESULT [i] = SYSTEM.CHR(SYSTEM.Tab) DO
          RESULT [i] := ' ';
          END;
        END;
      END GetEntireLine; 
      
    METHOD Parse (Input: InputStream): BOOLEAN;
      VAR
        Line: ARRAY OF CHAR;
      BEGIN
      RESULT := TRUE;
      WHILE NOT Input.Eof DO
        Line := GetEntireLine (Input);
        IF (Line <> VOID) AND (Line.SIZE > 0) THEN
          IF Line[0] <> CommentChar THEN
            RESULT := ParseLine (Line) AND RESULT;
            END;
          END;
        END;
      END Parse;

    METHOD Load: BOOLEAN;
      VAR
        Input: InputStream;
      BEGIN
      Input.CREATE;
      Input.Open (ProjectFileName, Input.ReadAccess);
      IF Input.ErrorCode = Input.NoError THEN
        RESULT := Parse(Input);
        Input.Close;
       ELSE
        RESULT := FALSE;
        END;
      END Load;
     
    METHOD ParseLine (Line: ARRAY OF CHAR): BOOLEAN;
      VAR
        Words: ARRAY OF ARRAY OF CHAR;
        NewModule: ProjectModule;
        NewWorld: ProjectWorld;
      BEGIN
      RESULT := TRUE;                           
      Words := String.BreakInWords (Source := Line, 
                                    SkipSeparator := " ",
                                    KeepSeparator := VOID);
      IF (Words <> VOID) AND (Words.SIZE > 0) THEN
        CASE PrjKeywords.Code (Words[0]) OF
          PrjKeywords.World:
            NewWorld.CREATE(VOID);
            NewWorld.Parse(Words);
            TheWorlds.Append (NewWorld);
            END;
          PrjKeywords.Module:
            NewModule.CREATE(THIS);
            NewModule.Parse (Words);            
            
            -- Patched by Louis

            IF GetModule (NewModule.Get) = VOID THEN
              TheModules.Append (NewModule); 
             ELSE
              IF YaflCfg.VerboseLevel > 2 THEN
                StdOut.WriteLine (NewModule.Get + " specified twice");
                END; -- IF
              END; -- IF
            END;
          PrjKeywords.Root :
            TheRootModuleName := Words[1];
            TheRootClassName := Words[2];
            END;
         ELSE
          RESULT := FALSE;
          END;
        END;
      END ParseLine;
      
    METHOD Modules: StringList(ProjectModule);
      BEGIN
      RESULT := TheModules;
      END Modules;
      
    METHOD Worlds: StringList(ProjectWorld);
      BEGIN
      RESULT := TheWorlds;
      END Worlds;
      
    METHOD RootModule: ProjectModule;
      BEGIN
      IF TheRootModule = VOID THEN
        IF TheRootModuleName <> VOID THEN
          TheRootModule := GetModule (TheRootModuleName);
          END;
        END;
      RESULT := TheRootModule;
      END RootModule;
      
    METHOD RootModuleName: ARRAY OF CHAR;
      BEGIN              
      IF RootModule <> VOID THEN
        RESULT := RootModule.Get;
       ELSE
        RESULT := TheRootModuleName;
        END;
      END RootModuleName;
      
    METHOD RootClass: ARRAY OF CHAR;
      BEGIN
      RESULT := TheRootClassName;
      END RootClass;               
      
    METHOD SetRootClass (Name: ARRAY OF CHAR);
      BEGIN
      TheRootClassName := Name;
      END SetRootClass;
      
    METHOD GetModule (ModuleName: ARRAY OF CHAR): ProjectModule;
      BEGIN              
      RESULT := TheModules.FindString (ModuleName);
      END GetModule;
      
    METHOD ClearTimeStamps;
      BEGIN        
      FOR Mod IN TheModules DO
        Mod.ClearTimeStamps;
        END;
      END ClearTimeStamps;

    METHOD Save: BOOLEAN;
      VAR
        Output: OutputStream;
      BEGIN
      Output.CREATE;
      Output.Create (ProjectFileName, Output.WriteAccess);
      IF Output.ErrorCode = Output.NoError THEN
        IF YaflCfg.VerboseLevel > 0 THEN
          StdOut.WriteLine ("Generating "+ ProjectFileName);
          END;
        SaveStream (Output);
        Output.Close;
        RESULT := TRUE;
       ELSE
        RESULT := FALSE;
        END;
      END Save;
 
    METHOD SaveStream (Output: OutputStream);
          
        METHOD GenerateWorlds (Output: OutputStream);
          BEGIN
          FOR w IN TheWorlds DO
            w.SaveStream (Output);
            END;          
          END GenerateWorlds;
          
      BEGIN
      Output.WriteLine ("###############################################");
      Output.WriteLine ("#  Automatically generated project file [" +
                              Version + "]");
      Output.WriteLine ("#  Main class:  " + TheRootClassName);
      Output.WriteLine ("#  Main module: " + TheRootModuleName);
      Output.WriteLine ("###############################################");
      IF RootModule <> VOID THEN
        Output.WriteLine ("ROOT " + RootModuleName + " " + 
                                    TheRootClassName);                              
        END;                                
      GenerateWorlds (Output);
      FOR Mod IN TheModules DO
        Output.Flush;
        Mod.SaveStream (Output);
        END;
      END SaveStream;

     METHOD ProjectFileName: ARRAY OF CHAR;
       BEGIN
       RESULT := RootModule.World.
                   TrueWorld.BuildProjectFName (TheRootClassName,
                                                YaflCfg.ProjectFileExt);
       END ProjectFileName;

    METHOD LinkerResponseFileName: ARRAY OF CHAR;
      BEGIN
      RESULT := RootModule.World.
                  TrueWorld.BuildProjectFName (TheRootClassName,
                                               YaflCfg.LinkerResponseFileExt);
      END LinkerResponseFileName;

    METHOD StubFileName: ARRAY OF CHAR;
      BEGIN
      RESULT := RootModule.World.TrueWorld.
                 BuildTargetFName (TheRootClassName,YaflCfg.IntermediateExt);
      END StubFileName;

     METHOD FindWorld (TheWorld: World): ProjectWorld;
       BEGIN
       ASSERT TheWorld <> VOID;
       RESULT := FIRST w IN TheWorlds :- w.TrueWorld = TheWorld;
       END FindWorld;
      
     METHOD FindModule (TheModule: DefinitionModule): ProjectModule;
       BEGIN
       ASSERT TheModule <> VOID;
       RESULT := FIRST m IN TheModules :- m.TrueModule = TheModule;
       END FindModule;
       
    METHOD UseWorlds (Worlds: ARRAY OF World);
      VAR
        PWorld: ProjectWorld;
        BEGIN            
      TheWorlds.CREATE;
      FOR w IN Worlds DO
        PWorld.CREATE (w);
        TheWorlds.Append (PWorld);
        END;
      END UseWorlds;

    METHOD SetPatterns (Mapper: PatternMapper);
      BEGIN
      Mapper.Associate ('A', TheRootClassName);
      END SetPatterns;
      
    METHOD NeedsStubRecompilation(MissingFilesOnly: BOOLEAN): BOOLEAN;
      VAR
        SourceFName, TargetFName: ARRAY OF CHAR;
        SourceInstant, TargetInstant: Instant;
        Entry: DirectoryEntry;
      BEGIN                      
      SourceFName := RootModule.World.TrueWorld.
                     BuildTargetFName (RootClass, YaflCfg.IntermediateExt);
      TargetFName := RootModule.World.TrueWorld.
                     BuildTargetFName (RootClass, YaflCfg.ObjExt);
      IF MissingFilesOnly THEN
        RESULT := NOT Operations.Exist(TargetFName);
       ELSE                     
        Entry := Operations.GetEntry (SourceFName);
        IF Entry <> VOID THEN
          SourceInstant := Entry.LastModification;
          END;
        Entry := Operations.GetEntry (TargetFName);
        IF Entry <> VOID THEN
          TargetInstant := Entry.LastModification;
          END;
        RESULT := (TargetInstant = VOID) OR 
		  ((SourceInstant <> VOID) AND
                  NOT TargetInstant.IsGreater(SourceInstant));
        END;
      END NeedsStubRecompilation;
        
    VAR
      TheRootClassRef : ClassReference;
                                                                         
    METHOD SetRootClassRef (ClassRef : ClassReference);
      BEGIN
      TheRootClassRef := ClassRef;
      END SetRootClassRef;
      
    METHOD EnterInDictionary(FrontEnd: YaflFrontEnd): BOOLEAN;
      VAR 
        TheProjectModule      : ProjectModule;
        ModuleName, ClassName : ARRAY OF CHAR;
      BEGIN
      RESULT := TRUE;

      ASSERT NOT YaflCfg.PleaseGenerateCode;
      FOR i := 0 TO Modules.Size - 1 WHILE RESULT DO
        TheProjectModule := Modules.Get(i);
        IF YaflCfg.VerboseLevel > 0 THEN
          StdOut.WriteInt (i+1, 0);
          StdOut.WriteChar ('/');
          StdOut.WriteInt (Modules.Size,0);
          StdOut.WriteLine (':' + TheProjectModule.Get);
          END;
                                                                     
        RESULT := RESULT AND TheProjectModule.EnterInDictionary(FrontEnd);
        END; -- FOR     
      ModuleName := Space.StoreString (RootModule.Get);
      ClassName  := Space.StoreString (RootClass);
      SetRootClassRef (ClassDictionary.FindClass (ModuleName, ClassName));
      ASSERT TheRootClassRef <> VOID;
      CallDictionary.FillStructure;
      MethodDictionary.FillStructure;
      END EnterInDictionary;
                                    
    METHOD RootClassRef : ClassReference;
      BEGIN
      RESULT := TheRootClassRef;
      END RootClassRef;
      
    METHOD VisitParseTree;
      VAR
        k: INTEGER;
      BEGIN    
      -----------------------------
      -- With each method in ToVisit, one can access to
      -- other methods to put in ToVisit, etc...
      ----------------------------- 
      RootClassRef.MarkCreated;
      ClassDictionary.VisitOnceClasses;
      WHILE (MethodQueue.Size > 0) DO
        MethodQueue.VisitTop;
        k := k + 1;
        IF k MOD 256 = 0 THEN
          StdOut.WriteString ("Visiting methods: ");
          StdOut.WriteInt (k,0);
          StdOut.WriteString (" Waiting: ");
          StdOut.WriteInt (MethodQueue.Size,0);
          StdOut.WriteLn; 
          END;
        END;
      END VisitParseTree;

    -- Generates the global optimized code      
    METHOD GenerateGlobalOptimizedCode(Comp : Yc): BOOLEAN;
      VAR 
        CompRun   : CompilationRun;
        MainModule: ImplementationModule;
        MainClass: ClassDefinition;
        Counter  : INTEGER;
      BEGIN
      RESULT := TRUE;
      FOR Mod IN Modules WHILE RESULT DO
        Comp.CheckMemory;
        Counter := Counter + 1;
        StdOut.WriteInt (Counter, 0);
        StdOut.WriteChar ('/');
        StdOut.WriteInt (Modules.Size,0);
        StdOut.WriteLine (':' + Mod.Get);

        -- Rereads the module
        ASSERT NOT YaflCfg.PleaseGenerateCode;
        CompRun.CREATE(Mod.Get, TRUE, Comp.GetCodeGCList);
        
        -- Compile the module with global optimizations 
        CurrentSpot.SetCurrentCompilationRun (CompRun);
        CompRun.CompiledModule.AttachToCurrentWorld;
        CompRun.CompiledModule.RemoveUnused;
        YaflCfg.SetGenerateCode(TRUE);
        CompRun.CompiledModule.ClearAllGc; -- OOO 
        CompRun.CompiledModule.Gc.GenerateCode;
        YaflCfg.SetGenerateCode(FALSE);

        RESULT := RESULT AND CompRun.Ok;
        CompRun.EraseCompiledModule;
        CompRun := VOID;
        CurrentSpot.SetCurrentCompilationRun (VOID);
        END; -- FOR     
        
      Comp.CheckMemory;
      CompRun.CREATE(RootModule.Get, TRUE, Comp.GetCodeGCList);
      MainModule := CompRun.CompiledModule;
      MainClass := MainModule.DefModule.Classes.Find(
                                              Space.StoreString(RootClass));
      IF MainClass = VOID THEN
        StdOut.WriteLine("Could ot find class "+ RootClass);
        RESULT := FALSE;
        END;
      Comp.GenerateStub (THIS, MainModule, MainClass);
      END GenerateGlobalOptimizedCode; 
                 
   METHOD Dump;
     BEGIN    
     StdOut.WriteLine ("Root class " + RootClass);
     StdOut.WriteLine ("Root module " + RootModule.Get);
     FOR TheCount := 0 TO Modules.Size -1 DO 
       StdOut.WriteLine ("Module " +
                         IntConversions.IntToString (TheCount, 0) +
                         " : " + Modules.Get (TheCount).Get);
       END; -- FOR
     END Dump;   
      
   END ProjectFile; 
----------------------------------------------  
  CLASS ProjectModule;          
    INHERITS StringElement;
    
    VAR
      TheFather: ProjectFile;
      DependantModuleName : ARRAY OF ARRAY OF CHAR;
      TheDepends: ARRAY OF ProjectModule;     
      TheWorld: ProjectWorld;
      TheTrueModule: DefinitionModule;
      
      
    REDEFINE METHOD CREATE (Father: ProjectFile);
      BEGIN
      ASSERT Father <> VOID;
      THIS.TheFather := Father;
      BASE (VOID);
      END CREATE;
      
    METHOD Father: ProjectFile;
      BEGIN
      RESULT := TheFather;
      END Father;

    METHOD SetTrueModule (Module: DefinitionModule);
      BEGIN
      THIS.TheTrueModule := Module;
      IF Module <> VOID THEN
        Set (Module.Id.Data);
        TheWorld := Father.FindWorld (Module.GetWorld);  
        DependantModuleName := VOID;
        TheDepends := VOID;      
        END;
      END SetTrueModule;

    METHOD TrueModule: DefinitionModule;
      BEGIN
      RESULT := TheTrueModule;
      END TrueModule;

    METHOD Parse (Words: ARRAY OF ARRAY OF CHAR);
      VAR
        WorldNr: INTEGER;
      BEGIN       
      WorldNr := IntConversions.StringToInt (Words[1]);
      TheWorld := Father.Worlds.Get(WorldNr);
      Set (Words[2]);
      ASSERT PrjKeywords.Code (Words[3]) = PrjKeywords.Depends;
      DependantModuleName := Words.SLICE (4, Words.SIZE - 4);
      END Parse;
      
    METHOD Depends: ARRAY OF ProjectModule;     
      BEGIN
      IF TheDepends = VOID THEN
        TheDepends.CREATE (DependantModuleName.SIZE);
        FOR i := 0 TO TheDepends.SIZE - 1 DO
          TheDepends[i] := Father.GetModule (DependantModuleName[i]);
          END;
        END;
      RESULT := TheDepends;
      END Depends;
      
    METHOD World: ProjectWorld;
      BEGIN     
      RESULT := THIS.TheWorld;
      END World;
      
    METHOD FileName (Kind: INTEGER): ARRAY OF CHAR;
      VAR
        TheWorld: YaflWorlds.World;
      BEGIN             
      TheWorld := World.TrueWorld;
      ASSERT TheWorld <> YaflWorlds.DefaultWorld;
      CASE Kind OF
        ImpModule:
          RESULT := TheWorld.BuildSourceFName (Get, YaflCfg.ImpExt);
          END;
        DefModule:
          RESULT := TheWorld.BuildSourceFName (Get, YaflCfg.DefExt);
          END;
        CFile:
          RESULT := TheWorld.BuildTargetFName (Get, YaflCfg.IntermediateExt);
          END;
        H1File:
          RESULT := TheWorld.BuildTargetFName (Get, YaflCfg.Header1Ext);
          END;
        H2File:
          RESULT := TheWorld.BuildTargetFName (Get, YaflCfg.Header2Ext);
          END;
        ObjFile:
          RESULT := TheWorld.BuildTargetFName (Get, YaflCfg.ObjExt);
          END;
        END;
      END FileName;                             
      
    VAR
      TimeStamps: ARRAY OF Instant;
      UsedTimeStamps: ARRAY OF BOOLEAN;
      
    METHOD InstantFileTime (Kind: INTEGER): Instant;
      VAR
        Entry: DirectoryEntry;
      BEGIN
      Entry := Operations.GetEntry (FileName (Kind));
      IF Entry <> VOID THEN
        RESULT := Entry.LastModification;
       ELSE
        IF YaflCfg.VerboseLevel > 0 THEN
          StdErr.WriteLine ("Could not open file:" + FileName (Kind));
          END; -- IF
        END; -- IF
      END InstantFileTime;
            
    METHOD FileTime (Kind: INTEGER): Instant;
      BEGIN                        
      IF TimeStamps = VOID THEN
        TimeStamps.CREATE (ObjFile+1);
        UsedTimeStamps.CREATE (ObjFile+1);
        END;
      IF NOT UsedTimeStamps[Kind] THEN
        UsedTimeStamps[Kind] := TRUE;
        TimeStamps [Kind] := InstantFileTime (Kind);
        END;
      RESULT := TimeStamps[Kind];
      END FileTime;
      
    METHOD ExistFile (Kind: INTEGER): BOOLEAN;
      VAR
        a: ARRAY OF CHAR;
      BEGIN              
      a := FileName(Kind);
      RESULT := Operations.Exist (a);
      END ExistFile;
          
    METHOD ImplementationModuleTime: Instant;
      BEGIN
      RESULT := FileTime (ImpModule);
      END ImplementationModuleTime;
      
    METHOD DefinitionModuleTime: Instant;
      BEGIN
      RESULT := FileTime (DefModule);
      END DefinitionModuleTime;
      
    METHOD CFileTime: Instant;
      BEGIN
      RESULT := FileTime (CFile);
      END CFileTime;
                               
    METHOD H1FileTime: Instant;
      BEGIN
      RESULT := FileTime (H1File);
      END H1FileTime;
                               
    METHOD H2FileTime: Instant;
      BEGIN
      RESULT := FileTime (H2File);
      END H2FileTime;
                               
    METHOD ObjFileTime: Instant;
      BEGIN
      RESULT := FileTime (ObjFile);
      END ObjFileTime;                    
      
    METHOD ClearTimeStamps;
      BEGIN                                   
      IF UsedTimeStamps <> VOID THEN
        FOR i := 0 TO UsedTimeStamps.SIZE - 1 DO
          UsedTimeStamps[i] := FALSE;
          END;
        END;
      END ClearTimeStamps;
      
    ------------------------------------------------
      
    METHOD NeedsEnterInDictionary : BOOLEAN;
      BEGIN
      RESULT := (InstantFileTime (ImpModule) = VOID) OR
                (InstantFileTime (DefModule) = VOID) OR 
                (InstantFileTime (ImpModule).IsGreater (
                                            FileTime (ImpModule))) OR
                (InstantFileTime (DefModule).IsGreater (
                                            FileTime (DefModule)));
      END NeedsEnterInDictionary;

    ------------------------------------------------

    METHOD NeedsYaflRecompilation(MissingFilesOnly: BOOLEAN): ProjectModule;
      VAR
        TheDepends: ARRAY OF ProjectModule;
      BEGIN                            
      IF MissingFilesOnly THEN
        IF NOT ExistFile(H1File) OR NOT ExistFile(H2File) OR
           NOT ExistFile(CFile) THEN
          RESULT := THIS;
          END;
       ELSE            
        TheDepends := Depends;
        IF (CFileTime = VOID) OR (H1FileTime = VOID) OR
                  (H2FileTime = VOID) OR (DefinitionModuleTime = VOID) OR
                  (ImplementationModuleTime = VOID) OR
                  ImplementationModuleTime.IsGreater(CFileTime) OR
                  DefinitionModuleTime.IsGreater(CFileTime) THEN
          RESULT := THIS;
          END;            
        IF RESULT = VOID THEN
          RESULT := FIRST Depend IN TheDepends :-
            (Depend.DefinitionModuleTime = VOID) OR
             Depend.DefinitionModuleTime.IsGreater(CFileTime);
          END;   
        END;
      END NeedsYaflRecompilation;
      
    METHOD NeedsCRecompilation(MissingFilesOnly: BOOLEAN): ProjectModule;
      VAR
        TheDepends: ARRAY OF ProjectModule;
      BEGIN 
      IF MissingFilesOnly THEN
        IF NOT ExistFile (ObjFile) THEN
          RESULT := THIS;
          END;
       ELSE                           
        TheDepends := Depends;
        IF (CFileTime = VOID) OR (H1FileTime = VOID) OR
                  (H2FileTime = VOID) OR (ObjFileTime = VOID) OR
                  CFileTime.IsGreater(ObjFileTime) OR
                  H1FileTime.IsGreater(ObjFileTime) OR
                  H2FileTime.IsGreater(ObjFileTime) THEN
          RESULT := THIS;
          END;            
        IF RESULT = VOID THEN  
          RESULT := FIRST Depend IN TheDepends :-  
                    (Depend.H1FileTime = VOID) OR
                    (Depend.H2FileTime = VOID) OR
                     Depend.H1FileTime.IsGreater(ObjFileTime) OR
                     Depend.H2FileTime.IsGreater(ObjFileTime);
          END;           
        END;
      END NeedsCRecompilation;

    METHOD NeedsRecompilation (Yafl,
                               MissingFilesOnly: BOOLEAN): ProjectModule;
      BEGIN                  
      IF Yafl THEN
        RESULT := NeedsYaflRecompilation(MissingFilesOnly);
       ELSE
        RESULT := NeedsCRecompilation(MissingFilesOnly);
        END;
      END NeedsRecompilation;
      
    METHOD SaveStream (Output: OutputStream);
      VAR
        LineLength: INTEGER;
      CONST
        MaxLineLength = 76;
      BEGIN
      VOID := Depends;
      Output.WriteString ("MODULE ");
      Output.WriteInt(World.Number, 0);
      Output.WriteLine (" " + Get + " DEPENDS \");
      FOR Depend IN TheDepends DO
        IF LineLength + Depend.Get.SIZE + 3 >= MaxLineLength THEN
          Output.WriteLine ("\");
          Output.WriteChar(" ");
          LineLength := 1;
          END;
        Output.WriteString (Depend.Get + " ");
        LineLength := LineLength + Depend.Get.SIZE + 2;
        END;
      Output.WriteLn;
      END SaveStream;

    METHOD SetPatterns (Mapper: PatternMapper);
      BEGIN
      World.SetPatterns (Mapper);
      Mapper.Associate ('R', Get);
      END SetPatterns;

    METHOD SetDependencies;
      VAR
        ModArray: ARRAY OF DefinitionModule;
        BEGIN
      ASSERT TrueModule <> VOID;
      ModArray :=  TrueModule.CombinedImported.Row;
      TheDepends.CREATE (ModArray.SIZE);
      FOR i := 0 TO ModArray.SIZE - 1 DO
        TheDepends [i] := Father.FindModule (ModArray[i]);
        ASSERT TheDepends[i] <> VOID;
        END;
      END SetDependencies;

    METHOD EnterInDictionary (FrontEnd : YaflFrontEnd) : BOOLEAN;
      VAR
        CompRun               : CompilationRun;
                                                   
      BEGIN                                
      FrontEnd.CheckMemory;             
      
      CompRun.CREATE (Get, 
                      KeepModule := TRUE, 
                      FrontEnd.GetCodeGCList);
      CurrentSpot.SetCurrentCompilationRun (CompRun);
      RESULT := CompRun.Ok;
      IF RESULT THEN                          
        CompRun.CompiledModule.EnterInDictionary;     
        IF YaflCfg.PleaseTag THEN
          CompRun.CompiledModule.EnterImportsInDictionary;
          END; -- IF
        END;

      CurrentSpot.SetCurrentCompilationRun (VOID);
      CompRun.EraseCompiledModule;
      CompRun := VOID;
      END EnterInDictionary;

  END ProjectModule;

 ------------------------------------------

  CLASS ProjectWorld;
    INHERITS StringElement;
    
    VAR
      TheTrueWorld: World;      
      WorldNr: INTEGER;
    
    REDEFINE METHOD CREATE (TrueWorld: World);
      BEGIN      
      IF TrueWorld = VOID THEN
        BASE (VOID);                          
       ELSE 
        TheTrueWorld := TrueWorld;
        WorldNr := TheTrueWorld.Number;
        BASE (TrueWorld.Prefix);
        END;
      END CREATE;
    
    METHOD Parse (Words: ARRAY OF ARRAY OF CHAR);
      BEGIN
      WorldNr := IntConversions.StringToInt (Words[1]);
      Set (Words[2]);
      END Parse;
      
    METHOD TrueWorld: World;
      VAR
        NewWorld: World;
        WorldArr : ARRAY OF World;
      BEGIN
      IF TheTrueWorld = VOID THEN
        WorldArr := WorldList.Row;
        TheTrueWorld := FIRST w IN WorldArr :- String.Equals (w.Prefix, Get);
        IF TheTrueWorld = VOID THEN
          NewWorld.CREATE ("", Get);
          TheTrueWorld := NewWorld;
          WorldList.Append (NewWorld);
          END;
        WorldNr := TheTrueWorld.Number;
        END;
      RESULT := TheTrueWorld;
      ASSERT RESULT <> VOID;
      END TrueWorld;

   METHOD SaveStream (Output: OutputStream);
     BEGIN
     Output.WriteString ("WORLD ");
     Output.WriteInt (WorldNr, 0);
     Output.WriteLine (" " + Get);
     END SaveStream;

   METHOD Number: INTEGER;
     BEGIN
     RESULT := WorldNr;
     END Number;

    METHOD SetPatterns (Mapper: PatternMapper);
      BEGIN
      Mapper.Associate ('P', Get);
      END SetPatterns;
      
  END ProjectWorld;
 ------------------------------------------
  ONCE CLASS PrjKeywords;
    CONST
      World = 1;
      Module = 2;
      Depends = 3;
      Root = 4;
      Last = Root;
      
      Other = -1;
      
    VAR
      Table: ARRAY OF ARRAY OF CHAR;
      
    METHOD CreateTable;
      BEGIN
      ASSERT Table = VOID;
      Table.CREATE (Last + 1);
      Table[World    ] := "WORLD";
      Table[Module   ] := "MODULE";
      Table[Depends  ] := "DEPENDS";
      Table[Root     ] := "ROOT";
      END CreateTable;  
            
    METHOD Code (Keyword: ARRAY OF CHAR): INTEGER;
      BEGIN    
      IF Table = VOID THEN
        CreateTable;
        END;
      ASSERT Keyword <> VOID;
      RESULT := FIRST i IN 1 TO Table.SIZE - 1 :-
                  (Table[i] <> VOID) AND String.Equals (Table[i], Keyword);
      IF RESULT = 0 THEN
        RESULT := Other;
        END;            
      END Code;
      
  END PrjKeywords;

END YaflProject;
