IMPLEMENTATION MODULE YaflMethods;

FROM YaflLex IMPORT LexicalAnalyzer;
FROM List IMPORT List;
IMPORT Ref;
IMPORT Space;
FROM YaflSymbols IMPORT SymbolTable;
FROM YaflError IMPORT WarningHandler, MainErrorHandler;
FROM YaflCfg IMPORT YaflCfg;
FROM YaflDeclarations IMPORT SingleDataItem, ConstDeclaration, InheritsClause;
FROM YaflModules IMPORT CompilationUnit;
FROM YaflNTList IMPORT MultiDeclList;
FROM YaflParamClasses IMPORT ClassFormal;
FROM YaflPredefined IMPORT PredefItems, PredefDataItem, PredefMethod, 
                           ResultDataItem;
FROM YaflStatements IMPORT Statement;
FROM YaflCfg IMPORT CurrentSpot;
FROM YaflClasses IMPORT VirtualClassDecl;
FROM YaflMetImplementation IMPORT MethodImplementation;
FROM YaflPreconditions IMPORT PreCondition, PostCondition;
FROM YaflDictionary IMPORT EntryReference,
                           ClassReference,
                           EntryDictionary,
                           MethodReference, 
                           MethodDictionary;
FROM Conversions IMPORT IntConversions;
FROM Streams IMPORT StdOut;

  CLASS MethodDeclaration(gc IN MethDeclCodeGenerator);
    INHERITS Declaration(gc);

    VAR
      TheId: Ident;
      TheRedefine, TheDeferred: BOOLEAN;
      TheFormalList: FormalList;
      TheReturn: Type;
      ImmediateRedefined,
      OriginalRedefined: MethodDeclaration;
      TheStrap: SystemMethod;
      TheBeenRedefined: BOOLEAN;
      TheSubDecls: MultiDeclList;
      ThePreCond: PreCondition;
      ThePostCond: PostCondition;
      TheMethodNumberInMinDual : INTEGER;
      TheLocalResult: ResultDataItem;
      

    REDEFINE METHOD CREATE(LineNr, ColNr : INTEGER);
      BEGIN      
      BASE (LineNr, ColNr);
      TheFormalList.CREATE;
      TheSubDecls.CREATE;
      TheSubDecls.SetFather (THIS);
      TheSubDecls.AppendList (TheFormalList);
      TheMethodNumberInMinDual := -1;
      END CREATE;
      
    REDEFINE METHOD SubDecls: MultiDeclList;
      BEGIN        
      RESULT := TheSubDecls;
      END SubDecls;
      
    REDEFINE METHOD WhatAmI: ARRAY OF CHAR;
      BEGIN
      RESULT := "MethodDeclaration";
      END WhatAmI;

    METHOD Enclosing: MethodImplementation;
      BEGIN
      -- Default is to return VOID.
      END Enclosing;
      
    METHOD IsLocal: BOOLEAN;
      BEGIN
      -- Default is to return false.
      END IsLocal;

    METHOD Nesting: INTEGER;
      BEGIN
      -- Default is to return 0
      END Nesting;

    METHOD SetBeenRedefined;
      BEGIN
      TheBeenRedefined := TRUE;
      END SetBeenRedefined;

    METHOD BeenRedefined: BOOLEAN;
      BEGIN
      RESULT := TheBeenRedefined;
      END BeenRedefined;

    METHOD Strap(Meth: SystemMethod);
      BEGIN
      TheStrap := Meth;
      END Strap;

    METHOD Strapped: SystemMethod;
      BEGIN
      RESULT := TheStrap;
      END Strapped;

    METHOD Class: ClassDeclaration;
      VAR
        p: ONCE Ref(ClassDeclaration);
      BEGIN
      IF p = VOID THEN
        p.CREATE(VOID);
        END;
      GetAncestor(p);
      RESULT := p.Get;
      DEBUG
        IF RESULT = VOID THEN
          Warning ("No parent class defined");
          ASSERT FALSE;
          END;
        END;
      p.Set (VOID);
      END Class;

    REDEFINE METHOD Id: Ident;
      BEGIN
      RESULT:= TheId;
      END Id;

    REDEFINE METHOD SubTree: ARRAY OF NonTerminal;
      BEGIN
      RESULT.CREATE (2);
      RESULT [0] := TheId;
      RESULT [1] := TheReturn;
      RESULT := RESULT + BASE;
      END SubTree;

    METHOD Redefine: BOOLEAN;
      BEGIN
      RESULT := TheRedefine;
      END Redefine;
      
    METHOD AppearsInDual : BOOLEAN;
      BEGIN                      
      ASSERT NOT Redefine;
      IF Publish THEN
        RESULT := TRUE;
       ELSIF Class.Once THEN
        RESULT := FALSE;
       ELSE 
        RESULT := (Public OR BeenRedefined);
        -----------------------------------------------           
        -- Cut & paste of the formal post conditions
        -----------------------------------------------           
        ASSERT (NOT Public AND NOT BeenRedefined AND NOT Publish 
                                               IMPLIES NOT RESULT);
        
        IF RESULT AND YaflCfg.PleaseGlobalOptimize THEN
          RESULT := EntryRef.IsPolymorphic;
          END;
        END;            
      ASSERT (IsLocal IMPLIES NOT RESULT);
      END AppearsInDual;
      
    METHOD Deferred: BOOLEAN;
      BEGIN
      RESULT:= TheDeferred;
      END Deferred;

    METHOD Return: Type;
      BEGIN
      RESULT:= TheReturn;
      END Return;

    METHOD Formals: FormalList;
      BEGIN
      RESULT := TheFormalList;
      END Formals;

    METHOD ReturnObjPtr: BOOLEAN;
      BEGIN
      IF TheReturn = VOID THEN
        RESULT := FALSE;
       ELSE
--------------------------------------------------------------------------
-- caution: it is possible that TheLocalResult is VOID in the case of a deferred
-- method for example; but in this case the VarType pragma should not be
-- used anyway so CName has no meaning
--------------------------------------------------------------------------
        IF (TheLocalResult <> VOID) AND(TheLocalResult.GetCName <> VOID) THEN
          RESULT := TRUE;
         ELSE
          RESULT := TheReturn.UseObjPtr;
          END; -- IF
        END; -- IF
      END ReturnObjPtr;

    METHOD EnterFormals;
      BEGIN                        
      Formals.Enter;
      END EnterFormals;
      
    METHOD GetPreCondition: PreCondition;
      BEGIN
      RESULT := ThePreCond;
      END GetPreCondition;
      
    METHOD GetPostCondition: PostCondition;
      BEGIN
      RESULT := ThePostCond;
      END GetPostCondition;

    -- XXJC (d)
    METHOD SetPreCondition(Pre: PreCondition);
      BEGIN
      ASSERT ThePreCond = VOID;
      ThePreCond := Pre;
      END SetPreCondition;

    METHOD SetPostCondition(Post: PostCondition);
      BEGIN
      ASSERT ThePostCond = VOID;
      ThePostCond := Post;
      END SetPostCondition;
    -- END XXJC (d)
    
    METHOD Match (Other:         MethodDeclaration;
                  CheckRedefine: BOOLEAN): BOOLEAN;
      BEGIN
      IF NOT CheckRedefine OR (TheRedefine IFF Other.TheRedefine) THEN
        IF NOT CheckRedefine OR (NOT TheDeferred AND NOT Other.Deferred) THEN
          ASSERT Other.Id.Data = Id.Data;
          IF (TheReturn = VOID IFF Other.TheReturn = VOID) AND
             (TheFormalList = VOID IFF Other.TheFormalList = VOID) THEN
            RESULT := TRUE;
            --------------------------------------------------
            -- Compare the Return Clauses.
            --------------------------------------------------
            IF TheReturn <> VOID THEN
              RESULT := TheReturn.Match(Other.TheReturn);
              END;
            IF RESULT THEN
              -------------------------------
              -- Compare the formal parameters.
              -------------------------------       
              RESULT := Formals.Match(THIS, Other.TheFormalList, VOID);
              END;
            END;
          END;
        END;
      END Match;

    METHOD UseStaticAnchor: BOOLEAN;
      BEGIN
      END UseStaticAnchor;
      
    METHOD ParseDeclaration(Lkh: LookAhead);
      BEGIN 
      IF Lkh.CurrentToken = LexicalAnalyzer.Redefine THEN
        TheRedefine := TRUE;
        Lkh.GetToken;
       ELSIF Lkh.CurrentToken = LexicalAnalyzer.Deferred THEN
        TheDeferred := TRUE;
        Lkh.GetToken;
        END;
      Lkh.Accept (LexicalAnalyzer.Method);
      IF NOT Lkh.Ok THEN
        WHILE (Lkh.CurrentToken <> Lkh.SemiColon) AND 
              (Lkh.CurrentToken <> Lkh.Eof) DO
          Lkh.GetToken;
          END;
        Lkh.Reset;
       ELSE 
        TheId := Lkh.AcceptIdent;
        SetSon (TheId);
        SubDecls.AppendFromList (Lkh.AcceptFormalList);
        TheReturn := Lkh.AcceptReturn;
        SetSon (TheReturn);
        END;
      Lkh.Accept (LexicalAnalyzer.SemiColon);
      ThePreCond := Lkh.AcceptPreCondition;
      SetSon(ThePreCond);
      ThePostCond := Lkh.AcceptPostCondition;
      SetSon(ThePostCond);
      END ParseDeclaration;

    --------------------------------
    -- Returns TRUE if THIS is indeed
    -- a predefined method
    --------------------------------
    METHOD IsPredefined: BOOLEAN;
      VAR
        Mth: PredefMethod;
      BEGIN
      IF Id <> VOID THEN
        Mth := PredefItems.FindPredefinedMethod(Id.Data);
        IF Mth <> VOID THEN
          IF (Mth <> PredefItems.Create) AND (Mth <> PredefItems.Clone) 
              AND (Mth <> PredefItems.Kill) THEN
            Error ("Conflicting definition");
            END;
          RESULT := TRUE;
          END;
        END;
      END IsPredefined;

    METHOD IsCreate: BOOLEAN;
      BEGIN
      RESULT := Id.Data = PredefItems.Create.Id.Data;
      END IsCreate;
      
    VAR
      GotRedefined: BOOLEAN;

    --------------------------------------------
    -- Returns the previous or the original
    -- declaration of a redefined method,
    -- depending on the parameter's value.
    --------------------------------------------
    METHOD Redefined(Original: BOOLEAN): MethodDeclaration;
      VAR
        ClassDecl: ClassDeclaration;
        Decl: Declaration;
      BEGIN
      IF TheRedefine THEN
        IF NOT GotRedefined THEN
          GotRedefined := TRUE;
          ClassDecl := Class;
          IF ClassDecl.Inherits <> VOID THEN
            ClassDecl := ClassDecl.Inherits.Class;
           ELSE
            ClassDecl := VOID;
            END;
          IF (ClassDecl = VOID) THEN
            --------------------------------------
            -- CREATE and CLONE must be redefined,
            -- so they don't necessarily have a 
            -- previous definition.
            --------------------------------------
            IF (NOT IsCreate) AND
               (Id.Data <> PredefItems.Clone.Id.Data) AND
               (Id.Data <> PredefItems.Kill.Id.Data) THEN
              Error("No method to redefine (no inheritance)");
              END;
           ELSE
            Decl := ClassDecl.GetDecl (Id.Data);
            IF (Decl = VOID) THEN
              IF (NOT IsCreate) AND
                 (Id.Data <> PredefItems.Kill.Id.Data) AND
                 (Id.Data <> PredefItems.Clone.Id.Data) THEN
                Error("No method to redefine");
                END;
             ELSE
              WHAT Decl OF
                IN MethodDeclaration:
                  -----------------------------------
                  -- Memorize the previous definition
                  -----------------------------------
                  ImmediateRedefined := TAG;
                  TAG.SetBeenRedefined;
                  IF ImmediateRedefined.Redefine THEN
                    -------------------------------------
                    -- Search for the original definition
                    -------------------------------------
                    OriginalRedefined := ImmediateRedefined.Redefined (TRUE);
                    IF OriginalRedefined <> VOID THEN
                      OriginalRedefined.SetBeenRedefined;
                      END;
                   ELSE
                    OriginalRedefined := TAG;
                    END;
                  END;
               ELSE
                Error ("Can only redefine methods");
                END;
              END;
            END;
          END;
        IF Original THEN
          RESULT := OriginalRedefined;
         ELSE
          RESULT := ImmediateRedefined;
          END;
        END;
      END Redefined;              
      
    --------------------------------------------
    -- The ConstrainedRedefinition method indicates whether
    -- THIS refers to a redefinition where the resulting type
    -- is a derived class (instead of being strictly isomorphic)
    -- of what the previous definition indicated.
    --------------------------------------------
    METHOD ConstrainedRedefinition: BOOLEAN;
      VAR
        Prev: MethodDeclaration;
        PrevReturn: Type;
      BEGIN
      IF Return <> VOID THEN
        Prev := Redefined (Original := FALSE);
        IF (Prev <> VOID) THEN
          PrevReturn := Prev.Return;
          ASSERT PrevReturn <> VOID;
          RESULT := NOT Return.Match (PrevReturn);
          END;
        END;
      END ConstrainedRedefinition;
      
    METHOD ConformantRedefined: MethodDeclaration;
      BEGIN
      RESULT := Redefined (Original := FALSE);
      WHILE NOT RESULT.ConstrainedRedefinition AND 
                (RESULT <> OriginalRedefined) DO
        RESULT := RESULT.Redefined (Original := FALSE);                
        END;        
      END ConformantRedefined;

    METHOD TagHeader;
      BEGIN
      ASSERT Id <> VOID;
      Id.SetRef (THIS);
      Formals.UniqueTag;
      IF Return <> VOID THEN
        Return.UniqueTag;
        END;
      END TagHeader;
            
    ------------------------------------
    -- Enter the variable RESULT
    -- and its type in the symbol table.
    ------------------------------------  
    METHOD EnterResult;
      BEGIN
      IF TheLocalResult = VOID THEN
        TheLocalResult.CREATE (THIS);
        SetSon (LocalResult);
        TheLocalResult.SetType (Return);
        END;
      SymbolTable.Enter (TheLocalResult.Id.Data, TheLocalResult);
      END EnterResult;
      
    METHOD LocalResult: PredefDataItem;  
      BEGIN
      RESULT := TheLocalResult;
      END LocalResult;

    METHOD SetAssertionsVisibility;
      BEGIN
      Class.Consts.Enter;
      Class.Methods.Enter;
      Class.EnterInheritedSymbols;
      This.Enter;
      END SetAssertionsVisibility;
        
    ----------------------------------
    -- Tag Pre- and Post Conditions
    ----------------------------------    
    METHOD TagAssertions;
      BEGIN    
      IF YaflCfg.VerboseLevel > 2 THEN
        StdOut.WriteLine("MethodDeclaration.TagAssertions: " +
                         Id.Data + "(" + 
                         IntConversions.IntToString(LineNr, 0) + "," 
                         + IntConversions.IntToString(ColNr, 0) +")" );
        END;
	  IF (ThePreCond <> VOID) OR (ThePostCond <> VOID) THEN
	    CurrentSpot.PushCurrentMethod (THIS);
        ----------
        -- For the Pre and Post conditions we may referenced the formals and the
        -- predefined RESULT. Thus they must be visible.
        ----------
        --SetAssertionsVisibility;
        SymbolTable.PushLevel;
        EnterFormals; 
        IF ThePreCond <> VOID THEN
          ThePreCond.UniqueTag;
          END;
        IF ThePostCond <> VOID THEN
          -------------  
          -- We enter the NoChange method in the symbol table here to 
          -- make visible only in the post-conditions.  
          ------------------------
          IF Return <> VOID THEN
            EnterResult;
            END;
          PredefItems.NoChange.Enter;
          PredefItems.NoChangeHC.Enter;
          ThePostCond.UniqueTag;
          END;
        SymbolTable.PopLevel;
        CurrentSpot.PopCurrentMethod;
        END;
      END TagAssertions;
        
    REDEFINE METHOD Tag;
      BEGIN
      TagHeader;   
      END Tag;
      
    REDEFINE METHOD CheckType;
      BEGIN
      CurrentSpot.PushCurrentMethod (THIS);
      ---------------------------------------------
      -- Make sure that predefined methods are well
      -- formed.
      --
      -- First, consider the CREATE case:
      --   . It cannot hold a return value
      ---------------------------------------------
      IF IsCreate THEN
        IF Return <> VOID THEN
          Error ("CREATE should not return a value");
          END;
      ---------------------------------------------
      -- Then, consider the CLONE case:
      --   . It cannot hold a return value
      --   . It should take a single parameter; of the same
      --     class as the enclosing class.
      ---------------------------------------------
       ELSIF Id.Data = PredefItems.Clone.Id.Data THEN
        IF Return <> VOID THEN
          Error ("CLONE should not return a value");
         ELSIF (Arity <> 1) OR
                NOT Formals.Get(0).GetType.Match(Class.This.GetType) THEN
          Error ("Badly formed CLONE");
          END;
       ELSIF Id.Data = PredefItems.Kill.Id.Data THEN
        IF Return <> VOID THEN
          Error ("KILL should not return a value");
         ELSIF Arity > 0 THEN
          Error ("KILL does not accept parameters");
          END;
        END;
      IF YaflCfg.VerboseLevel > 1 THEN
        StdOut.WriteLine(WhatAmI + "("
                           + IntConversions.IntToString(LineNr,0)
                           + "," 
                           + IntConversions.IntToString(ColNr,0)
                           +") : CheckType");
        END;
      IF ThePreCond <> VOID THEN
        ThePreCond.UniqueCheckType;
        END;
      IF ThePostCond <> VOID THEN
        IF YaflCfg.VerboseLevel >= 3 THEN
          StdOut.WriteLine("Postcondition CheckType: " 
                            + Class.Module.Id.Data + "."
                            + Id.Data + "(" 
                            + IntConversions.IntToString(LineNr,0) + ","
                            + IntConversions.IntToString(ColNr,0) + ")");
          END;
        ThePostCond.UniqueCheckType;
        END;
      IF NoChangeRequested THEN
        IF NoChangeStatus <> MethIsNoChange THEN
          Warning("Method is not NO_CHANGE");
          END;
        END;
      CurrentSpot.PopCurrentMethod;
      END CheckType;

    METHOD Arity: INTEGER;
      BEGIN
      RESULT := Formals.Size;
      END Arity;    
      
    METHOD NeedsSeparateAnchor: BOOLEAN;
      BEGIN
      IF Publish THEN
        RESULT := TRUE;
       ELSE
        RESULT := NOT Redefine AND
                  NOT Class.Once AND
                  NOT IsCreate AND 
                  NOT IsLocal;
        END;         
      ASSERT Deferred IMPLIES RESULT;
      ASSERT IsPredefined IMPLIES NOT RESULT;                
      END NeedsSeparateAnchor;
      
    VAR
      TheCallBackName: ARRAY OF CHAR;
      ThePublish: BOOLEAN;

    METHOD CallBackName: ARRAY OF CHAR;
      BEGIN
      RESULT := TheCallBackName;
      END CallBackName;
      
    METHOD SetCallBackName (TheName: ARRAY OF CHAR);
      BEGIN
      TheCallBackName := TheName;
      END SetCallBackName;

    METHOD SetPublish(Publish: BOOLEAN);
      BEGIN
      ThePublish := Publish;
      IF Publish THEN
        IF IsPredefined THEN
          Error ("Cannot publish a predefined method");
         ELSIF Redefine THEN
          Error ("Cannot publish a method redefinition");
         ELSIF IsLocal THEN
          Error ("Cannot publish a local method");
          END;
        END; 
      END SetPublish;

    METHOD Publish: BOOLEAN;
      BEGIN
      RESULT := ThePublish;
      END Publish;
      
    METHOD This: ThisDataItem;         
      BEGIN
      RESULT := Class.This;
      END This;
      
    METHOD Public: BOOLEAN;
      BEGIN
      -- RESULT := FALSE;
      END Public;
     
    VAR
      TheNoChangeRequestedFlag: BOOLEAN;
      TheNoChangeHCRequestedFlag: BOOLEAN;
      TheNoChangeStatus: INTEGER;
      NoChangeStatusAsked: BOOLEAN;

    METHOD SetNoChangeStatus(Status: INTEGER);
      BEGIN
      ASSERT NOT NoChangeStatusAsked;
      TheNoChangeStatus := Status;
      NoChangeStatusAsked := TRUE;
      END SetNoChangeStatus;
          
    METHOD ComputeNoChangeStatus;
      BEGIN
      IF NoChangeRequested THEN
        TheNoChangeStatus := MethIsNoChange;
      ELSIF NoChangeHCRequested THEN
        TheNoChangeStatus := MethIsNoChangeHC;
      ELSE
        TheNoChangeStatus := MethIsUndefined;
        END;
      NoChangeStatusAsked := TRUE;
      END ComputeNoChangeStatus;

    METHOD NoChangeStatus: INTEGER;
      BEGIN
      IF NOT NoChangeStatusAsked THEN
        ComputeNoChangeStatus;
        END;
      RESULT := TheNoChangeStatus;
      END NoChangeStatus;

    METHOD NoChangeRequested: BOOLEAN;
      BEGIN
      RESULT := TheNoChangeRequestedFlag;
      IF NOT RESULT AND (Redefined(FALSE) <> VOID) THEN
        RESULT := Redefined(FALSE).NoChangeRequested;
        END;
      END NoChangeRequested;
      
    METHOD SetNoChangeRequested;
      BEGIN
      TheNoChangeRequestedFlag := TRUE;
      END SetNoChangeRequested;
      
    METHOD NoChangeHCRequested: BOOLEAN;
      BEGIN
      RESULT := TheNoChangeHCRequestedFlag;
      IF NOT RESULT AND (Redefined(FALSE) <> VOID) THEN
        RESULT := Redefined(FALSE).NoChangeHCRequested;
        END;
      END NoChangeHCRequested;
      
    METHOD SetNoChangeHCRequested;
      BEGIN
      TheNoChangeHCRequestedFlag := TRUE;
      END SetNoChangeHCRequested;

--    METHOD CheckNoChange;
--      BEGIN
--      END CheckNoChange;
     
    METHOD IsNoChange: BOOLEAN;
      BEGIN
      RESULT := NoChangeRequested;
      IF (NOT RESULT) AND (Redefined(FALSE) <> VOID) THEN
        RESULT := Redefined(FALSE).IsNoChange;
        END;
      END IsNoChange;
     
    ----------------------------------  
    -- Access to the dictionnaries entries
    ----------------------------------  

    METHOD EntryRef: EntryReference;
      BEGIN
      IF Deferred THEN        
        RESULT := EntryDictionary.FindEntry (Class.Module.Id.Data,
                                              Class.Id.Data,
                                              Id.Data);
       ELSE 
        RESULT := Reference.EntryRef;
        END;                                            
      END EntryRef;
      
    --------------------------------
              
    VAR
      TheRef : MethodReference;
    
    METHOD Reference: MethodReference;
      BEGIN                    
      IF TheRef = VOID THEN
        TheRef := MethodDictionary.FindMethod (Class.Module.Id.Data,
                                               Class.Id.Data,
                                               Id.Data);
        IF TheRef = VOID THEN
          MethodDictionary.AppendMethod (THIS);
          TheRef := MethodDictionary.FindMethod (Class.Module.Id.Data,
                                                 Class.Id.Data,
                                                 Id.Data);
          END; -- IF
        END; -- IF
      RESULT := TheRef;
      ASSERT (RESULT <> VOID) OR Deferred; 
      END Reference;
      
    METHOD EnterInDictionary;
      BEGIN
      DEBUG 
        IF YaflCfg.VerboseLevel > 2 THEN
          StdOut.WriteLine (WhatAmI + "(" +
                            IntConversions.IntToString (Id.LineNr, 0) +
                            "," +
                            IntConversions.IntToString (Id.ColNr, 0) +
                            ") : " + Id.Data + " : Enter In Dictionary");
          END; -- IF                                     
        END; -- DEBUG
      
      ASSERT NOT Deferred;

      Reference.SetState (State);
      END EnterInDictionary;

    METHOD SetMethodNumberInMinDual (In: INTEGER);
      BEGIN
      ASSERT TheMethodNumberInMinDual < 0;
      TheMethodNumberInMinDual := In;
      END SetMethodNumberInMinDual;

    METHOD GetMethodNumberInMinDual : INTEGER;
      BEGIN
      ASSERT TheMethodNumberInMinDual >= 0;
      RESULT := TheMethodNumberInMinDual;
      END GetMethodNumberInMinDual;

             
  END MethodDeclaration;

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

  CLASS Formal;
    INHERITS SingleDataItem;

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

    REDEFINE METHOD IsLocal: BOOLEAN;
      BEGIN
      RESULT := FALSE;
      END IsLocal;  

    REDEFINE METHOD IsFormal : BOOLEAN;
      BEGIN
      RESULT := TRUE;
      END IsFormal;   
      
    REDEFINE METHOD IsAttribute : BOOLEAN;
      BEGIN
      RESULT := FALSE;
      END IsAttribute;

    REDEFINE METHOD Parse(Lkh: LookAhead);
      BEGIN
      ASSERT FALSE;
      END Parse;                                         
      
    -------------------------------------------------------
    -- Matches formal parameters depending on a context
    -------------------------------------------------------
    METHOD Match (Other: Formal; Ctx: ConstrainedClassDecl): BOOLEAN;
      VAR
        OtherType: Type;
      BEGIN
      OtherType := Other.GetType;
      ---------------------------------------
      -- First find the correct type for Other
      -- depending on the context Ctx.
      ---------------------------------------
      IF Ctx <> VOID THEN
        OtherType := OtherType.BuildContextual (Ctx);
        END;   
      IF GetType.Match(OtherType) THEN
        IF Id.Data = Other.Id.Data THEN
          RESULT := TRUE;
         ELSE
          Error('Non matching redefined identifiers: ' +
                             Id.Data + '/' + Other.Id.Data);
          END;
       ELSE
        Error("Non compatible redefined types");
        DEBUG
          VOID := GetType.Match(OtherType);
          END;
        END;
      END Match;

  END Formal;
----------------------------------------
  CLASS FormalList;
    INHERITS DeclList (Formal);
    
    METHOD Match (Meth: MethodDeclaration;
                  Other: FormalList; 
                  Ctx: ConstrainedClassDecl): BOOLEAN;
      BEGIN
      ASSERT Meth.Formals = THIS;
      IF Size = Other.Size THEN             
        RESULT := TRUE;
        FOR i := 0 TO Size - 1 WHILE RESULT DO
          RESULT := Get(i).Match (Other.Get(i), Ctx);
          IF NOT RESULT THEN
            Get(i).Error ("Non matching redefinition");
            END;
          END;
       ELSE
        Meth.Error ("Non matching arity");
        END;
      END Match;
                        
  END FormalList;

END YaflMethods;
