-------------------------------------------------------------------------------
-- (C) Altran Praxis Limited
-------------------------------------------------------------------------------
--
-- The SPARK toolset is free software; you can redistribute it and/or modify it
-- under terms of the GNU General Public License as published by the Free
-- Software Foundation; either version 3, or (at your option) any later
-- version. The SPARK toolset is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
-- Public License for more details. You should have received a copy of the GNU
-- General Public License distributed with the SPARK toolset; see file
-- COPYING3. If not, go to http://www.gnu.org/licenses for a complete copy of
-- the license.
--
--=============================================================================

separate (Sem.Walk_Expression_P.Walk_Annotation_Expression)
procedure Down_Wf_Quantifier
  (Node      : in     STree.SyntaxNode;
   E_Stack   : in out Exp_Stack.Exp_Stack_Type;
   Scope     : in out Dictionary.Scopes;
   Next_Node :    out STree.SyntaxNode)
is
   Ident_Node, Type_Node    : STree.SyntaxNode;
   Quantifier_Sym, Type_Sym : Dictionary.Symbol;
   Ident_Str                : LexTokenManager.Lex_String;
begin
   Ident_Node := STree.Next_Sibling (Current_Node => STree.Child_Node (Current_Node => Node));
   -- ASSUME Ident_Node = identifier
   SystemErrors.RT_Assert
     (C       => STree.Syntax_Node_Type (Node => Ident_Node) = SP_Symbols.identifier,
      Sys_Err => SystemErrors.Invalid_Syntax_Tree,
      Msg     => "Expect Ident_Node = identifier in Down_Wf_Quantifier");
   Ident_Str := STree.Node_Lex_String (Node => Ident_Node);

   Type_Node := STree.Next_Sibling (Current_Node => Ident_Node);
   -- ASSUME Type_Node = type_mark
   SystemErrors.RT_Assert
     (C       => STree.Syntax_Node_Type (Node => Type_Node) = SP_Symbols.type_mark,
      Sys_Err => SystemErrors.Invalid_Syntax_Tree,
      Msg     => "Expect Type_Node = type_mark in Down_Wf_Quantifier");

   -- continue tree walk from next node after the type mark; this is either the range
   -- or the predicate
   Next_Node := STree.Next_Sibling (Current_Node => Type_Node);
   -- ASSUME Next_Node = annotation_arange OR predicate
   SystemErrors.RT_Assert
     (C       => STree.Syntax_Node_Type (Node => Next_Node) = SP_Symbols.annotation_arange
        or else STree.Syntax_Node_Type (Node => Next_Node) = SP_Symbols.predicate,
      Sys_Err => SystemErrors.Invalid_Syntax_Tree,
      Msg     => "Expect Next_Node = annotation_arange OR predicate in Down_Wf_Quantifier");

   -- check type declared and scalar
   Sem.Wf_Type_Mark (Node          => Type_Node,
                     Current_Scope => Scope,
                     Context       => Dictionary.ProofContext,
                     Type_Sym      => Type_Sym);
   if not Dictionary.TypeIsScalar (Type_Sym) then
      ErrorHandler.Semantic_Error
        (Err_Num   => 44,
         Reference => ErrorHandler.No_Reference,
         Position  => STree.Node_Position (Node => Type_Node),
         Id_Str    => LexTokenManager.Null_String);
      Type_Sym := Dictionary.GetUnknownTypeMark;
   end if;

   -- check quantified variable is not already declared
   if Dictionary.IsDefined
     (Name              => Ident_Str,
      Scope             => Scope,
      Context           => Dictionary.ProofContext,
      Full_Package_Name => False) then
      Next_Node := STree.NullNode; -- prune walk to prevent error knock on
      Exp_Stack.Push (X     => Sem.Unknown_Type_Record,
                      Stack => E_Stack); -- result of whole Q.E. is unknown
      ErrorHandler.Semantic_Error
        (Err_Num   => 10,
         Reference => ErrorHandler.No_Reference,
         Position  => STree.Node_Position (Node => Ident_Node),
         Id_Str    => Ident_Str);
   else
      Dictionary.AddQuantifiedVariable
        (Name          => Ident_Str,
         Comp_Unit     => ContextManager.Ops.Current_Unit,
         Declaration   => Dictionary.Location'(Start_Position => STree.Node_Position (Node => Ident_Node),
                                               End_Position   => STree.Node_Position (Node => Ident_Node)),
         TypeMark      => Type_Sym,
         TheConstraint => Dictionary.NullSymbol,
         Region        => Dictionary.GetRegion (Scope),
         Variable      => Quantifier_Sym);

      -- plant quantifier symbol for recovery and use by VCG
      STree.Add_Node_Symbol (Node => Ident_Node,
                             Sym  => Quantifier_Sym);

      -- enter local scope of quantifier
      Scope := Dictionary.Set_Visibility (The_Visibility => Dictionary.Local,
                                          The_Unit       => Quantifier_Sym);
   end if;
end Down_Wf_Quantifier;
