IMPLEMENTATION MODULE YaflCompiler;

IMPORT ModuleTable;
FROM Streams IMPORT StdOut;
FROM YaflSymbols IMPORT SymbolTable;
FROM YaflError IMPORT MainErrorHandler, WarningHandler;
FROM YaflLint IMPORT LintChecker;
FROM YaflPredefined IMPORT PredefItems;
FROM YaflCfg IMPORT YaflCfg, CurrentSpot;
FROM YaflController IMPORT Controller;
FROM YaflCreator IMPORT CodeGeneratorCreator, Creators;

IMPORT SYSTEM;

  CLASS Compiler;
    VAR
      GenLines: INTEGER;
      
    METHOD GeneratedLines: INTEGER;
      BEGIN
      RESULT := GenLines;
      END GeneratedLines;
                        
      METHOD PrepareCompilation;
        BEGIN
        SymbolTable.Zap;
        PredefItems.EnterInSymbolTable;
        MainErrorHandler.Reset;
        WarningHandler.Reset;
        YaflCfg.ResetUniqueNumber;
        END PrepareCompilation;
        
      METHOD AfterCompilation;
        BEGIN      
        SymbolTable.Zap;
        PredefItems.EnterInSymbolTable;
        END AfterCompilation;

    METHOD Compile (ModuleName: ARRAY OF CHAR;
                    VerboseLevel: INTEGER;
                    PleaseTag,
                    PleaseCheckType,
                    PleaseGenerateMetrics,
                    PleaseLint: BOOLEAN;
                    GCList: CodeGeneratorCreatorList): ImplementationModule;
      VAR
        Checker: LintChecker;
        
      METHOD CheckErrors: BOOLEAN;
        BEGIN
        RESULT := MainErrorHandler.ErrorCount = 0;
        END CheckErrors;
        
      METHOD Perform: ImplementationModule;
        VAR
          TheGCCreator: CodeGeneratorCreator; 
          HaveToClear: BOOLEAN;
        BEGIN        
        RESULT := ModuleTable.LocateImplementationModule (ModuleName);
        IF (NOT YaflCfg.Interrupted) AND (RESULT <> VOID) THEN
          CurrentSpot.PushCurrentModule (RESULT);

          ------------
          -- Tag
          ------------
          IF (NOT YaflCfg.Interrupted) AND (CheckErrors) AND
             (PleaseTag) THEN

            YaflCfg.GetController.Capture (Controller.Tag); 
            RESULT.UniqueTag;

            -----------------------
            -- Check type
            -----------------------
            
            IF (NOT YaflCfg.Interrupted) AND (CheckErrors) AND 
               (PleaseCheckType) THEN

              YaflCfg.GetController.Capture (Controller.CheckType);

              RESULT.UniqueCheckType;
              IF (NOT YaflCfg.Interrupted) AND (CheckErrors) THEN

                -----------------------
                -- Extended checks
                -----------------------

                IF PleaseLint THEN
                  IF VerboseLevel > 0 THEN
                    StdOut.WriteLine ("Extended checks");
                    END; -- IF

                  YaflCfg.GetController.Capture (Controller.ExtendedChecks);

                  Checker.CREATE (RESULT);
                  END; -- IF

                -----------------------
                -- Generate code
                -----------------------

                FOR i := 0 TO GCList.Size - 1  WHILE NOT YaflCfg.Interrupted DO
                  IF HaveToClear THEN
                    RESULT.ClearAllGc;
                    END;
                  HaveToClear := TRUE;
                  TheGCCreator := GCList.Get(i);
                  IF VerboseLevel > 0 THEN
                    StdOut.WriteLine ("Generating code: " 
                                      + TheGCCreator.WhatAmI);
                    END; -- IF

                  Creators.SetCodeGenerator(TheGCCreator);
 
                  RESULT.Gc.GenerateCode;
                  GenLines := GenLines + RESULT.GeneratedLines;
                  END; -- FOR 
                END; -- IF
              END; -- IF
            END; -- IF
          CurrentSpot.PopCurrentModule;
          END; -- IF
        END Perform;
        
      BEGIN
      PrepareCompilation;
      RESULT := Perform;
      AfterCompilation;
      END Compile;

    END Compiler;

END YaflCompiler;
