IMPLEMENTATION MODULE YaflExpressions;

FROM Conversions           IMPORT IntConversions;
FROM YaflLex               IMPORT LexicalAnalyzer;
FROM YaflPredefined        IMPORT PredefClass, PredefMethod, PredefItems;
FROM YaflIdentifiers       IMPORT QualIdent;
FROM Linked                IMPORT LinkedList, Linkable;
FROM Streams               IMPORT StdOut, StdErr;
FROM YaflModules           IMPORT CompilationUnit;
FROM YaflDeclarations      IMPORT ConstDeclaration, SingleDataItem;
FROM YaflMethods           IMPORT MethodDeclaration;
FROM YaflMetImplementation IMPORT MethodImplementation;
FROM YaflError             IMPORT MainErrorHandler;
FROM YaflLiteral           IMPORT Literal, StringLiteral, BooleanLiteral;
FROM YaflDesignator        IMPORT Desig, DesigElement;

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

  CLASS Expression;
    INHERITS TypedNonTerminal(ExpressionCodeGenerator);
    VAR
      TheFirstExpr: TypedNonTerminal;
      TheRelation: INTEGER;
      TheSecondExpr: TypedNonTerminal;

    REDEFINE METHOD SubTree: ARRAY OF NonTerminal;
      BEGIN
      IF TheSecondExpr = VOID THEN
        RESULT.CREATE(1);
       ELSE
        RESULT.CREATE(2);
        RESULT[1] := TheSecondExpr;
        END;
      RESULT[0] := TheFirstExpr;
      END SubTree;

    REDEFINE METHOD Parse(Lkh: LookAhead);
      BEGIN
      END Parse;
      
    METHOD FirstExpr: TypedNonTerminal;
      BEGIN
      RESULT:= TheFirstExpr;
      END FirstExpr;

    METHOD Relation: INTEGER;
      BEGIN
      RESULT:= TheRelation;
      END Relation;

    METHOD SecondExpr: TypedNonTerminal;
      BEGIN
      RESULT:= TheSecondExpr;
      END SecondExpr;

    METHOD Set (Left: TypedNonTerminal;
                Op: INTEGER;
                Right: TypedNonTerminal);
      BEGIN
      TheFirstExpr := Left;
      TheRelation := Op;
      TheSecondExpr := Right;
      SetSon (Left);
      SetSon (Right);
      END Set;

--    REDEFINE METHOD IsNoChange: BOOLEAN;
--      BEGIN
--      WHAT THIS OF
--        IS Expression:
--          END;
--      ELSE
--        Warning("IsNoChange not redefined for (" + WhatAmI + ")");
--        END;
--      IF FirstExpr <> VOID THEN
--        RESULT := FirstExpr.IsNoChange;
--      ELSE
--        RESULT := TRUE;
--        END;
--      IF RESULT AND (SecondExpr <> VOID) THEN
--        RESULT := RESULT AND SecondExpr.IsNoChange;
--        END;
--      END IsNoChange;
--
--    REDEFINE METHOD IsNoChangeHC: BOOLEAN;
--      BEGIN
--      WHAT THIS OF
--        IS Expression:
--          END;
--      ELSE
--        Warning("IsNoChangeHC not redefined for (" + WhatAmI + ")");
--        END;
--      RESULT := IsNoChange;
--      IF NOT RESULT THEN
--        IF FirstExpr <> VOID THEN
--          RESULT := FirstExpr.IsNoChangeHC;
--          END;
--        IF RESULT AND (SecondExpr <> VOID) THEN
--          RESULT := RESULT AND SecondExpr.IsNoChangeHC;
--          END;
--        END;
--      END IsNoChangeHC;
--
--    REDEFINE METHOD IsChange: BOOLEAN;
--      BEGIN
--      WHAT THIS OF
--        IS Expression:
--          END;
--      ELSE
--        Warning("IsChange not redefined for (" + WhatAmI + ")");
--        END;
--      IF FirstExpr <> VOID THEN
--        RESULT := FirstExpr.IsChange;
--        END;
--      IF (NOT RESULT) AND (SecondExpr <> VOID) THEN
--        RESULT := SecondExpr.IsChange;
--        END;
--      END IsChange;
--
--    REDEFINE METHOD CallChangeMeth: BOOLEAN;
--      BEGIN
--      WHAT THIS OF
--        IS Expression:
--          END;
--      ELSE
--        Warning("CallChangeMeth not redefined for (" + WhatAmI + ")");
--        END;
--      IF FirstExpr <> VOID THEN
--        RESULT := FirstExpr.CallChangeMeth;
--        END;
--      IF (NOT RESULT) AND (SecondExpr <> VOID) THEN
--        RESULT := SecondExpr.CallChangeMeth;
--        END;
--      END CallChangeMeth;

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

    REDEFINE METHOD Tag;
      BEGIN
      IF TheFirstExpr <> VOID THEN
        TheFirstExpr.UniqueTag;
        END;
      IF TheSecondExpr <> VOID THEN
        TheSecondExpr.UniqueTag;
        END;
      END Tag;

    REDEFINE METHOD WithSideEffects: BOOLEAN;
      BEGIN
      IF TheFirstExpr <> VOID THEN
        RESULT := TheFirstExpr.WithSideEffects;
        END;
      IF (NOT RESULT) AND (TheSecondExpr <> VOID) THEN
        RESULT := TheSecondExpr.WithSideEffects;
        END;
      END WithSideEffects;

    REDEFINE METHOD BuildType: Type;
      VAR
        LeftContext, RightContext: Type;
      BEGIN
      LeftContext := TheFirstExpr.GetType;
      RESULT := LeftContext;
      IF LeftContext = VOID THEN
        Error ('Left expression has a VOID context');
       ELSE
        IF TheSecondExpr <> VOID THEN
          RightContext := TheSecondExpr.GetType;
          IF RightContext = VOID THEN
            Error ('Right expression has a VOID context');
           ELSE
            --------------------------------------------
            -- We use a separate method for each of
            -- the operators. Each of these method will
            -- also take care of constant folding.
            --------------------------------------------
            CASE TheRelation OF
              LexicalAnalyzer.Plus:
                RESULT := BuildPlusType (TheFirstExpr, TheSecondExpr);
                END;
              LexicalAnalyzer.Mod:
                RESULT := BuildModType (TheFirstExpr, TheSecondExpr);
                END;
              LexicalAnalyzer.Star,
              LexicalAnalyzer.Minus,
              LexicalAnalyzer.Slash:
                RESULT := BuildOperatorType (TheFirstExpr, TheRelation,
                                             TheSecondExpr);
                END;
              LexicalAnalyzer.Iff,
              LexicalAnalyzer.Implies,
              LexicalAnalyzer.And,
              LexicalAnalyzer.Or:
                RESULT := BuildAndOrType (TheFirstExpr, TheRelation,
                                          TheSecondExpr);
                END;
              LexicalAnalyzer.Equal,
              LexicalAnalyzer.NonEqual:
                RESULT := BuildEqualType (TheFirstExpr.Optimized,
                                          TheRelation,
                                          TheSecondExpr.Optimized);
                END;
              LexicalAnalyzer.Greater,
              LexicalAnalyzer.SmallerEqual,
              LexicalAnalyzer.Smaller,
              LexicalAnalyzer.GreaterEqual:
                RESULT := BuildCompareType (TheFirstExpr.Optimized,
                                            TheRelation,
                                            TheSecondExpr.Optimized);
                END;
              END; -- End Case
            END;
         ELSE    -- second expression is VOID
          CASE TheRelation OF
            LexicalAnalyzer.Minus:
              RESULT := BuildNegativeType (TheFirstExpr);
              END;
            LexicalAnalyzer.Not:
              RESULT := BuildNotType (TheFirstExpr);
              END;
            END;
          END;
        END;
      END BuildType;

    METHOD BuildPlusType (LeftExpr, RightExpr: TypedNonTerminal): Type;
      VAR
        LeftContext: Type;
        LeftFolded, RightFolded: Literal;
      BEGIN
      LeftContext := LeftExpr.GetType;
      LeftFolded := LeftExpr.GetFolded;
      RightFolded := RightExpr.GetFolded;
      IF NOT RightExpr.ExprMatch (LeftContext) THEN
        Error ('Type mismatch [1]');
       ELSIF LeftContext.ArrayLevel = 0 THEN
        IF (LeftContext.SimpleType <> PredefItems.Integer) AND
           (LeftContext.SimpleType <> PredefItems.Real) THEN
          Error ("Type mismatch [2]");
         ELSE
          RESULT := LeftContext;
          END;
       ELSE
        ------------------------------
        -- Adding arrays: always Ok.
        ------------------------------
        RESULT := LeftContext;
        END;
      IF (LeftFolded <> VOID) AND (RightFolded <> VOID) THEN
        SetFolded (LeftFolded.Fold(LexicalAnalyzer.Plus,
                            RightFolded));
        END;
      END BuildPlusType;

    METHOD BuildOperatorType (LeftExpr: TypedNonTerminal;
                               Op: INTEGER;
                               RightExpr: TypedNonTerminal): Type;
      VAR
        LeftContext: Type;
        LeftFolded, RightFolded: Literal;
        Fl: BOOLEAN;
      BEGIN
      LeftContext := LeftExpr.GetType;
      LeftFolded := LeftExpr.GetFolded;
      RightFolded := RightExpr.GetFolded;
      IF NOT RightExpr.ExprMatch (LeftContext) THEN
        Error ('Type mismatch [3]');
       ELSIF (LeftContext.ArrayLevel <> 0) OR
          ((LeftContext.SimpleType <> PredefItems.Integer) AND
          (LeftContext.SimpleType <> PredefItems.Real)) THEN
        Error ("Type mismatch [4]");
       ELSE
        RESULT := LeftContext;
        IF (LeftFolded <> VOID) AND (RightFolded <> VOID) THEN
          SetFolded (LeftFolded.Fold(Op, RightFolded));
 	   END;
        END;
      END BuildOperatorType;

    METHOD BuildModType (LeftExpr, RightExpr: TypedNonTerminal): Type;
      VAR
        LeftContext: Type;
        LeftFolded, RightFolded: Literal;
      BEGIN
      LeftContext := LeftExpr.GetType;
      LeftFolded := LeftExpr.GetFolded;
      RightFolded := RightExpr.GetFolded;
      IF NOT RightExpr.ExprMatch (LeftContext) THEN
        Error ('Type mismatch [93]');
       ELSIF (LeftContext.ArrayLevel <> 0) OR
          (LeftContext.SimpleType <> PredefItems.Integer) THEN
        Error ("Type mismatch [94]");
       ELSE
        RESULT := LeftContext;
        END;
      IF (LeftFolded <> VOID) AND (RightFolded <> VOID) THEN
        SetFolded (LeftFolded.Fold(LexicalAnalyzer.Mod, RightFolded));
        END;
      END BuildModType;

    METHOD BuildAndOrType (LeftExpr: TypedNonTerminal;
                           Op: INTEGER;
                           RightExpr: TypedNonTerminal): Type;
      VAR
        LeftContext: Type;
        LeftFolded, RightFolded: Literal;
        Fl: BOOLEAN;
      BEGIN
      LeftContext := LeftExpr.GetType;
      LeftFolded := LeftExpr.GetFolded;
      RightFolded := RightExpr.GetFolded;
      IF NOT LeftExpr.ExprMatch (PredefItems.Boolean.MakeType(0)) OR
         NOT RightExpr.ExprMatch (PredefItems.Boolean.MakeType(0)) THEN
        Error ('Type mismatch [9]');
       ELSE
        RESULT := LeftContext;
        END;
      IF (LeftFolded <> VOID) THEN
        IF (RightFolded <> VOID) THEN
          SetFolded (LeftFolded.Fold(Op, RightFolded));
         ELSE
          WHAT LeftFolded OF
            IN BooleanLiteral:
              Fl := TAG.Value;
              END;
            END;
          CASE Op OF
            LexicalAnalyzer.Implies:
              IF NOT Fl THEN
                SetFolded (PredefItems.True);
                END;
              END;
            LexicalAnalyzer.And:
              IF NOT Fl THEN
                SetFolded (PredefItems.False);
                END;
              END;
              
            LexicalAnalyzer.Or:
              IF Fl THEN
                SetFolded (PredefItems.True);
                END;
              END;
              
           ELSE
            END; -- Case
          END;
        END;
      END BuildAndOrType;
      
    METHOD BuildEqualType (LeftExpr: TypedNonTerminal;
                           Op: INTEGER;
                           RightExpr: TypedNonTerminal): Type;
      VAR
        LeftContext, RightContext: Type;
        LeftFolded, RightFolded: Literal;
      BEGIN
      LeftContext := LeftExpr.GetType;
      RightContext := RightExpr.GetType;
      LeftFolded := LeftExpr.GetFolded;
      RightFolded := RightExpr.GetFolded;
      --------------------------------------------
      -- If Both expressions are string constants,
      -- try to match them to single chars
      --------------------------------------------
      IF LeftContext.Match (PredefItems.Char.MakeType(1)) AND
         RightContext.Match (PredefItems.Char.MakeType(1)) AND
         (LeftFolded <> VOID) AND (RightFolded <> VOID) THEN
        VOID := LeftExpr.ExprMatch (PredefItems.Char.MakeType(0));
        VOID := RightExpr.ExprMatch (PredefItems.Char.MakeType(0));
        LeftContext := LeftExpr.GetType;
        RightContext := RightExpr.GetType;
        END;
      IF NOT RightExpr.ExprCompatible (LeftContext) AND
         NOT LeftExpr.ExprCompatible (RightContext) THEN
        Error ('Type mismatch [11]');
       ELSIF LeftContext.Match (PredefItems.Boolean.MakeType(0)) THEN
        Error ('Booleans cannot be tested for equality. Use IFF instead');
       ELSE
        RESULT := PredefItems.Boolean.MakeType(0);
        END;
      IF (LeftFolded <> VOID) AND (RightFolded <> VOID) THEN
        SetFolded (LeftFolded.Fold(Op, RightFolded));
        END;
      END BuildEqualType;

    METHOD BuildCompareType (LeftExpr: TypedNonTerminal;
                             Op: INTEGER;
                             RightExpr: TypedNonTerminal): Type;
      VAR
        LeftContext, RightContext: Type;
        LeftFolded, RightFolded: Literal;
      BEGIN
      LeftContext := LeftExpr.GetType;
      RightContext := RightExpr.GetType;
      LeftFolded := LeftExpr.GetFolded;
      RightFolded := RightExpr.GetFolded;
      --------------------------------------------
      -- If Both expressions are string constants,
      -- try to match them to single chars
      --------------------------------------------
      IF LeftContext.Match (PredefItems.Char.MakeType(1)) AND
         RightContext.Match (PredefItems.Char.MakeType(1)) AND
         (LeftFolded <> VOID) AND (RightFolded <> VOID) THEN
        VOID := LeftExpr.ExprMatch (PredefItems.Char.MakeType(0));
        VOID := RightExpr.ExprMatch (PredefItems.Char.MakeType(0));
        LeftContext := LeftExpr.GetType;
        RightContext := RightExpr.GetType;
        END;
      IF NOT RightExpr.ExprMatch (LeftContext) THEN
        Error ('Type mismatch [13]');
       ELSIF LeftContext.ArrayLevel = 0 THEN
        IF (LeftContext.SimpleType <> PredefItems.Integer) AND
           (LeftContext.SimpleType <> PredefItems.Real) AND
           (LeftContext.SimpleType <> PredefItems.Char) THEN
          Error ("Type mismatch [14]");
         ELSE
          RESULT := PredefItems.Boolean.MakeType(0);
          END;
       ELSE
        Error ("Cannot compare arrays");
        END;
      IF (LeftFolded <> VOID) AND (RightFolded <> VOID) THEN
        SetFolded (LeftFolded.Fold(Op, RightFolded));
        END;
      END BuildCompareType;

    METHOD BuildNegativeType (LeftExpr: TypedNonTerminal): Type;
      VAR
        LeftContext: Type;
        LeftFolded: Literal;
      BEGIN
      LeftContext := LeftExpr.GetType;
      LeftFolded := LeftExpr.GetFolded;
      IF ((LeftContext.SimpleType <> PredefItems.Integer) AND
         (LeftContext.SimpleType <> PredefItems.Real)) OR
         (LeftContext.ArrayLevel <> 0) THEN
        Error ("Type mismatch [23]");
       ELSE
        RESULT := LeftContext;
        END;
      IF LeftFolded <> VOID THEN
        SetFolded (LeftFolded.Fold(LexicalAnalyzer.Minus, VOID));
        END;
      END BuildNegativeType;

    METHOD BuildNotType (LeftExpr: TypedNonTerminal): Type;
      VAR
        LeftContext: Type;
        LeftFolded: Literal;
      BEGIN
      LeftContext := LeftExpr.GetType;
      LeftFolded := LeftExpr.GetFolded;
      IF (LeftContext.SimpleType <> PredefItems.Boolean) OR
         (LeftContext.ArrayLevel <> 0) THEN
        Error ("Type mismatch [24]");
       ELSE
        RESULT := LeftContext;
        END;
      IF LeftFolded <> VOID THEN
        SetFolded (LeftFolded.Fold(LexicalAnalyzer.Not, VOID));
        END;
      END BuildNotType;
------------------------------------------      
    REDEFINE METHOD GrabConcat: ARRAY OF TypedNonTerminal;
      BEGIN
      IF (GetFolded = VOID) AND (TheFirstExpr.GetType.ArrayLevel <> 0) THEN
        RESULT :=  TheFirstExpr.GrabConcat + TheSecondExpr.GrabConcat;
       ELSE
        RESULT := BASE;
        END;
      END GrabConcat;
------------------------------------------      
      
    REDEFINE METHOD Isomorph (Other: TypedNonTerminal): BOOLEAN;
    
        METHOD CheckSubExpression (One, Two: TypedNonTerminal): BOOLEAN;
          BEGIN
          IF One = VOID THEN
            RESULT := Two = VOID;
           ELSIF Two <> VOID THEN
            RESULT := One.Isomorph(Two);
            END;
          END CheckSubExpression;
    
      BEGIN        
      WHAT Other OF
        IN Expression:
          IF TheRelation = TAG.TheRelation THEN
            RESULT := CheckSubExpression (TheFirstExpr, TAG.TheFirstExpr) AND
                      CheckSubExpression (TheSecondExpr, TAG.TheSecondExpr);
            END;
          END;
       ELSE
        -- Don't abort, of course.
        END;
      END Isomorph;
      

    METHOD IsArithmeticOperator: BOOLEAN;
      BEGIN
      CASE TheRelation OF
        LexicalAnalyzer.Plus, 
        LexicalAnalyzer.Minus, 
        LexicalAnalyzer.Star,
        LexicalAnalyzer.Mod, 
        LexicalAnalyzer.Slash:
          RESULT := TRUE;
          END;
       ELSE
        -- Else, return implicit FALSE.
        END;
      END IsArithmeticOperator;  
      
    REDEFINE METHOD UsesValueStack: BOOLEAN;
      BEGIN
      RESULT := TheFirstExpr.UsesValueStack OR 
                ((TheSecondExpr <> VOID) AND (TheSecondExpr.UsesValueStack));
      IF NOT RESULT AND (TheFirstExpr <> VOID) 
                    AND (TheSecondExpr <> VOID) THEN
        IF TheRelation = LexicalAnalyzer.Plus THEN
          RESULT := TheFirstExpr.GetType.ArrayLevel > 0;
          END;
        END;                      
      END UsesValueStack;

    REDEFINE METHOD Functional: BOOLEAN;
      --POST
      --  RESULT IMPLIES TheFirstExpr.Functional,
      --  RESULT IMPLIES (TheSecondExpr <> VOID) 
      --                 IMPLIES TheSecondExpr.Functional;
      BEGIN
      RESULT := TheFirstExpr.Functional;
      IF RESULT AND (TheSecondExpr <> VOID) THEN
        RESULT := TheSecondExpr.Functional;
	END;
      END Functional;

  END Expression;

 
----------------------------------------
  CLASS Actual;
    INHERITS NonTerminal(ActualCodeGenerator);
    VAR
      TheId: Ident;
      TheExpr: TypedNonTerminal;
      
    -- XXJC (d)
      TheContext: INTEGER;

    REDEFINE METHOD CREATE (LineNr, ColNr, Context: INTEGER);
      BEGIN
      BASE(LineNr, ColNr);
      TheContext := Context;
      END CREATE;
    -- END XXJC (d)  
    
    METHOD RequiresTempSaving: BOOLEAN;
      BEGIN                  
      RESULT := TheExpr.RequiresTempSaving;
      END RequiresTempSaving;

    REDEFINE METHOD SubTree: ARRAY OF NonTerminal;
      BEGIN
      IF TheId = VOID THEN
        RESULT.CREATE(1);
       ELSE
        RESULT.CREATE(2);
        RESULT[1] := TheId;
        END;
      RESULT[0] := TheExpr;
      END SubTree;

    REDEFINE METHOD Parse(Lkh: LookAhead);
      VAR
        Sub: ARRAY OF NonTerminal;
        Next: NonTerminal;
        GoOn: BOOLEAN;
        i: INTEGER;
      BEGIN
      TheId := VOID;
      -- XXJC (d)
      --TheExpr := Lkh.AcceptPlainExpr;
      TheExpr := Lkh.AcceptExpression(TheContext);
      -- END XXJC (d)
      SetSon (TheExpr);
      IF Lkh.CurrentToken = LexicalAnalyzer.Becomes THEN
        Lkh.GetToken;
        GoOn := TRUE;
        Sub := TheExpr.SubTree;
        WHILE GoOn AND (Sub <> VOID) DO
          Next := VOID;
          i := 0;
          WHILE GoOn AND (i < Sub.SIZE) DO
            IF Sub[i] <> VOID THEN
              IF Next = VOID THEN
                Next := Sub [i];
               ELSE
                GoOn := FALSE;
                END;
              END;
            i := i + 1;
            END;
          IF GoOn AND (Next <> VOID) THEN
            WHAT Next OF
              IN Ident:
                TheId := TAG;
                SetSon (TheId);
                GoOn := FALSE;
                END;
             ELSE
              Sub := Next.SubTree;
              END;
           ELSE
            GoOn := FALSE;
            END;
          END;
        DEBUG
          IF Sub = VOID THEN
            Lkh.Error ("Void Sub Tree Before Ident");
           ELSIF TheId = VOID THEN
            Lkh.Error ("Wrong size of Sub Tree");
            END;
          END;
        IF TheId = VOID THEN
          Error ("Syntax error in named parameters");
          END;
        TheExpr := Lkh.AcceptPlainExpr;
        SetSon (TheExpr);
        END;
      END Parse;

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

    METHOD Expr: TypedNonTerminal;
      BEGIN
      RESULT := TheExpr;
      END Expr;
    
    -- this method was added for sqlyafl    
    METHOD SetExpr(Exp: TypedNonTerminal);
      BEGIN
      TheExpr := Exp;
      END SetExpr;
        
    REDEFINE METHOD WhatAmI: ARRAY OF CHAR;
      BEGIN
      RESULT := "Actual";
      END WhatAmI;

    REDEFINE METHOD Tag;
      BEGIN
      TheExpr.UniqueTag;
      END Tag;

    -----------------------------------------------------------
    -- Check if one Actual parameter matches its Formal parameter
    -----------------------------------------------------------
    METHOD Match (Formal: SingleDataItem; 
                  FormalType: Type): BOOLEAN;
      VAR
        TempExpr: TypedNonTerminal;
        a, b: ARRAY OF CHAR;                  
      BEGIN
      IF (TheId <> VOID) AND (TheId.Data <> Formal.Id.Data) THEN
        Error ("Mismatch in parameters names");
       ELSE
        TempExpr := TheExpr.Optimized;
        IF NOT TempExpr.ExprCompatible (FormalType) THEN
          IF TempExpr.GetType <> VOID THEN
            a := TempExpr.GetType.Image;
           ELSE
            a := "<Actual type undefined>";
            END;
          IF FormalType <> VOID THEN
            b := FormalType.Image;
           ELSE
            b := "<Formal type undefined>";
            END;
          TheExpr.Error ("Type mismatch in parameters (" + 
                          a + '/' + b + ")");
          DEBUG
            VOID := TempExpr.ExprCompatible (FormalType);
            END;
         ELSE
          RESULT := TRUE;
          END; 
        END;
      END Match;
                                 
    -----------------------------  
    -- Matches THIS with the formal id provided
    -- THIS must be simple, that is
    --   * no () or []
    --   * only a single DesigElement
    -----------------------------
    METHOD SimpleMatch (Formal : SingleDataItem): BOOLEAN;
      VAR                             
        DesEl : DesigElement;
      BEGIN       
      WHAT TheExpr.Optimized OF
        IN Desig:
          IF (TAG.Size = 1) THEN
            DesEl := TAG.First;
            END;
          END;
        IN DesigElement:
          DesEl := TAG;
          END;
       ELSE
        -- Don't abord        
        END;      
        IF (DesEl <> VOID) THEN
          IF (DesEl.Actuals = VOID) AND (DesEl.BrExpr = VOID) THEN
            RESULT := (DesEl.Id.Data = Formal.Id.Data);
            END;
          END;
      END SimpleMatch;
      
  END Actual;
----------------------------------------
  CLASS TypedNTList(Element IN NonTerminal);
    INHERITS NTList (Element);
    
    METHOD CheckIntegers (Number: INTEGER): BOOLEAN;
      VAR
        TheType: Type;
        Expr: TypedNonTerminal;
      BEGIN
      IF Size <> Number THEN
        Father.Error ("Wrong number of parameters");
       ELSE
        RESULT := TRUE;
        FOR i := 0 TO Number - 1 WHILE RESULT DO
          Expr := GetExpression (i);
          IF Expr <> VOID THEN
            TheType := Expr.GetType;
            IF (TheType = VOID) OR
              (TheType.SimpleType <> PredefItems.Integer) OR
              (TheType.ArrayLevel <> 0) THEN
              Father.Error ("Type mismatch");
              RESULT := FALSE;
              END;
            END;
          END;
        END;
      END CheckIntegers;
      
    METHOD CheckAllIntegers: BOOLEAN;
      BEGIN
      RESULT := CheckIntegers (Size);
      END CheckAllIntegers;
      
    METHOD WithSideEffects: BOOLEAN;             
      BEGIN
      FOR i := 0 TO Size - 1 WHILE NOT RESULT DO
        RESULT := GetExpression(i).WithSideEffects;
        END;
      END WithSideEffects;
      
    METHOD Isomorph (Other: TypedNTList(Element)): BOOLEAN;
      BEGIN
      RESULT := TRUE;
      FOR i := 0 TO Size - 1 WHILE RESULT DO
        RESULT := GetExpression(i).Isomorph (Other.GetExpression(i));
        END;
      END Isomorph;
      
    METHOD UsesValueStack: BOOLEAN;
      BEGIN
      FOR i := 0 TO Size - 1 WHILE NOT RESULT DO
        RESULT := GetExpression(i).UsesValueStack;
        END;
      END UsesValueStack;
      
  END TypedNTList;
----------------------------------------
  CLASS ActualList;
    INHERITS TypedNTList (Actual);
    
    REDEFINE METHOD GetExpression(i: INTEGER): TypedNonTerminal;
      VAR
        Act: Actual;
      BEGIN
      Act := Get(i);
      IF Act <> VOID THEN
        RESULT := Act.Expr;
        END;
      END GetExpression;
      
    ------------------------------------------------
    -- Check if all the Actual parameters match the 
    -- corresponding Formal parameters.
    -------------------------------------------------
    METHOD Match (TheFormals: FormalList; 
                  Context: ConstrainedClassDecl): BOOLEAN;
      VAR
        CurActual: Actual;
        CurFormal: Formal;
        TheType: Type;     
      BEGIN
      IF Size <> TheFormals.Size THEN
        Error ("Arity error (" + 
              IntConversions.IntToString(Size, 0) + "/" +
              IntConversions.IntToString(TheFormals.Size, 0) + ")");
       ELSE
        RESULT := TRUE;
        FOR i := 0 TO Size - 1 WHILE TRUE DO
          CurActual := Get(i);
          CurFormal := TheFormals.Get(i);
          TheType := CurFormal.GetType.BuildContextual (Context);
          ---------------------------------------------
          -- Check the conformity of a single parameter
          ---------------------------------------------

          RESULT := CurActual.Match(CurFormal, TheType);
          END;
        END;
      END Match;
           
    ---------------------------
    -- Checks if all Actuals are simple, that is
    --   * no () nor []
    --   * only a single DesigElement
    -- and their ids correspond to the formal ones
    -- and there is no more formals than actuals
    ---------------------------    
    METHOD SimpleMatch(TheFormals : FormalList): BOOLEAN;
      VAR
        TheFormal : SingleDataItem;
        TheActual : Actual;
      BEGIN                                          
      RESULT := (TheFormals<>VOID) AND (TheFormals.Size=Size);  
                                                  -- !!! THIS is <> VOID
      FOR i := 0 TO TheFormals.Size - 1 WHILE RESULT DO
        TheFormal := TheFormals.Get(i);
        TheActual := Get(i);
        RESULT := TheActual.SimpleMatch(TheFormal);
        END;           
      END SimpleMatch;

    METHOD RequiresTempSaving: BOOLEAN;
      BEGIN
      FOR i := 0 TO Size - 1 WHILE NOT RESULT DO
        RESULT := Get(i).RequiresTempSaving;
        END;
      END RequiresTempSaving;
      
  END ActualList;
----------------------------------------
  CLASS ExpressionList;
    INHERITS TypedNTList (TypedNonTerminal);
    
    REDEFINE METHOD GetExpression(i: INTEGER): TypedNonTerminal;
      BEGIN
      RESULT := Get(i);
      END GetExpression;    
    
  END ExpressionList;
      
END YaflExpressions;
