[multiple changes]
[gcc.git] / gcc / ada / exp_ch5.adb
index 6694fdfbfd4b3881ac45c8a4dd2f1fa6679acb3b..48e6238fac7d8f9d88bcf8e072a9df2a9d73c21a 100644 (file)
@@ -103,6 +103,10 @@ package body Exp_Ch5 is
    --  clause (this last case is required because holes in the tagged type
    --  might be filled with components from child types).
 
+   procedure Expand_Iterator_Loop (N : Node_Id);
+   --  Expand loops over arrays and containers that use the form "for X of C"
+   --  with an optional subtype mark, and "for Y in C".
+
    function Make_Tag_Ctrl_Assignment (N : Node_Id) return List_Id;
    --  Generate the necessary code for controlled and tagged assignment, that
    --  is to say, finalization of the target before, adjustment of the target
@@ -2747,6 +2751,201 @@ package body Exp_Ch5 is
       end if;
    end Expand_N_If_Statement;
 
+   --------------------------
+   -- Expand_Iterator_Loop --
+   --------------------------
+
+   procedure Expand_Iterator_Loop (N : Node_Id) is
+      Loc        : constant Source_Ptr := Sloc (N);
+      Isc        : constant Node_Id    := Iteration_Scheme (N);
+      I_Spec     : constant Node_Id    := Iterator_Specification (Isc);
+      Id         : constant Entity_Id  := Defining_Identifier (I_Spec);
+      Container  : constant Entity_Id :=  Entity (Name (I_Spec));
+
+      Typ        : constant Entity_Id := Etype (Container);
+
+      Cursor     : Entity_Id;
+      New_Loop   : Node_Id;
+      Stats      : List_Id;
+
+   begin
+      if Is_Array_Type (Typ) then
+         if Of_Present (I_Spec) then
+            Cursor := Make_Temporary (Loc, 'C');
+
+            --  For Elem of Arr loop ..
+
+            declare
+               Decl : constant Node_Id :=
+                        Make_Object_Renaming_Declaration (Loc,
+                          Defining_Identifier => Id,
+                          Subtype_Mark =>
+                            New_Occurrence_Of (Component_Type (Typ), Loc),
+                          Name => Make_Indexed_Component (Loc,
+                            Prefix => New_Occurrence_Of (Container, Loc),
+                            Expressions =>
+                              New_List (New_Occurrence_Of (Cursor, Loc))));
+            begin
+               Stats := Statements (N);
+               Prepend (Decl, Stats);
+
+               New_Loop := Make_Loop_Statement (Loc,
+                 Iteration_Scheme =>
+                   Make_Iteration_Scheme (Loc,
+                     Loop_Parameter_Specification =>
+                       Make_Loop_Parameter_Specification (Loc,
+                         Defining_Identifier => Cursor,
+                         Discrete_Subtype_Definition =>
+                            Make_Attribute_Reference (Loc,
+                              Prefix => New_Occurrence_Of (Container, Loc),
+                              Attribute_Name => Name_Range),
+                         Reverse_Present => Reverse_Present (I_Spec))),
+                 Statements => Stats,
+                 End_Label => Empty);
+            end;
+
+         else
+
+            --  For Index in Array loop
+            --
+            --  The cursor (index into the array) is the source Id.
+
+            Cursor := Id;
+            New_Loop := Make_Loop_Statement (Loc,
+              Iteration_Scheme =>
+                Make_Iteration_Scheme (Loc,
+                  Loop_Parameter_Specification =>
+                    Make_Loop_Parameter_Specification (Loc,
+                      Defining_Identifier => Cursor,
+                      Discrete_Subtype_Definition =>
+                         Make_Attribute_Reference (Loc,
+                           Prefix => New_Occurrence_Of (Container, Loc),
+                           Attribute_Name => Name_Range),
+                      Reverse_Present => Reverse_Present (I_Spec))),
+              Statements => Statements (N),
+              End_Label => Empty);
+         end if;
+
+      else
+
+         --  Iterators over containers. In both cases these require a
+         --  cursor of the proper type.
+
+         --  Cursor : P.Cursor_Type := Container.First;
+         --  while Cursor /= P.No_Element loop
+
+         --     --  for the "of" form, the element name renames
+         --     --  the element denoted by the cursor.
+
+         --     Obj : P.Element_Type renames Element (Cursor);
+         --     Statements;
+         --     P.Next (Cursor);
+         --  end loop;
+         --
+         --  with the obvious replacements if "reverse" is specified.
+
+         declare
+            Element_Type  : constant Entity_Id := Etype (Id);
+            Pack          : constant Entity_Id := Scope (Etype (Container));
+
+            Name_Init     : Name_Id;
+            Name_Step     : Name_Id;
+
+            Cond          : Node_Id;
+            Cursor_Decl   : Node_Id;
+            Renaming_Decl : Node_Id;
+
+         begin
+            Stats := Statements (N);
+
+            if Of_Present (I_Spec) then
+               Cursor := Make_Temporary (Loc, 'C');
+
+            else
+               Cursor := Id;
+            end if;
+
+            if Reverse_Present (I_Spec) then
+
+               --  Must verify that the container has a reverse iterator ???
+
+               Name_Init := Name_Last;
+               Name_Step := Name_Previous;
+
+            else
+               Name_Init := Name_First;
+               Name_Step := Name_Next;
+            end if;
+
+            --  C : Cursor_Type := Container.First;
+
+            Cursor_Decl := Make_Object_Declaration (Loc,
+              Defining_Identifier => Cursor,
+              Object_Definition =>
+                Make_Selected_Component (Loc,
+                  Prefix => New_Occurrence_Of (Pack, Loc),
+                  Selector_Name =>
+                    Make_Identifier (Loc, Name_Cursor)),
+              Expression =>
+                Make_Selected_Component (Loc,
+                  Prefix => New_Occurrence_Of (Container, Loc),
+                  Selector_Name => Make_Identifier (Loc, Name_Init)));
+
+            Insert_Action (N, Cursor_Decl);
+
+            --  while C /= No_Element loop
+
+            Cond := Make_Op_Ne (Loc,
+              Left_Opnd => New_Occurrence_Of (Cursor, Loc),
+              Right_Opnd => Make_Selected_Component (Loc,
+                 Prefix => New_Occurrence_Of (Pack, Loc),
+                 Selector_Name => Make_Identifier (Loc,
+                   Chars => Name_No_Element)));
+
+            if Of_Present (I_Spec) then
+
+               --  Id : Element_Type renames Pack.Element (Cursor);
+
+               Renaming_Decl :=
+                 Make_Object_Renaming_Declaration (Loc,
+                   Defining_Identifier => Id,
+                   Subtype_Mark => New_Occurrence_Of (Element_Type, Loc),
+                   Name => Make_Indexed_Component (Loc,
+                     Prefix =>
+                     Make_Selected_Component (Loc,
+                       Prefix =>  New_Occurrence_Of (Pack, Loc),
+                       Selector_Name =>
+                         Make_Identifier (Loc, Chars => Name_Element)),
+                     Expressions =>
+                       New_List (New_Occurrence_Of (Cursor, Loc))));
+
+               Prepend (Renaming_Decl, Stats);
+            end if;
+
+            --  For both iterator forms, add call to Next to advance cursor.
+
+            Append_To (Stats,
+              Make_Procedure_Call_Statement (Loc,
+                Name => Make_Selected_Component (Loc,
+                  Prefix => New_Occurrence_Of (Pack, Loc),
+                  Selector_Name => Make_Identifier (Loc, Name_Step)),
+                Parameter_Associations =>
+                  New_List (New_Occurrence_Of (Cursor, Loc))));
+
+            New_Loop := Make_Loop_Statement (Loc,
+              Iteration_Scheme =>
+                Make_Iteration_Scheme (Loc,
+                  Condition => Cond),
+              Statements => Stats,
+              End_Label => Empty);
+         end;
+      end if;
+
+      --  Set_Analyzed (I_Spec);
+      Rewrite (N, New_Loop);
+      Analyze (N);
+   end Expand_Iterator_Loop;
+
    -----------------------------
    -- Expand_N_Loop_Statement --
    -----------------------------
@@ -2755,7 +2954,8 @@ package body Exp_Ch5 is
    --  2. Deal with while condition for C/Fortran boolean
    --  3. Deal with loops with a non-standard enumeration type range
    --  4. Deal with while loops where Condition_Actions is set
-   --  5. Insert polling call if required
+   --  5. Deal with loops with iterators over arrays and containers
+   --  6. Insert polling call if required
 
    procedure Expand_N_Loop_Statement (N : Node_Id) is
       Loc  : constant Source_Ptr := Sloc (N);
@@ -2955,6 +3155,11 @@ package body Exp_Ch5 is
 
             Analyze (N);
          end;
+
+      elsif Present (Isc)
+        and then Present (Iterator_Specification (Isc))
+      then
+         Expand_Iterator_Loop (N);
       end if;
    end Expand_N_Loop_Statement;