IMPLEMENTATION MODULE YaflDesignator;

FROM YaflDictionary IMPORT MethodQueue, ClassReference, MethodReference,
                           CallDictionary, EntryReference, CallReference,
                           AttributeReference, AttributeDictionary;
FROM YaflLex IMPORT LexicalAnalyzer;
FROM YaflPredefined IMPORT PredefClass, PredefMethod, PredefItems, Void,
                           ThisDataItem;
FROM YaflModules IMPORT CompilationUnit;
FROM YaflDeclarations IMPORT ConstDeclaration, SingleDataItem,
                             Declaration, InheritsClause;
FROM YaflError IMPORT WarningHandler;
FROM YaflExpressions IMPORT Actual, ActualList, ExpressionList;
FROM YaflMethods IMPORT MethodDeclaration;
FROM YaflMetImplementation IMPORT MethodImplementation;
FROM YaflMetDefinition IMPORT MethodDefinition;
FROM YaflParamClasses IMPORT ClassActual;
FROM YaflPredefined IMPORT PredefBaseMethod;
FROM YaflError IMPORT MainErrorHandler;
FROM YaflClasses IMPORT ClassDeclaration, VirtualClassDecl, 
                        ConstrainedClassDecl;
FROM YaflClDefinition IMPORT ClassDefinition;                        
FROM YaflClImplementation IMPORT ClassImplementation;
FROM YaflLiteral IMPORT Literal;
FROM YaflNTList IMPORT NTList;
FROM Ref IMPORT Ref;
FROM Streams IMPORT StdOut;
FROM YaflCfg IMPORT CurrentSpot, YaflCfg;
FROM YaflStatements IMPORT Statement;
FROM YaflSystem IMPORT SystemMethod;
IMPORT SYSTEM;


  CLASS DesigElement;
    INHERITS TypedNonTerminal(DesigElementCodeGenerator);  
    
    VAR
      TheId: Ident;
      BrExprList: ExpressionList;
      TheActuals: ActualList;
      TheFather: Desig;
      TheIndex: INTEGER;  
      
    METHOD Index: INTEGER;
      BEGIN     
      RESULT := TheIndex;
      END Index;      
      
    METHOD SetIndex (TheIndex: INTEGER);
      BEGIN
      THIS.TheIndex := TheIndex;
      END SetIndex;
      
    REDEFINE METHOD SetFather (TheFather: NonTerminal);
      BEGIN         
      BASE (TheFather);  
      WHAT TheFather OF
        IN Desig:
          THIS.TheFather := TAG;
          END;
        END;
      END SetFather;

    REDEFINE METHOD SubTree: ARRAY OF NonTerminal;
      BEGIN
      RESULT.CREATE(1);
      RESULT[0] := TheId;
      IF TheActuals <> VOID THEN
        RESULT := RESULT + TheActuals.SubTree;
        END;
      IF BrExprList <> VOID THEN
        RESULT := RESULT + BrExprList.SubTree;
        END;
      END SubTree;

    REDEFINE METHOD Parse(Lkh: LookAhead);
      BEGIN
      TheId := Lkh.AcceptIdent;
      IF Lkh.CurrentToken = LexicalAnalyzer.LeftParen THEN
        -- XXJC (d)
        TheActuals := Lkh.AcceptActuals(GetContext);
        -- END XXJC (d)
        IF TheActuals <> VOID THEN
          TheActuals.SetFather (THIS);
          END;
        END;
      IF Lkh.CurrentToken = LexicalAnalyzer.LeftBracket THEN
        BrExprList := Lkh.AcceptBrExprList;
        IF BrExprList <> VOID THEN
          BrExprList.SetFather (THIS);
          END;
        END;
      SetSon (TheId);
      END Parse;

    METHOD Id: Ident;
      BEGIN
      RESULT:= TheId;
      END Id;
  
    METHOD BrExpr: ExpressionList;
      BEGIN
      RESULT := BrExprList;
      END BrExpr;
    
    METHOD Actuals: ActualList;
      BEGIN
      RESULT := TheActuals;
      END Actuals;
        
    METHOD SetId(Id: Ident); 
      BEGIN
      TheId := Id;
      END SetId;
    
    METHOD SetBrExpr(BrExpr: ExpressionList);
      BEGIN
      BrExprList := BrExpr;
      END SetBrExpr;

    METHOD SetActuals(Actuals: ActualList);
      BEGIN
      TheActuals := Actuals;
      END SetActuals;

    METHOD IsChange: BOOLEAN;
      VAR
        Meth: MethodDeclaration;
        Status: INTEGER;
      BEGIN
      IF IsBase THEN
        Meth := CurrentSpot.CurrentMethod;
        ASSERT Meth <> VOID;
        Meth := Meth.Redefined(FALSE);
        IF Meth <> VOID THEN
          Status := Meth.NoChangeStatus;
          RESULT := (Status <> MethodDeclaration.MethIsNoChange) AND 
                    (Status <> MethodDeclaration.MethIsNoChangeHC);
          END;
       ELSIF Id.GetRef <> VOID THEN
        WHAT Id.GetRef OF
          IN MethodDeclaration:
            Status := TAG.NoChangeStatus;
            RESULT := (Status <> MethodDeclaration.MethIsNoChange)
                      AND (Status <> MethodDeclaration.MethIsNoChangeHC);
            END;
        ELSE
          END;
        END;
      END IsChange;
          
    REDEFINE METHOD WithSideEffects: BOOLEAN;
      BEGIN
      IF Id.GetRef <> VOID THEN
        WHAT Id.GetRef OF
          IN MethodDeclaration:
            RESULT := TRUE;
            END;
         ELSE
          RESULT := (THERE_IS Act IN TheActuals :-
                                       Act.Expr.WithSideEffects) OR
                    (THERE_IS Expr IN BrExprList :- Expr.WithSideEffects);
          END;
        END;    
      END WithSideEffects;
      
    REDEFINE METHOD Isomorph (Other: TypedNonTerminal): BOOLEAN;
      BEGIN            
      WHAT Other OF
        IN DesigElement:
          IF Id.GetRef = TAG.Id.GetRef THEN 
            RESULT := TRUE;
            IF BrExprList <> VOID THEN
              RESULT := BrExprList.Isomorph (TAG.BrExprList);
              END;
            IF RESULT AND (Actuals <> VOID) THEN
              RESULT := Actuals.Isomorph (TAG.Actuals);
              END;
            END;
          END;
       ELSE
        -- Don't abort, they simply are not Isomorph.
        END;
      END Isomorph;
        
    REDEFINE METHOD WhatAmI: ARRAY OF CHAR;
      BEGIN
      RESULT := "DesigElement";
      END WhatAmI;
      
    VAR
      TheLeftContext: Type;

    METHOD LeftContext: Type;
      VAR
        r: ONCE Ref(ClassDeclaration);
      BEGIN
      IF TheLeftContext = VOID THEN
        IF PreviousElement <> VOID THEN
          TheLeftContext := PreviousElement.GetType;
         ELSE
          IF r = VOID THEN
            r.CREATE (VOID);
           ELSE
            r.Set(VOID);
            END;
          GetAncestor (r);
          ASSERT r.Get <> VOID;
          TheLeftContext := r.Get.ThisType;          
          r.Set(VOID);
          END;
        END;
      RESULT := TheLeftContext;
      END LeftContext;

    METHOD TagSubExprs;
      BEGIN
      IF TheActuals <> VOID THEN
        TheActuals.UniqueTag;
        END;
      IF BrExprList <> VOID THEN
        BrExprList.UniqueTag;
        END;
	  END TagSubExprs;

    METHOD TagWithContext(Context: NonTerminal;
                          WriteContext,
                          PleaseDebug: BOOLEAN): NonTerminal;
      VAR
        Err: BOOLEAN;
        PredefMeth: PredefMethod;
        Ctx: ConstrainedClassDecl;
      
        METHOD BuildContext (PrevContext: ConstrainedClassDecl;
                             IdRef: NonTerminal): NonTerminal;
          VAR
            ActType: Type;
          BEGIN 
          RESULT := IdRef; 
          IF IdRef <> VOID THEN
            WHAT IdRef OF
              IN MethodDeclaration:
                ActType := TAG.Return;
                IF (ActType <> VOID) AND 
                   (ActType.ConstrainedClass <> VOID) THEN
                  RESULT := ActType.ConstrainedClass.
                            BuildContextual(PrevContext);
                  END;
                END; 
             ELSE
              END;
            END;
          END BuildContext;
          
        METHOD MarkUsage (IDecl: SingleDataItem);
          VAR
            AttrContext: Declaration;
            Stmt: Statement;
          BEGIN
          AttrContext := IDecl.Context;
          Stmt := StatementContext;
          IF AttrContext <> VOID THEN
            WHAT AttrContext OF
              IN ClassImplementation:
                IF TAG <> CurrentSpot.CurrentClass THEN
                  Error ("Private attribute access");
                  END;
                END;
             ELSE
              -- Don't abort: it's a local...
              END;
            END;            
          IF NextElement = VOID THEN
            IF (BrExprList = VOID) AND WriteContext THEN
              IDecl.UseWrite(Stmt);
             ELSE
              IDecl.UseRead(Stmt);
              END;
           ELSE
            ASSERT NextElement <> VOID;
            -----------------------
            -- Check if Next is a CREATE method
            -- invocation.
            -----------------------
            IF (BrExprList = VOID) AND NOT WriteContext THEN
              IF NextElement.Id.Data = PredefItems.Create.Id.Data THEN
                IDecl.UseWrite (Stmt);
               ELSE
                IDecl.UseRead (Stmt);
                END;
             ELSE
              IDecl.UseRead (Stmt);
              END;
            END;
          ASSERT (Stmt <> VOID) IMPLIES (IDecl.UsedRead OR IDecl.UsedWrite);
          END MarkUsage;
          
        METHOD TagWithoutContext: NonTerminal;
        
          VAR
            Ctx: ConstrainedClassDecl;
            ActType,
            TheType: Type;
          BEGIN
          Id.UniqueTag;
          IF Id.GetRef <> VOID THEN
            WHAT Id.GetRef OF
              IN MethodDeclaration:
                IF CurrentSpot.CurrentMethod <> VOID THEN
                  TheType := CurrentSpot.CurrentMethod.This.GetType;
                  Ctx := TheType.ConstrainedClass;     
                  ASSERT Ctx <> VOID;
                  ActType := TAG.Return;
                  --------------------------------
                  -- Consider constrained redefinitions
                  --------------------------------
                  IF (ActType <> VOID) AND (ActType.ArrayLevel = 0) THEN
                    ActType := Ctx.SimpleType.ConstrainedReturn (TAG);
                    END;
                  ASSERT ActType <> VOID IMPLIES ActType.IsTagged;
                  IF (ActType <> VOID) AND (ActType.ConstrainedClass <> VOID) THEN
                    RESULT := ActType.ConstrainedClass.BuildContextual(Ctx);
                   ELSE
                    RESULT := Id.GetRef; 
                    END;
                  END;
                END;
             ELSE 
              RESULT := Id.GetRef;   
              END;
            END;
          END TagWithoutContext;
      
      BEGIN
      IF Context = VOID THEN
        RESULT := TagWithoutContext;
       ELSE
        PredefMeth := PredefItems.FindPredefinedMethod (Id.Data);
        IF (PredefMeth <> VOID) THEN
          Id.SetRef (PredefMeth);
          ------------------------------------------------------
          -- First, Handle predefined methods and pseudo-methods
          ------------------------------------------------------
          IF (PredefMeth = PredefItems.Clone) OR
             (PredefMeth = PredefItems.Slice) THEN
            RESULT := Context;
           ELSIF PredefMeth = PredefItems.Size THEN
            RESULT := PredefItems.Integer;
           ELSIF (PredefMeth = PredefItems.Create) OR
                 (PredefMeth = PredefItems.Kill) THEN
            RESULT := VOID;
           ELSIF PredefMeth = PredefItems.Base THEN
            Error("BASE cannot be applied on another object than THIS");
           ELSE
            ASSERT FALSE;
            END;
         ELSE
          ------------------------------------------------------
          -- It should not be treated as
          -- a predefined method or pseudo-method
          ------------------------------------------------------
          WHAT Context OF
            IN CompilationUnit:
              Id.SetRef (TAG.GetClass(Id.Data));
              RESULT := Id.GetRef;
              END;
            IN ClassDeclaration:
              Id.SetRef(TAG.GetDecl(Id.Data));
              Ctx := TAG.MakeConstrainedClass(VOID);
              RESULT := BuildContext(Ctx, Id.GetRef);
              END;
            IN ConstrainedClassDecl:  
              Id.SetRef (TAG.SimpleType.GetDecl(Id.Data));
              Ctx := TAG;
              RESULT := BuildContext(Ctx, Id.GetRef);
              END;
            IN SingleDataItem:
              IF (TAG.GetType <> VOID) AND (TAG.GetType.SimpleType <> VOID)
                  THEN
                Id.SetRef (TAG.GetType.SimpleType.GetDecl(Id.Data));
                Ctx := TAG.GetType.ConstrainedClass;
                RESULT := BuildContext(Ctx, Id.GetRef);
                END;
              END;
           ELSE
            Err := TRUE;
            Error ("Bad context for " + Id.Data + " (" +
                        Context.WhatAmI + ")");
            DEBUG            
              ASSERT FALSE;            
              END;
            END;
          IF (RESULT = VOID) AND NOT Err THEN
            IF Ctx <> VOID THEN
              Error ('Identifier not found in context: ' + Id.Data + '/' +
                   Ctx.Image);
             ELSE
              Error ('Identifier not found in context: ' + Id.Data + '/' +
                   Context.WhatAmI);
              END;
            END;
          END;
        END;
      IF Id.GetRef <> VOID THEN
        WHAT Id.GetRef OF
          IN SingleDataItem:
            ------------------------
            -- Mark the read-and-write context
            -- flags to the data item decl referred
            -- to by the current DesigElement.
            ------------------------
            MarkUsage (TAG);
            END;
         ELSE
          --------------------------          
          -- Marking the usage of the DataItem makes no sense
          -- for other classes then SingleDataItem's.
          --------------------------          
          END;
        END;     
      END TagWithContext;

    REDEFINE METHOD Tag;
      BEGIN
      ASSERT FALSE;
      END Tag;

    METHOD CheckParameters (MethodDecl: MethodDeclaration; 
                            Context: ConstrainedClassDecl);
      BEGIN
      IF NOT (TheActuals = VOID IFF MethodDecl.Arity = 0) THEN
        Error ("Parameters mismatch[2]");
       ELSIF TheActuals <> VOID THEN
        VOID := TheActuals.Match (MethodDecl.Formals, Context);
        END;
      END CheckParameters;
          
    REDEFINE METHOD BuildType: Type;
      VAR
        ConstrainedRes, Ctx, TheType: Type;
        Level, BrSize: INTEGER;
        PreviousElem: DesigElement;
        Constrained, Context: ConstrainedClassDecl;
        Nt: NonTerminal;
      BEGIN
      IF BrExprList <> VOID THEN
        BrSize := BrExprList.Size;
        END;
      PreviousElem := PreviousElement;
      IF PreviousElem <> VOID THEN
        Ctx := LeftContext;
        IF Ctx <> VOID THEN
          Level := Ctx.ArrayLevel;
          END;
        END;
      Nt := Id.GetRef;
      IF Nt <> VOID THEN  
        WHAT Nt OF     
          IN CompilationUnit:
            IF TheActuals <> VOID THEN
              Error ("Not a method");
              END;
            IF BrExprList <> VOID THEN
              Error ("Not an array");
              END;
            END;
          IN ClassDeclaration:
            IF TheActuals <> VOID THEN
              Error ("Not a method");
              END;
            IF BrExprList <> VOID THEN
              Error ("Not an array");
              END;
            IF TAG.Once THEN
              RESULT := TAG.MakeType(0);
              END;
            END;
          ------------------------------------
          IN SingleDataItem:
            IF (Ctx = VOID) OR (Level = 0) THEN
              IF TheActuals <> VOID THEN
                Error ("Unexpected actuals for variable");
               ELSE
                IF (BrExprList = VOID) OR BrExprList.CheckAllIntegers THEN
                  TheType := TAG.GetType;
                  IF TheType = VOID THEN
                    DEBUG
                      Error ("VOID type in data item (" + TAG.Id.Data + ")");
                      END;
                   ELSE
                    IF TheType.ArrayLevel >= BrSize THEN
                      IF BrSize > 0 THEN
                        RESULT := TheType.ConstrainedClass.MakeType
                                           (TheType.ArrayLevel - BrSize);
                       ELSE
                        RESULT := TheType;  
                        END;          
                     ELSE
                      Error ("Array nested too deep");
                      END;
                    END;
                  END;
                END;
              END;
            END; -- of IN SingleDataItem
          --------------------
          IN MethodDeclaration:
            IF (PreviousElem <> VOID) AND (Ctx = VOID) THEN
              Error ("Wrong context for method " + TAG.Id.Data);
             ELSE
              WHAT TAG OF
                IN PredefMethod:
                  RESULT := TAG.BuildType (THIS, PreviousElem);
                  END;
               ELSE
                ------------------------------
                -- The left part must be an
                -- acceptable Value
                ------------------------------
                IF (PreviousElem = VOID) OR PreviousElem.Instance THEN
                  -----------------------------------
                  -- The context of the current element
                  -- must be got from its predecessor
                  -- if it exists. Otherwise, there is
                  -- no context
                  -----------------------------------
                  IF (Ctx = VOID) OR (Level = 0) THEN
                    -------------------------------------
                    -- If the context is VOID, the Method
                    -- is applied to THIS.
                    -------------------------------------
                    IF Ctx = VOID THEN
                      Ctx := CurrentSpot.CurrentMethod.This.GetType;
                      END;
                    ASSERT Ctx <> VOID;
                    -------------------------------------------
                    -- Check the conformity of the parameters;
                    -------------------------------------------
                    ASSERT Ctx.ConstrainedClass <> VOID;
                    Context := Ctx.ConstrainedClass;
                    CheckParameters (TAG, Context);     
                    RESULT := TAG.Return;
                    IF RESULT <> VOID THEN
                      -----------------------------------------
                      -- Take possible constrained redefinition
                      -- into account.
                      -----------------------------------------
                      IF RESULT.ArrayLevel = 0 THEN
                        ConstrainedRes := Ctx.ConstrainedClass.SimpleType.
                                          ConstrainedReturn (Meth := TAG);
                        RESULT := ConstrainedRes;                                        
                        END;
                      -----------------------------------------
                      -- Check if the resulting Type refers to 
                      -- ClassFormals, and find the correct 
                      -- values if it does.
                      -----------------------------------------
                      Constrained := RESULT.ConstrainedClass.
                                     BuildContextual(Context);
                      IF Constrained <> RESULT.ConstrainedClass THEN
                        RESULT := Constrained.MakeType(RESULT.ArrayLevel);
                        ASSERT RESULT <> VOID;
                        END;
                      -----------------------------------------
                      -- Check the conformity of the brackets.
                      -----------------------------------------
                      RESULT := RESULT.MatchBrackets (BrExprList);
                      ASSERT RESULT <> VOID;
                     ELSIF BrExprList <> VOID THEN
                      Error ("Not an array");
                      END;
                   ELSE
                    Error("A method cannot be applied to an array"); 
                    END;
                 ELSE
                  Error ("Left part of this Method is not an acceptable Value");
                  END;
                END;
              END;
            END;
          IN ConstDeclaration:
            IF (TheActuals <> VOID) OR (BrExprList <> VOID) THEN
              Error ("Actuals and/or brackets with constant");
             ELSE
              IF TAG.GetFolded <> VOID THEN
                SetFolded (TAG.GetFolded.CLONE);
                END;
              RESULT := TAG.Expr.GetType;
              END;
            END;
          IN Literal:
            IF TheActuals <> VOID THEN
              Error ("Not a method");
              END;
            IF BrExprList <> VOID THEN
              Error ("Not an array");
              END;
            SetFolded (TAG);
            RESULT := TAG.GetType;
            END;
          END;
        END;
      END BuildType;
  
    METHOD NextElement: DesigElement;
      BEGIN        
      ASSERT TheFather <> VOID;
      RESULT := TheFather.GetElement (TheIndex + 1);
      END NextElement;

    METHOD PreviousElement: DesigElement;
      BEGIN
      ASSERT TheFather <> VOID;
      RESULT := TheFather.GetElement (TheIndex - 1);
      END PreviousElement;

    METHOD LValue: BOOLEAN;
      BEGIN
      IF Value THEN
        IF BrExprList = VOID THEN
          WHAT TheId.GetRef OF
            IN SingleDataItem:
              RESULT := NOT TAG.ReadOnly;
              END;
           ELSE
            RESULT := FALSE;
            END;
         ELSE
          RESULT := TRUE;
          END;
        END;
      END LValue;
      
    METHOD Value: BOOLEAN;
      BEGIN
      IF BrExprList <> VOID THEN
        RESULT := TRUE;
       ELSE
        IF TheId.GetRef <> VOID THEN
          WHAT TheId.GetRef OF
            IN ClassDeclaration:
              RESULT := TAG.Once;
              END;
            IN CompilationUnit:
              RESULT := FALSE;
              END;
           ELSE
            RESULT := TRUE;
            END;
         ELSE
          RESULT := TRUE;
          END;
        END;
      END Value;

    METHOD Instance: BOOLEAN;
      BEGIN
      IF BrExprList <> VOID THEN
        RESULT := TRUE;
       ELSE
        WHAT TheId.GetRef OF
          IN ConstDeclaration:
            RESULT := FALSE;
            END;
          IN ClassDeclaration:
            RESULT := TAG.Once;
            END;
          IN CompilationUnit:
            RESULT := FALSE;
            END;
         ELSE
          RESULT := TRUE;
          END;
        END;
      END Instance;

    REDEFINE METHOD RequiresTempSaving: BOOLEAN;
      BEGIN                  
      IF GetType.UseObjPtr THEN
        WHAT TheId.GetRef OF
          IN SingleDataItem:  
            IF NOT TAG.ReadOnly THEN
              IF TAG.IsLocal THEN
                RESULT := TAG.Once OR TAG.UsedNonLocalWrite;
               ELSE
                RESULT := TAG.IsAttribute;
                END;
              END;
            END;
         ELSE
          -- Implicit FALSE...
          END;
        END;
      END RequiresTempSaving;
      
    METHOD IsVoid: BOOLEAN;
      BEGIN
      RESULT := (BrExprList = VOID) AND (TheActuals = VOID) AND
                (Id.Data = Void.Denotation);
      END IsVoid;

    METHOD IsBase: BOOLEAN;
      BEGIN
      IF Id.GetRef <> VOID THEN
        WHAT Id.GetRef OF
          IN PredefBaseMethod:
            RESULT := TRUE;
            END;
         ELSE
          END;
        END;
      END IsBase;
      
    REDEFINE METHOD UsesValueStack: BOOLEAN;
      VAR          
        t: Type;
      BEGIN
      IF Id.GetRef <> VOID THEN
        WHAT Id.GetRef OF
          IN MethodDeclaration:
            t := TAG.Return;    
            RESULT := ((t <> VOID) AND t.UseObjPtr) OR TAG.IsCreate;
            RESULT := RESULT OR ((PreviousElement <> VOID) AND 
                                PreviousElement.RequiresTempSaving);
            END;
         ELSE 
          END;
        END;
      IF NOT RESULT THEN
        IF Actuals <> VOID THEN
          RESULT := Actuals.UsesValueStack OR Actuals.RequiresTempSaving;
          END;
        IF NOT RESULT THEN
          IF (BrExprList <> VOID) THEN
            RESULT := BrExprList.UsesValueStack;
            END;
          END;
        END;
      END UsesValueStack;

    VAR 
      TheCall : CallReference;       
      TheCallAsked: BOOLEAN;
      TheOptimizedMethod: MethodReference;
      TheOptimizedMethodAsked: BOOLEAN;
      TheAttribute : AttributeReference;
      TheAttributeAsked : BOOLEAN;

    METHOD AttributeRef(TheClass: ClassDeclaration):AttributeReference;
      BEGIN
      IF NOT TheAttributeAsked THEN
        TheAttributeAsked := TRUE;
        TheAttribute := AttributeDictionary.FindAttribute 
                   (TheClass.Module.Id.Data, TheClass.Id.Data, Id.Data);
        END;                             
      RESULT := TheAttribute;
      END AttributeRef;
      
    METHOD CallRef: CallReference;
      VAR
        TheClass : ClassDeclaration;
        MethRef: MethodReference;
      BEGIN
      IF NOT TheCallAsked THEN
        TheCallAsked := TRUE;
        IF LeftContext <> VOID THEN
          TheClass := LeftContext.SimpleType.ClosestCanonic;
          IF (TheClass = VOID) THEN 
            -- StdOut.WriteInt (LineNr, 5);
            -- StdOut.WriteLine ("  VOID Left context : " + Id.Data);
           ELSIF (Id.GetRef = VOID) THEN
            -- StdOut.WriteLine ("VOID Id.GetRef : " + Id.Data);
           ELSIF (LeftContext.ArrayLevel = 0) THEN
            WHAT Id.GetRef OF
              IN PredefBaseMethod: 
                MethRef := CurrentSpot.CurrentMethod.Reference.Redefines;
                IF MethRef <> VOID THEN
                  TheCall := MethRef.CallRef;
                  TheOptimizedMethod := MethRef;
                  END;           
                END;
              IN MethodDeclaration:
                TheCall := CallDictionary.FindCall (TheClass.Module.Id.Data,
                                                    TheClass.Id.Data, Id.Data);
                END;
             ELSE
              -- Don't abort...
              END;
            END;
          END;
        END;
      RESULT := TheCall;
      END CallRef; 
      
    METHOD FirstPassCallRef: CallReference;
      BEGIN
      IF IsBase THEN
        RESULT := CallDictionary.FindCall (CurrentSpot.CurrentModule.Id.Data,
                                           CurrentSpot.CurrentClass.Id.Data,
                                           CurrentSpot.CurrentMethod.Id.Data);
        
       ELSE
        RESULT := CallRef;
        END;
      END FirstPassCallRef; 
      
    METHOD OptimizedMethodRef: MethodReference;
      BEGIN                            
      VOID := CallRef;
      IF NOT TheOptimizedMethodAsked AND (TheOptimizedMethod = VOID) THEN
        TheOptimizedMethodAsked := TRUE;
        IF CallRef <> VOID THEN
          TheOptimizedMethod := CallRef.OptimizedMethod;
          END;
        END;          
      RESULT := TheOptimizedMethod;
      END OptimizedMethodRef;
            
    ------------------------------------
    -- Generates direct call to the rigth version of the method.
    -- This method should be used only if the call is monomorphic. 
    ------------------------------------
--    METHOD GenerateDirectCall : BOOLEAN;
--      BEGIN
--      ASSERT GetCall.IsMonomorphic;
--      END GenerateDirectCall;
 
    -----------------------------------------
    -- 
    -----------------------------------------
    METHOD VisitMethInvocation (Meth: MethodDeclaration);
      VAR
        Class     : ClassDeclaration;
      BEGIN                          
      IF (LeftContext.ArrayLevel = 0) AND 
          YaflCfg.PleaseOptimizeDirectLink  THEN  
        Class := LeftContext.SimpleType;
        CallDictionary.IncrementCall (Class.Module.Id.Data, Class.Id.Data,
                                       Meth.Id.Data);
        END;
      END VisitMethInvocation;                                  
                   
    --------------------------
    -- Adds the BASE method in the MethodQueue.
    -- If the BASE method exists, it can be optimized
    --------------------------
    METHOD VisitBase (Method : MethodImplementation);
      VAR
        MethRef, BaseMethRef: MethodReference;
      BEGIN                                   
      MethRef := Method.Reference;
      BaseMethRef := MethRef.Redefines;
      IF BaseMethRef <> VOID THEN
        ASSERT BaseMethRef <> MethRef;
        BaseMethRef.CallRef.Increment;
        MethodQueue.Push (BaseMethRef);
        END;
      END VisitBase;
      
    ---------------------------
    -- Extracts the Class of the CREATE method,
    -- marks the class a being used and
    -- Add the CREATE method in ToVisit & Visited
    ---------------------------
    METHOD VisitCreate;
      VAR
        Ctx          : Type;
        Cl           : ClassReference;
        Create       : MethodReference;
      BEGIN 
      Ctx := LeftContext;
      ASSERT Ctx <> VOID;
      IF Ctx.ArrayLevel = 0 THEN    -- ARRAY's CREATE? Yes -> do nothing
        Cl := Ctx.SimpleType.Reference;
        IF NOT Cl.Removed THEN     
          Create := Cl.Create;
          IF Create <> VOID THEN
            MethodQueue.Push(Create);
            END;
          END;
        END;
      END VisitCreate;       

    --------------------------------------      
    -- 
    --------------------------------------      
    METHOD Visit(Method: MethodImplementation);
      BEGIN
      IF Id.GetRef <> VOID THEN
        WHAT Id.GetRef OF
          IN PredefMethod:
            IF TAG = PredefItems.Create THEN
              VisitCreate;
             ELSIF TAG = PredefItems.Base THEN
              ASSERT Method <> VOID;
              VisitBase (Method);
              END;
            END;
          IN MethodDeclaration:
            VisitMethInvocation(TAG);
            END;
         ELSE
          END;
        END;
      END Visit;

    METHOD FunctionalWithoutArrays: BOOLEAN;
      BEGIN
      RESULT := FOR_ALL Act IN Actuals :- Act.Expr.Functional;
      IF RESULT AND (PreviousElement <> VOID) THEN
        RESULT := PreviousElement.Functional;
	 END;
      END FunctionalWithoutArrays;

    REDEFINE METHOD Functional: BOOLEAN;
      BEGIN
      RESULT := FunctionalWithoutArrays AND
                   FOR_ALL Expr IN BrExprList :- Expr.Functional;
      END Functional;
    
  END DesigElement;

----------------------------------------
  CLASS Desig;
    INHERITS TypedNonTerminal(DesigCodeGenerator);
    
    VAR
      DesigElementList: NTList(DesigElement);
      WriteContext: BOOLEAN;

    METHOD Size: INTEGER;
      BEGIN    
      RESULT := DesigElementList.Size;
      END Size;                     
      
    METHOD First: DesigElement;
      BEGIN
      RESULT := DesigElementList.First;
      END First;
      
    METHOD Last: DesigElement;
      BEGIN
      RESULT := DesigElementList.Last;
      END Last;
      
    METHOD GetElement (Index: INTEGER): DesigElement;
      BEGIN          
      IF Index < DesigElementList.Size THEN
        RESULT := DesigElementList.Get(Index);
	END;
      END GetElement;
      
    METHOD SetElements(DesigElList: NTList(DesigElement));
      BEGIN
      DesigElementList := DesigElList;
      Renumber;
      END SetElements;
  
    METHOD Elements: NTList(DesigElement);
      BEGIN
      RESULT := DesigElementList;
      END Elements;
      
    REDEFINE METHOD SubTree: ARRAY OF NonTerminal;
      BEGIN
      IF DesigElementList <> VOID THEN
        RESULT := DesigElementList.SubTree;
        END;
      END SubTree;
      
    METHOD Renumber;
      BEGIN
      DesigElementList.SetFather (THIS);
      FOR i := 0 TO DesigElementList.Size - 1 DO
        DesigElementList.Get(i).SetIndex (i);
        END;
      END Renumber;

    REDEFINE METHOD Parse(Lkh: LookAhead);   
      BEGIN
      DesigElementList.CREATE;
      DesigElementList.Append (Lkh.AcceptDesigElement(GetContext));
      WHILE Lkh.CurrentToken = LexicalAnalyzer.Dot DO
        Lkh.GetToken;
        DesigElementList.Append (Lkh.AcceptDesigElement(GetContext));
        END;
      Renumber;        
      END Parse;

    REDEFINE METHOD WhatAmI: ARRAY OF CHAR;
      BEGIN
      RESULT := "Desig";
      END WhatAmI;

    REDEFINE METHOD Tag;
      BEGIN
      FOR El IN DesigElementList DO
        El.TagSubExprs;
        END;
      DesigElementList.First.Id.UniqueTag;
      END Tag;
      
    METHOD LateTag;
      VAR
        Context: NonTerminal;
        GoOn: BOOLEAN;
      BEGIN
      Context := DesigElementList.First.
                      TagWithContext (VOID, WriteContext, FALSE);
      GoOn := TRUE;
      FOR i := 1 TO Size - 1 WHILE GoOn DO      
        IF Context = VOID THEN
          DesigElementList.Get(i-1).Error ("VOID resulting context");
          GoOn := FALSE;
          END;
        Context := DesigElementList.Get(i).
                     TagWithContext(Context, WriteContext, FALSE);
        END;
      IF NOT Value THEN
        Error ("The designator holds no value");
        END;
      END LateTag;

    REDEFINE METHOD BuildType: Type;
      BEGIN
      LateTag;
      FOR El IN DesigElementList DO
        VOID := El.GetType;
        END;
      RESULT := DesigElementList.Get(Size-1).GetType;
      SetFolded (Last.GetFolded);
      END BuildType;

    REDEFINE METHOD WithSideEffects: BOOLEAN;
      BEGIN               
      ASSERT DesigElementList <> VOID;
      RESULT := THERE_IS El IN DesigElementList :- El.WithSideEffects;
      END WithSideEffects;

    METHOD LValue: BOOLEAN;
      BEGIN
      RESULT := DesigElementList.Last.LValue;
      END LValue;

    METHOD Value: BOOLEAN;
      BEGIN
      RESULT := DesigElementList.Last.Value;
      END Value;

    METHOD IsVoid: BOOLEAN;
      BEGIN
      RESULT := (Size = 1) AND DesigElementList.First.IsVoid;
      END IsVoid;


    METHOD IsChange: BOOLEAN;
      BEGIN
	  RESULT := THERE_IS El IN Elements :- El.IsChange;
      END IsChange;
      
      
    REDEFINE METHOD Isomorph (Other: TypedNonTerminal): BOOLEAN;
      BEGIN
      WHAT Other OF
        IN Desig: 
          RESULT := (Size = TAG.Size) AND
            FOR_ALL i IN 0 TO Size - 1 :-
              DesigElementList.Get(i).Isomorph(TAG.DesigElementList.Get(i));
          END;
       ELSE
        -- Don't abort, the two TypedNonTerminal simply are not
        -- isomorphic.
        END;
      END Isomorph;
      
    REDEFINE METHOD UsesValueStack: BOOLEAN;
      BEGIN
      RESULT := THERE_IS El IN DesigElementList :- El.UsesValueStack;
      END UsesValueStack;
      
    METHOD UseInWriteContext;
      BEGIN
      WriteContext := TRUE;
      END UseInWriteContext;
      
    REDEFINE METHOD RequiresTempSaving: BOOLEAN;
      BEGIN                  
      RESULT := Last.RequiresTempSaving;
      END RequiresTempSaving;

    REDEFINE METHOD Functional: BOOLEAN;
      BEGIN
      RESULT := Last.Functional;
      END Functional;

  END Desig;


END YaflDesignator;
