IMPLEMENTATION MODULE CGDesig; 

FROM Conversions IMPORT IntConversions;
FROM YaflDictionary IMPORT MethodReference, CallReference;
FROM YaflGC IMPORT YaflGC;

------------------------------
-- C Code Generators
------------------------------
FROM CGCode          IMPORT CGcContext;
FROM CGClass IMPORT CDummyClDeclCodeGenerator,
                    CVirtualClassDeclCodeGenerator,
                    CInstClassDefCodeGenerator,
                    CPredefClassCodeGenerator,
                    CClassImplCodeGenerator;
FROM CGMethods IMPORT CPredefMethCodeGenerator,
                      CMethDefCodeGenerator,
                      CMethImplCodeGenerator;                      

------------------------------
-- Generic Code Generators
------------------------------
FROM YaflGCode       IMPORT GC;
FROM YaflGType       IMPORT TypedNTCodeGenerator;
FROM YaflGClass      IMPORT ClassDeclCodeGenerator;
FROM YaflGMethods    IMPORT MethDeclCodeGenerator;

------------------------------
-- Non Terminals
------------------------------
FROM YaflType         IMPORT TypedNonTerminal,
                             Type;

FROM YaflPredefined   IMPORT PredefMethod,
                             PredefItems, 
                             PredefClass,
                             ThisDataItem;
FROM YaflQuantifiers  IMPORT FreeVariableDataItem;                             
FROM YaflClasses      IMPORT ClassDeclaration;
FROM YaflDeclarations IMPORT SingleDataItem, ConstDeclaration;
FROM YaflDictionary   IMPORT MethodReference, EntryReference,
                             CallReference, AttributeReference,
                             CallDictionary;
FROM YaflDesignator IMPORT DesigElement, Desig;
FROM YaflParser       IMPORT NonTerminal, Walker, LimitedWalker;
FROM Streams          IMPORT StdOut;
FROM YaflLex          IMPORT LexicalAnalyzer;
FROM YaflParamClasses IMPORT ClassActual;
FROM YaflCfg          IMPORT CurrentSpot, YaflCfg;
FROM YaflError        IMPORT WarningHandler;
FROM YaflMetImplementation IMPORT MethodImplementation;
FROM YaflMetDefinition IMPORT MethodDefinition;
FROM YaflMethods IMPORT MethodDeclaration;
FROM YaflSystem IMPORT SystemMethod;
FROM YaflClImplementation IMPORT ClassImplementation;
FROM YaflLiteral     IMPORT Literal;
FROM Ref IMPORT Ref;

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

  CLASS CDesigElementCodeGenerator;
    INHERITS DesigElementCodeGenerator(CGcContext);


    VAR
      PrefixTargetNr: INTEGER;

    METHOD Output: YaflGC;
      BEGIN
      ASSERT Ctx.Output <> VOID;
      RESULT := Ctx.Output;
      END Output;

    ------------------------------------------------------------
    METHOD GenerateMinDualRef(Gc: ClassDeclCodeGenerator);
      BEGIN
        WHAT Gc OF
          IN CDummyClDeclCodeGenerator:
             TAG.GenerateMinDualRef;
             END;
          IN CVirtualClassDeclCodeGenerator:
             TAG.GenerateMinDualRef;
             END;
          IN CInstClassDefCodeGenerator:
             TAG.GenerateMinDualRef;
             END;
          IN CPredefClassCodeGenerator:
             TAG.GenerateMinDualRef;
             END;
          IN CClassImplCodeGenerator:
             TAG.GenerateMinDualRef;
             END;
          END; -- WHAT
      END GenerateMinDualRef; 

    METHOD GenerateConstructFuncId(Gc: ClassDeclCodeGenerator);
      BEGIN
        WHAT Gc OF
          IN CDummyClDeclCodeGenerator:
             TAG.GenerateConstructFuncId;
             END;
          IN CVirtualClassDeclCodeGenerator:
             TAG.GenerateConstructFuncId;
             END;
          IN CInstClassDefCodeGenerator:
             TAG.GenerateConstructFuncId;
             END;
          IN CPredefClassCodeGenerator:
             TAG.GenerateConstructFuncId;
             END;
          IN CClassImplCodeGenerator:
             TAG.GenerateConstructFuncId;
             END;
          END; -- WHAT
      END GenerateConstructFuncId;

    METHOD GenerateCreateAnchorId(Gc: ClassDeclCodeGenerator);
      BEGIN
        WHAT Gc OF
          IN CDummyClDeclCodeGenerator:
             TAG.GenerateCreateAnchorId;
             END;
          IN CVirtualClassDeclCodeGenerator:
             TAG.GenerateCreateAnchorId;
             END;
          IN CInstClassDefCodeGenerator:
             TAG.GenerateCreateAnchorId;
             END;
          IN CPredefClassCodeGenerator:
             TAG.GenerateCreateAnchorId;
             END;
          IN CClassImplCodeGenerator:
             TAG.GenerateCreateAnchorId;
             END;
          END; -- WHAT
      END GenerateCreateAnchorId;

    METHOD GenerateMinimalDualExtract(Gc: ClassDeclCodeGenerator);
      BEGIN
        WHAT Gc OF
          IN CDummyClDeclCodeGenerator:
             TAG.GenerateMinimalDualExtract;
             END;
          IN CVirtualClassDeclCodeGenerator:
             TAG.GenerateMinimalDualExtract;
             END;
          IN CInstClassDefCodeGenerator:
             TAG.GenerateMinimalDualExtract;
             END;
          IN CPredefClassCodeGenerator:
             TAG.GenerateMinimalDualExtract;
             END;
          IN CClassImplCodeGenerator:
             TAG.GenerateMinimalDualExtract;
             END;
          END; -- WHAT
      END GenerateMinimalDualExtract;
    
    METHOD GenerateDualRef(Gc: ClassDeclCodeGenerator);
      BEGIN
        WHAT Gc OF
          IN CDummyClDeclCodeGenerator:
             TAG.GenerateDualRef;
             END;
          IN CVirtualClassDeclCodeGenerator:
             TAG.GenerateDualRef;
             END;
          IN CInstClassDefCodeGenerator:
             TAG.GenerateDualRef;
             END;
          IN CPredefClassCodeGenerator:
             TAG.GenerateDualRef;
             END;
          IN CClassImplCodeGenerator:
             TAG.GenerateDualRef;
             END;
          END; -- WHAT
      END GenerateDualRef; 

    METHOD GenerateCast(Gc: ClassDeclCodeGenerator);
      BEGIN
        WHAT Gc OF
          IN CDummyClDeclCodeGenerator:
             TAG.GenerateCast;
             END;
          IN CVirtualClassDeclCodeGenerator:
             TAG.GenerateCast;
             END;
          IN CInstClassDefCodeGenerator:
             TAG.GenerateCast;
             END;
          IN CPredefClassCodeGenerator:
             TAG.GenerateCast;
             END;
          IN CClassImplCodeGenerator:
             TAG.GenerateCast;
             END;
          END; -- WHAT
      END GenerateCast;
    ------------------------------------------------------------
 
    METHOD GenerateAnchorId(Gc: MethDeclCodeGenerator);
      BEGIN
      WHAT Gc OF
        IN CPredefMethCodeGenerator:
          TAG.GenerateAnchorId;
          END;
        IN CMethDefCodeGenerator:
          TAG.GenerateAnchorId;
          END;
        IN CMethImplCodeGenerator:
          TAG.GenerateAnchorId;
          END;
        END; -- WHAT
      END GenerateAnchorId;

    METHOD GenerateMethodPointer(Gc: MethDeclCodeGenerator);
      BEGIN
      WHAT Gc OF
        IN CPredefMethCodeGenerator:
          TAG.GenerateMethodPointer;
          END;
        IN CMethDefCodeGenerator:
          TAG.GenerateMethodPointer;
          END;
        IN CMethImplCodeGenerator:
          TAG.GenerateMethodPointer;
          END;
        END; -- WHAT
      END GenerateMethodPointer;

    ------------------------------------------------------------
 
    REDEFINE METHOD GenerateCode;
      BEGIN
      Ctx.TypedNTGenerateCode(THIS);
      END GenerateCode; 

    METHOD GenerateActuals(Functional,
                           InitialComma: BOOLEAN);
      BEGIN
      IF Obj.Actuals <> VOID THEN
        FOR i := 0 TO Obj.Actuals.Size - 1 DO
	  IF (i <> 0) OR (InitialComma) THEN
            Output.Comma;
	    END;
	  IF Functional THEN
            Obj.Actuals.Get(i).Gc.GenerateCode;
	   ELSE
	    Output.UniqueItem (Obj.Actuals.Get(i).Expr.Gc.Number);
	    END;
          END;
        END;
      END GenerateActuals;          
      
    METHOD GeneratePrefix;
      BEGIN              
      IF PrefixTargetNr <> 0 THEN
        Output.UniqueItem (PrefixTargetNr);
       ELSE
        WHAT Obj.Father.Gc OF
          IN CDesigCodeGenerator:
            TAG.GenerateCodeIndex( Obj.Index - 1);
	    END;
          END;
        END;
      END GeneratePrefix;

    METHOD GeneratePredefined (Meth: PredefMethod;
                               Functional: BOOLEAN);
      VAR
        Cl: ClassDeclaration;
        CurMeth, TheMeth: MethodDeclaration;
        
        METHOD GenerateCreate(Functional: BOOLEAN);
          VAR
            TypeCtx: Type;
            
            METHOD GenerateParamFuncActuals (TypeCtx: Type);
              VAR
                ActualsArr: ARRAY OF ClassActual;
                BEGIN
              IF TypeCtx.Actuals <> VOID THEN
                ActualsArr := TypeCtx.Actuals.ActualList.Row;
                FOR i := 0 TO ActualsArr.SIZE - 1 DO
                  Output.Comma;
                  GenerateMinDualRef(ActualsArr[i].Class.Gc);
                  END;
                END;      
              END GenerateParamFuncActuals;
              
          BEGIN
          TypeCtx := Obj.PreviousElement.GetType;
          Cl := TypeCtx.SimpleType;
          IF TypeCtx.ArrayLevel > 0 THEN
            --------------------------------------
            -- Creating an array
            --------------------------------------
            GeneratePrefix;
            Output.Becomes;
            Output.Alloc;
            Output.LeftParent;
            --------------------------------------
            -- There must be a single integer parameter
            --------------------------------------
            ASSERT Obj.Actuals <> VOID;
            ASSERT Obj.Actuals.Size = 1;
            Output.LeftParent;
            Output.WriteString (PredefItems.Integer.CName);
            Output.RightParent;
	    GenerateActuals (Functional, InitialComma := FALSE);
            Output.Comma;
            Output.WriteInt (TypeCtx.ArrayLevel, 0);
            Output.Comma;
            GenerateMinDualRef(Cl.Gc);
            Output.RightParent;
           ELSE
            --------------------------------------
            -- Creating an object
            --------------------------------------
            TheMeth := Cl.Create;
            ASSERT TheMeth <> VOID;
            IF TheMeth = PredefItems.Create THEN
              -----------------------------
              -- Just allocate: there is no
              -- CREATE method to use
              -----------------------------       
              GeneratePrefix;
              Output.Becomes;
              IF Cl.NeedsConstructFunc THEN        
                GenerateConstructFuncId(Cl.Gc);
                END;
              Output.LeftParent;
              Output.Allocate (Cl.Module.Id.Data, Cl.Id.Data);
              --------------------------------------------------
              -- If Father's class is parameterized, the addresses to the
              -- corresponding duals must be given as parameters to the
              -- ParamFunc function
              ---------------------------------------------------
              GenerateParamFuncActuals (TypeCtx);
              Output.RightParent;
             ELSE
              -----------------------------------
              -- The method must be called as well
              -----------------------------------
              ASSERT TheMeth <> VOID;
              GenerateCreateAnchorId(TheMeth.Class.Gc);
              Output.LeftParent;
              GeneratePrefix;
              Output.Becomes;
              IF Cl.NeedsConstructFunc THEN        
                GenerateConstructFuncId(Cl.Gc);
                END;
              Output.LeftParent;
              Output.Allocate (Cl.Module.Id.Data, Cl.Id.Data);
              GenerateParamFuncActuals (TypeCtx);
              Output.RightParent;
              GenerateActuals(Functional, InitialComma := TRUE);
              Output.RightParent;
              END;
            END;
          END GenerateCreate;
          
        METHOD GenerateKillFuncExtract (Cl: ClassDeclaration);
          BEGIN
          GenerateMinimalDualExtract(Cl.Gc);
          Output.Arrow;
          Output.KillFunc;
          END GenerateKillFuncExtract;
          
        METHOD GenerateBase(Functional: BOOLEAN);
          VAR
            OrgCl: ClassDeclaration;
            OrgMeth: MethodDeclaration;
            MethRef: MethodReference;
            CallRef: CallReference;
          BEGIN
          ----------------------------
          -- BASE can only be applied to THIS.
          ----------------------------
          ASSERT Obj.PreviousElement = VOID;
          Cl := CurrentSpot.CurrentClass;
          CurMeth := CurrentSpot.CurrentMethod;
          IF Cl.Inherits <> VOID THEN
            --------------------------------
            -- Otherwise, BASE does nothing!
            --------------------------------
            -- Handle BASE to CREATE
            --------------------------------
            IF CurMeth.IsCreate THEN
              ASSERT Cl.Inherits <> VOID;
              Cl := Cl.Inherits.Class;
              ----------------------------------
              -- Cl refers to the immediate
              -- base class
              ----------------------------------
              CurMeth := Cl.Create;
              ASSERT CurMeth <> VOID;
              IF CurMeth <> PredefItems.Create THEN
                Cl := CurMeth.Class;
                GenerateAnchorId(CurMeth.Gc);
                Output.LeftParent;
                Output.This;
                GenerateActuals(Functional, InitialComma := TRUE);
                Output.RightParent;
                END;
             -----------------------------------
             -- Handle the BASE to Clone case...
             -----------------------------------
             ELSIF CurMeth.Id.Data = PredefItems.Clone.Id.Data THEN
              ASSERT Cl.Inherits <> VOID;
              GenerateMinimalDualExtract(Cl.Inherits.Class.Gc);
              Output.Dot;
              Output.CloneFunc;
              Output.LeftParent;
              Output.This;
              GenerateActuals(Functional, InitialComma := TRUE);
              Output.RightParent;
             -----------------------------------
             -- Handle the BASE to Kill case...
             -----------------------------------
             ELSIF CurMeth.Id.Data = PredefItems.Kill.Id.Data THEN
              ASSERT Cl.Inherits <> VOID;
              Cl := Cl.Inherits.Class;
              Output.If;
              Output.LeftParent;              
              GenerateKillFuncExtract (Cl);
              Output.RightParent;
              GenerateKillFuncExtract (Cl);
              Output.LeftParent;
              Output.This;
              GenerateActuals(Functional, InitialComma := TRUE);
              Output.RightParent;
             ELSE -- Not BASE to a predefined method
              TheMeth := CurMeth.Redefined (TRUE);
              --------------------------------
              -- TheMeth now refers to the method's
              -- original definition
              --------------------------------
              ASSERT Cl.Inherits <> VOID;
              Cl := Cl.Inherits.Class;
              DEBUG
                IF TheMeth = VOID THEN
                  StdOut.WriteString ("Void TheMeth "+ CurMeth.Id.Data);
                  StdOut.WriteInt (Obj.LineNr, 8);
                  StdOut.WriteLn;
                  ASSERT FALSE;
                  END;
                END;
              OrgCl := TheMeth.Class;
              OrgMeth := TheMeth.Redefined(TRUE);
              IF OrgMeth = VOID THEN
                OrgMeth := TheMeth;
                END;
              ASSERT OrgCl <> VOID;
              -------------------------------
              -- Cl now refers to the method's original class
              -------------------------------
              Output.LeftParent;
              Output.Star;
              Output.LeftParents(3);
              Output.DualType (OrgCl.Module.Id.Data, OrgCl.Id.Data);
              Output.Star;
              Output.RightParent;
              Output.LeftParent;
              GenerateDualRef(Cl.Gc);
              Output.RightParents(2);
              Output.Arrow;
              GenerateMethodPointer(OrgMeth.Gc);
              Output.RightParent;
              Output.RightParent;
              Output.LeftParent;
              Output.This;
              GenerateActuals(Functional, InitialComma := TRUE);
              Output.RightParent;
              END;
            END;
          END GenerateBase;
          
      BEGIN
      IF Meth = PredefItems.Clone THEN
        Output.UnivClone;
        Output.LeftParent;
        GeneratePrefix;
        Output.RightParent;
       -----------------------------------------
       ELSIF Meth = PredefItems.Kill THEN
        Output.UnivKill;
        Output.LeftParent;
        GeneratePrefix;
        Output.RightParent;
       -----------------------------------------
       ELSIF Meth = PredefItems.Create THEN
        GenerateCreate(Functional);
       ELSIF Meth = PredefItems.Size THEN
        Output.High;
        Output.LeftParent;
        GeneratePrefix;
        Output.RightParent;
       ELSIF Meth = PredefItems.Slice THEN
        Output.UnivSlice;
        Output.LeftParent;
        GeneratePrefix;
        GenerateActuals(Functional, InitialComma := TRUE);
        ASSERT Obj.Actuals.Row.SIZE = 2;
        Output.RightParent;
       ELSIF Meth = PredefItems.Base THEN
        GenerateBase(Functional);
-- XXJC (d)
       ELSIF Meth = PredefItems.NoChange THEN
         -- always generate true.
         Output.True;
       ELSIF Meth = PredefItems.NoChangeHC THEN
         -- always generate true.
         Output.True;
-- END XXJC (d)
       ELSE
        ASSERT FALSE;
        END;
      END GeneratePredefined;
             
    ------------------------------
    -- GenerateMethodId generates the anchor name of the
    -- method if the call is polymorphic, otherwise, 
    -- GenerateMethodId generates the method name.
    ------------------------------
    METHOD GenerateMethodId (Meth: MethodDeclaration);
      VAR
        TheOptimized : MethodReference;                               
        TheEntry: EntryReference;
      BEGIN        
      IF NOT YaflCfg.PleaseGlobalOptimize THEN
        GenerateAnchorId(Meth.Gc);
       ELSE
        Obj.CallRef.AddGeneratedCall;
        TheEntry := Obj.CallRef.EntryRef;
        IF TheEntry = VOID THEN
          ------------------------------
          -- TheEntry shouldn't be VOID, but this is just for safeness
          ------------------------------
          GenerateAnchorId(Meth.Gc);
         ELSIF TheEntry.IsMonomorphic THEN
          ------------------------------
          -- The method's name is the same as its anchor's
          ------------------------------
          TheEntry.GenerateAnchorId(Output);
         ELSE           
          TheOptimized := Obj.OptimizedMethodRef;
          IF TheOptimized <> VOID THEN
            TheOptimized.GenerateMethodRef(Output);
           ELSE
            GenerateAnchorId(Meth.Gc);
            IF Obj.CallRef.BadCall THEN
              WarningHandler.EmitError ("Warning : "+Meth.Class.Id.Data + "." +
                                  Meth.Id.Data + " is abstract and used ("+
                                  Obj.CallRef.Image + ")");
              END;
            END;
          END;
        END;
      END GenerateMethodId;

    METHOD GenerateWithoutArray(TargetNr: INTEGER);
      VAR
        Original: MethodDeclaration;
        CurrentMeth : MethodImplementation;
        Strap: SystemMethod;
        
      METHOD GenerateDataItem ( DataItem: SingleDataItem);
        VAR
          r: Ref(MethodDefinition);
          m: MethodImplementation;
        BEGIN        
        -- XXJC	(d)
        --ASSERT DataItem.Context <> VOID;
        IF DataItem.Context = VOID THEN
          --StdOut.WriteLine("DataItem.Context = VOID -> " 
          --                 + DataItem.WhatAmI);
          r.CREATE (VOID);
          DataItem.GetAncestor (r);
          WHAT CurrentSpot.CurrentMethod OF
            IN MethodImplementation:
              m := TAG;
              IF m.Definition = r.Get THEN
                DataItem.SetContext(m);
              ELSE
                ASSERT FALSE;
                END;
              END;
	        IN MethodDefinition:
	          IF TAG = r.Get THEN
	            DataItem.SetContext(TAG);
	          ELSE
	            ASSERT FALSE;
	            END;
	          END;
	        END;
	      END;
        -- END XXJC (d)
        WHAT DataItem.Context OF
          IN MethodImplementation:
            WHAT TAG.Gc OF
              IN CMethImplCodeGenerator:
                 TAG.GenerateLocal( DataItem);
                 END;
              END;
            END;
	      -- XXJC
	      -- added for the handling of deferred method preconditions
	      IN MethodDefinition:
	        DataItem.Gc.GenerateCode;
	        END;
	      -- END XXJC
          IN ClassImplementation:
            Output.LeftParent;
            GenerateCast(TAG.Gc);
            IF Obj.Index = 0 THEN
              Output.This;
             ELSE                   
              GeneratePrefix;
              END;
            Output.RightParent;
            Output.Arrow;
            Output.Yu (DataItem.Id.Data);
            END;
          END;
        END GenerateDataItem;
        
      VAR       
        PleaseSaveTemp,
	IsFunc,
        Generated : BOOLEAN;
        CurCall : CallReference;
	TheExpr: TypedNonTerminal;
      BEGIN 
      IsFunc := Obj.FunctionalWithoutArrays;
      IF IsFunc AND (TargetNr <> 0) THEN
	Output.UniqueItem (TargetNr);
	Output.Becomes;
        END;
      IF NOT IsFunc THEN
	Output.WriteLn;
	Output.LeftBrace;
	Output.WriteLn;
--	Output.WriteLine (" /* Here, put radix decl */");
	IF (Obj.PreviousElement <> VOID) AND 
            NOT (Obj.PreviousElement.Functional) THEN
	  PrefixTargetNr := YaflCfg.UniqueNumber;
	  Ctx.TypeGenerateCode (Obj.PreviousElement.GetType.Gc);
	  Output.UniqueItem (PrefixTargetNr);
	  Output.SemiColon;
	  Output.WriteLn;
	  END;

--	Output.WriteLine (" /* Here, put actuals decls */");
	IF Obj.Actuals <> VOID THEN
	  FOR i := 0 TO Obj.Actuals.Size - 1 DO
  	    Ctx.TypeGenerateCode (Obj.Actuals.Get(i).Expr.GetType.Gc);
	    Output.UniqueItem (Obj.Actuals.Get(i).Expr.Gc.Number);
	    Output.SemiColon;
	    Output.WriteLn;
	    END;
	  END;
        END;
      IF PrefixTargetNr <> 0 THEN
--        Output.WriteLine (" /* Here, compute prefix target */");
	WHAT Obj.PreviousElement.Gc OF
          IN CDesigElementCodeGenerator:
	    TAG.GenerateCodeWithTarget (PrefixTargetNr);
	    END;
	  END;
        END;
      IF NOT IsFunc THEN
--        Output.WriteLine (" /* Here, init actuals temp */");
        IF Obj.Actuals <> VOID THEN
          FOR i := 0 TO Obj.Actuals.Size - 1 DO
	    TheExpr := Obj.Actuals.Get(i).Expr;
            Ctx.TypedNTGenerateCodeWithTarget (TheExpr.Gc,
	                                       TheExpr.Gc.Number);
	    IF TheExpr.RequiresTempSaving THEN
	      Output.FlyVReg;
	      Output.LeftParent;
	      Output.UniqueItem (TheExpr.Gc.Number);
	      Output.RightParent;
	      Output.SemiColon;
	      Output.WriteLn;
	      END;
            END;
          END;
--        Output.WriteLine (" /* Now, call whoever you wish */");
	IF TargetNr <> 0 THEN
	  Output.UniqueItem (TargetNr);
	  Output.Becomes;
	  END;
	END;
      WHAT Obj.Id.GetRef OF
        IN MethodDeclaration:
          IF YaflCfg.PleaseOptimizeInLine AND 
                                    (Obj.OptimizedMethodRef <> VOID) THEN
            Generated := GenerateInLineCall( Obj.OptimizedMethodRef);
            END;
          END;
       ELSE
        END;
      IF NOT Generated THEN
        WHAT Obj.Id.GetRef OF
          IN Literal:
            TAG.Gc.GenerateCode;
            END;
          IN ConstDeclaration:   -- Should only be required by
                                 -- Inlined constants. Will abort
                                 -- otherwise.
            TAG.Gc.GenerateCode;
            END;
          IN FreeVariableDataItem:
            Output.UniqueItem (TAG.HashValue);
            END;  
          IN ThisDataItem:
            TAG.Gc.GenerateCode;
            END;
          IN SingleDataItem:  
            IF TAG.Once THEN
              TAG.Gc.GenerateCode;
             ELSE
              GenerateDataItem(TAG);
              END;
            END;
          IN PredefMethod:
            GeneratePredefined(TAG, IsFunc);
            END;
          -------------------------------------------
          -- Not a predefined, see above.
          -------------------------------------------
          IN MethodDeclaration:
            IF YaflCfg.PleaseGlobalOptimize THEN
              CurCall := CallDictionary.FindCall (TAG.Class.Module.Id.Data,
                                                  TAG.Class.Id.Data,
                                                  TAG.Id.Data);
              END;
            IF TAG.Redefine THEN
              Original := TAG.Redefined (TRUE);
             ELSE
              Original := TAG;
              END;
            Strap := Original.Strapped;
            ---------------------------------
            -- If the method is not strapped,
            -- use the common code generation
            -- scheme.
            ---------------------------------
            IF Strap = VOID THEN
              GenerateMethodId( Original);
              Output.LeftParent;
              IF Obj.PreviousElement <> VOID THEN
                PleaseSaveTemp := Obj.PreviousElement.RequiresTempSaving;
                IF CurCall <> VOID THEN        -- TRUE when global optimizing
                  PleaseSaveTemp := PleaseSaveTemp AND 
                   (CurCall.AllocatingState <> CallReference.DoesNotAllocate);
                  END;
                IF PleaseSaveTemp THEN
                  Output.FlyVReg;
                  Output.LeftParent;
                  END;
                GeneratePrefix;
                IF PleaseSaveTemp THEN
                  Output.RightParent;
                  END;
               ELSE
                Output.This;
                END;
              IF Original.IsLocal THEN
                ------------------------------
                -- Pass the various context
                -- structures if required
                ------------------------------
                IF Original.Enclosing = CurrentSpot.CurrentMethod THEN
                  Output.Comma;
                  Output.Ampersand;
                  Output.Context;
                  CurrentMeth := Original.Enclosing;
                 ELSE
                  WHAT Original OF
                    IN MethodImplementation:
                      CurrentMeth := TAG;
                      END;
                    END;
                  END;
                WHILE CurrentMeth.Enclosing <> VOID DO
                  CurrentMeth := CurrentMeth.Enclosing;
                  Output.Comma;
                  Output.UniqueItem (CurrentMeth.ContextNr);
                  END;
                END;
              GenerateActuals(IsFunc, InitialComma := TRUE);
              Output.RightParent;
             ELSE
              Strap.GenerateCode(Ctx, Output, Obj.Actuals, IsFunc);
              END;
            END;
          IN ClassDeclaration:
            ------------------------------------------------------
            -- Only a ONCE class can appear in a designator,
            -- unless it is a constant, in which case it must have
            -- been replaced by the corresponding value earlier in
            -- the code generation process.
            ------------------------------------------------------
            ASSERT TAG.Once;
            Output.OnceClassInstance (TAG.Module.Id.Data, TAG.Id.Data);
            END;
          END;
        END;
      IF IsFunc AND (TargetNr <> 0) THEN
	Output.SemiColon;
	Output.WriteLn;
       ELSIF NOT IsFunc THEN
	Output.SemiColon;
	Output.WriteLn;
	Output.RightBrace;
	Output.WriteLn;
        END;
      END GenerateWithoutArray;

    METHOD LocalGenerateCode (TakeAddress: BOOLEAN;
                              TargetNr: INTEGER);

      VAR
        SideEffect, IsFunc: BOOLEAN;
	ArrLevels, BodyTargetNr: INTEGER;
	TheBodyType: Type;
        
      METHOD GenerateArrayPrefix;
        BEGIN
        IF Obj.BrExpr <> VOID THEN
          FOR i := 0 TO Obj.BrExpr.Size - 1 DO
            Output.ArrayElement;
            Output.LeftParent;
            END;
          END;
        END GenerateArrayPrefix;
        
      METHOD GenerateArrayPostfix;
        VAR
           ArrLevel: INTEGER;
          TheType: Type;
        BEGIN
        IF Obj.BrExpr <> VOID THEN
          TheType := Obj.GetType;
          ArrLevel := TheType.ArrayLevel + Obj.BrExpr.Size;
          FOR i := 0 TO Obj.BrExpr.Size - 1 DO
            Output.Comma;
            ArrLevel := ArrLevel - 1;                                         
            TheType.SimpleType.MakeType (ArrLevel).Gc.GenerateCode;
            Output.Comma;
	    IF IsFunc THEN
              Obj.BrExpr.Get(i).Gc.GenerateCode;
	     ELSE
	      Output.UniqueItem (Obj.BrExpr.Get(i).Gc.Number);
	      END;
            Output.RightParent;
            END;
          END;
        END GenerateArrayPostfix;
        
      BEGIN
      SideEffect := TargetNr > 0;
      IsFunc := Obj.Functional;
      IF IsFunc THEN
	IF TargetNr > 0 THEN
	  Output.UniqueItem (TargetNr);
	  Output.Becomes;
	  IF TakeAddress THEN
	    Output.Ampersand;
	    END;
	  Output.LeftParent;
	  END;
        GenerateArrayPrefix;
        GenerateWithoutArray(TargetNr := 0);
        GenerateArrayPostfix;
	IF TargetNr > 0 THEN
	  Output.RightParent;
	  END;
       ELSE
	Output.LeftBrace;
	IF Obj.BrExpr <> VOID THEN
	  FOR i := 0 TO Obj.BrExpr.Size - 1 DO
	    Output.Int;
	    Output.UniqueItem (Obj.BrExpr.Get(i).Gc.Number);
	    Output.SemiColon;
	    Output.WriteLn;
	    END;
	  ArrLevels := Obj.BrExpr.Size;
	  END;
	IF SideEffect THEN
  	  BodyTargetNr := YaflCfg.UniqueNumber;
          TheBodyType := Obj.GetType;
	  ASSERT TheBodyType <> VOID;
	  IF ArrLevels > 0 THEN
  	    TheBodyType := TheBodyType.ConstrainedClass.MakeType 
                             (TheBodyType.ArrayLevel + ArrLevels);
	    END;
	  Ctx.TypeGenerateCode (TheBodyType.Gc);
	  Output.UniqueItem (BodyTargetNr);
	  Output.SemiColon;
	  Output.WriteLn;
	  END;

	IF Obj.BrExpr <> VOID THEN
--  	  Output.WriteLine (" /* Computing indices */ ");
	  FOR i := 0 TO Obj.BrExpr.Size - 1 DO
	    Ctx.TypedNTGenerateCodeWithTarget (Obj.BrExpr.Get(i).Gc,
 					       Obj.BrExpr.Get(i).Gc.Number);
	    END;
	  END;
--	Output.WriteLine (" /* Computing Radix */ ");
	GenerateWithoutArray (BodyTargetNr);
  	Output.WriteLn;
	IF TargetNr > 0 THEN
--	  Output.WriteLine (" /* Final assignment */ ");
	  Output.UniqueItem (TargetNr);
	  Output.Becomes;
	  IF TakeAddress THEN
	    Output.Ampersand;
	    END;
	  Output.LeftParent;
	  GenerateArrayPrefix;
	  Output.UniqueItem (BodyTargetNr);
	  GenerateArrayPostfix;
	  Output.RightParent;
	  Output.SemiColon;
	  Output.WriteLn;
	  END;
	Output.RightBrace;
        END;
      END LocalGenerateCode;

    REDEFINE METHOD GenerateCodeWithTarget (TargetNr: INTEGER);
      BEGIN
      LocalGenerateCode (TakeAddress := FALSE, TargetNr);
      END GenerateCodeWithTarget;

    METHOD GenerateAddressWithTarget (TargetNr: INTEGER);
      BEGIN
      LocalGenerateCode (TakeAddress := TRUE, TargetNr);
      END GenerateAddressWithTarget;

    REDEFINE METHOD GenerateEvaluationCode;
      BEGIN
      GenerateCodeWithTarget (0);
      END GenerateEvaluationCode;

    METHOD GenerateNoSideEffect;
      BEGIN
      IF Obj.Functional THEN
        GenerateEvaluationCode;
       ELSE
	LocalGenerateCode (TakeAddress := FALSE,
			   TargetNr := -1);
        END;
      END GenerateNoSideEffect;

    ------------------------------------
    -- Generates the code of attribute modification trivial method
    ------------------------------------
    METHOD GenerateInLineAssign ( MethRef : MethodReference);
      BEGIN                            
      Output.LeftParents(2);
      MethRef.ClassRef.GenerateCast(Output);
      IF Obj.PreviousElement <> VOID THEN 
        GeneratePrefix;
       ELSE
        Output.This;
        END;
      Output.RightParent;
      Output.Arrow;
      Output.Yu(MethRef.SimpleAssignment);
      Output.Becomes;
      ASSERT Obj.Actuals <> VOID;
      ASSERT Obj.Actuals.Size = 1;
      Obj.Actuals.Get(0).Gc.GenerateCode;
      Output.RightParent;
      END GenerateInLineAssign;

    ------------------------------------
    -- Generates the code of attribute consultation trivial method
    ------------------------------------
    METHOD GenerateInLineQuery (MethRef: MethodReference);
      BEGIN              
      ASSERT MethRef <> VOID;
      ASSERT MethRef.SimpleQuery <> VOID;        
      ASSERT (Obj.Actuals = VOID) OR (Obj.Actuals.Size = 0);
      Output.LeftParent;
      Output.LeftParent;
      MethRef.ClassRef.GenerateCast(Output);
      IF Obj.PreviousElement <> VOID THEN
        GeneratePrefix;
       ELSE
        Output.This;
        END;
      Output.RightParent;
      Output.Arrow;
      Output.Yu(MethRef.SimpleQuery);
      Output.RightParent;
      END GenerateInLineQuery;
      
                             
    METHOD GenerateCallToNothing;
      BEGIN
      -- This is a call to nothing => no call at all!
      END GenerateCallToNothing;  
      
    ------------------------------------
    -- Generates the code of literal consultation method
    ------------------------------------
    METHOD GenerateInLineLiteral( Image: ARRAY OF CHAR);
      BEGIN
      Output.WriteString (Image);
      END GenerateInLineLiteral;
                                    
    ------------------------------------
    -- Generates an in lined trivial method call if the method
    -- is trivial. RESULT = TRUE implies code has been generated.
    ------------------------------------
    METHOD GenerateInLineCall ( MethRef: MethodReference) : BOOLEAN;
      BEGIN          
      ASSERT MethRef <> VOID;
      Obj.CallRef.AddGeneratedCall;
      IF MethRef.SimpleAssignment <> VOID THEN
        GenerateInLineAssign( MethRef);
        RESULT := TRUE;
      ELSIF MethRef.SimpleQuery <> VOID THEN
        GenerateInLineQuery( MethRef);
        RESULT := TRUE;
      ELSIF MethRef.SimpleLiteral <> VOID THEN
        GenerateInLineLiteral( MethRef.SimpleLiteral);
        RESULT := TRUE;
      ELSIF MethRef.DoesNothing THEN
        GenerateCallToNothing;
        -- Don't generate anything
        RESULT := TRUE;
        END;         
      END GenerateInLineCall;
                             
  END CDesigElementCodeGenerator;
  
----------------------------------------------------

  CLASS CDesigCodeGenerator;
    INHERITS DesigCodeGenerator(CGcContext);
    
    METHOD Output: YaflGC;
      BEGIN
      ASSERT Ctx.Output <> VOID;
      RESULT := Ctx.Output;
      END Output;

    METHOD GenerateCodeIndex(Index: INTEGER);
      BEGIN  
      IF (Index >= 0) AND (Index < Obj.Size) THEN
        Obj.Elements.Get(Index).Gc.GenerateCode;
        END;
      END GenerateCodeIndex;

    REDEFINE METHOD GenerateEvaluationCode;
      BEGIN                
      IF Obj.GetFolded <> VOID THEN
        Obj.GetFolded.Gc.GenerateCode;
       ELSE
        Obj.Last.Gc.GenerateCode;
        END;
      END GenerateEvaluationCode;

    REDEFINE METHOD GenerateCode;
      BEGIN
      Ctx.TypedNTGenerateCode(THIS);
      END GenerateCode;

    METHOD GenerateNoSideEffect;
      BEGIN
      ASSERT Obj.GetFolded = VOID;
      WHAT Obj.Last.Gc OF
	IN CDesigElementCodeGenerator:
	  TAG.GenerateNoSideEffect;
	  END;
        END;
      Output.SemiColon;
      END GenerateNoSideEffect;

    METHOD GenerateAddressWithTarget (TargetNr: INTEGER);
      BEGIN
      ASSERT Obj.GetFolded = VOID;
      WHAT Obj.Last.Gc OF
	IN CDesigElementCodeGenerator:
	  TAG.GenerateAddressWithTarget (TargetNr);
	  END;
        END;
      END GenerateAddressWithTarget;

    REDEFINE METHOD GenerateCodeWithTarget (TargetNr: INTEGER);
      BEGIN
      WHAT Obj.Last.Gc OF
        IN CDesigElementCodeGenerator:
          TAG.GenerateCodeWithTarget (TargetNr);
	  END;
        END;
      END GenerateCodeWithTarget;

  END CDesigCodeGenerator;
  
  
END CGDesig;

