* [Ada] Support for reverse iteration on formal containers
@ 2017-10-09 20:37 Pierre-Marie de Rodat
0 siblings, 0 replies; only message in thread
From: Pierre-Marie de Rodat @ 2017-10-09 20:37 UTC (permalink / raw)
To: gcc-patches; +Cc: Ed Schonberg
[-- Attachment #1: Type: text/plain, Size: 2070 bytes --]
This patch adds support for reverse iterations over formal containers,
analogous to what is supported on arrays and predefined containers.
Executing:
gnatmake -q foo
foo
must yield;
1 2 3 4 5 6 7 8 9 10
10 9 8 7 6 5 4 3 2 1
10 9 8 7 6 5 4 3 2 1
---
with Ada.Text_IO; use Ada.Text_IO;
procedure Foo is
type Int_Range is record
First, Last : Integer;
end record
with Iterable => (First => First,
Next => Next,
Previous => Previous,
Last => Last,
Has_Element => Has_Element,
Element => Element);
function First (IR : Int_Range) return Integer is (IR.First);
function Last (IR : Int_Range) return Integer is (IR.Last);
function Next (IR : Int_Range; N : Integer) return Integer is (N + 1);
function Previous (IR : Int_Range; N : Integer) return Integer is (N - 1);
function Has_Element (IR : Int_Range; N : Integer) return Boolean is
(N in IR.First ..IR.Last);
function Element (IR : Int_Range; N : Integer) return Integer is (N);
IR : Int_Range := (1, 10);
begin
for I of IR loop
Put (I'Img);
end loop;
New_Line;
for I in reverse IR loop
Put (I'Img);
end loop;
New_Line;
for I of reverse IR loop
Put (I'Img);
end loop;
end Foo;
Tested on x86_64-pc-linux-gnu, committed on trunk
2017-10-09 Ed Schonberg <schonberg@adacore.com>
* sem_ch5.adb (Analyze_Iterator_Specification,
Check_Reverse_Iteration): Check that the domain of iteration supports
reverse iteration when it is a formal container. This requires the
presence of a Previous primitive in the Iterable aspect.
* sem_ch13.adb (Resolve_Iterable_Operation): Verify legality of
primitives Last and Previous to support reverse iteration over formal
containers.
(Validate_Iterable_Aspect): Add check for reverse iteration operations.
* exp_ch5.adb (Build_Formal_Container_Iteration): Add proper expansion
for reverse iteration using primitives Last and Previous in generated
loop.
[-- Attachment #2: difs --]
[-- Type: text/plain, Size: 5707 bytes --]
Index: exp_ch5.adb
===================================================================
--- exp_ch5.adb (revision 253566)
+++ exp_ch5.adb (working copy)
@@ -178,14 +178,27 @@
Loc : constant Source_Ptr := Sloc (N);
Stats : constant List_Id := Statements (N);
Typ : constant Entity_Id := Base_Type (Etype (Container));
- First_Op : constant Entity_Id :=
- Get_Iterable_Type_Primitive (Typ, Name_First);
- Next_Op : constant Entity_Id :=
- Get_Iterable_Type_Primitive (Typ, Name_Next);
+ First_Op : Entity_Id;
+ Next_Op : Entity_Id;
+
Has_Element_Op : constant Entity_Id :=
Get_Iterable_Type_Primitive (Typ, Name_Has_Element);
begin
+ -- Use the proper set of primitives depending on the direction of
+ -- iteration. The legality of a reverse iteration has been checked
+ -- during analysis.
+
+ if Reverse_Present (Iterator_Specification (Iteration_Scheme (N))) then
+ First_Op := Get_Iterable_Type_Primitive (Typ, Name_Last);
+ Next_Op := Get_Iterable_Type_Primitive (Typ, Name_Previous);
+
+ else
+ First_Op := Get_Iterable_Type_Primitive (Typ, Name_First);
+ Next_Op := Get_Iterable_Type_Primitive (Typ, Name_Next);
+ null;
+ end if;
+
-- Declaration for Cursor
Init :=
@@ -198,7 +211,7 @@
Parameter_Associations => New_List (
Convert_To_Iterable_Type (Container, Loc))));
- -- Statement that advances cursor in loop
+ -- Statement that advances (in the right direction) cursor in loop
Advance :=
Make_Assignment_Statement (Loc,
Index: sem_ch13.adb
===================================================================
--- sem_ch13.adb (revision 253563)
+++ sem_ch13.adb (working copy)
@@ -13200,10 +13200,13 @@
Ent := Entity (N);
F1 := First_Formal (Ent);
- if Nam = Name_First then
- -- First (Container) => Cursor
+ if Nam = Name_First
+ or else Nam = Name_Last
+ then
+ -- First or Last (Container) => Cursor
+
if Etype (Ent) /= Cursor then
Error_Msg_N ("primitive for First must yield a curosr", N);
end if;
@@ -13221,6 +13224,19 @@
Error_Msg_N ("no match for Next iterable primitive", N);
end if;
+ elsif Nam = Name_Previous then
+
+ -- Previous (Container, Cursor) => Cursor
+
+ F2 := Next_Formal (F1);
+
+ if Etype (F2) /= Cursor
+ or else Etype (Ent) /= Cursor
+ or else Present (Next_Formal (F2))
+ then
+ Error_Msg_N ("no match for Previous iterable primitive", N);
+ end if;
+
elsif Nam = Name_Has_Element then
-- Has_Element (Container, Cursor) => Boolean
@@ -14022,6 +14038,7 @@
Cursor : constant Entity_Id := Get_Cursor_Type (ASN, Typ);
First_Id : Entity_Id;
+ Last_Id : Entity_Id;
Next_Id : Entity_Id;
Has_Element_Id : Entity_Id;
Element_Id : Entity_Id;
@@ -14034,6 +14051,7 @@
end if;
First_Id := Empty;
+ Last_Id := Empty;
Next_Id := Empty;
Has_Element_Id := Empty;
Element_Id := Empty;
@@ -14054,6 +14072,14 @@
Resolve_Iterable_Operation (Expr, Cursor, Typ, Name_First);
First_Id := Entity (Expr);
+ elsif Chars (Prim) = Name_Last then
+ Resolve_Iterable_Operation (Expr, Cursor, Typ, Name_Last);
+ Last_Id := Entity (Expr);
+
+ elsif Chars (Prim) = Name_Previous then
+ Resolve_Iterable_Operation (Expr, Cursor, Typ, Name_Previous);
+ Last_Id := Entity (Expr);
+
elsif Chars (Prim) = Name_Next then
Resolve_Iterable_Operation (Expr, Cursor, Typ, Name_Next);
Next_Id := Entity (Expr);
@@ -14082,7 +14108,9 @@
elsif No (Has_Element_Id) then
Error_Msg_N ("match for Has_Element primitive not found", ASN);
- elsif No (Element_Id) then
+ elsif No (Element_Id)
+ or else No (Last_Id)
+ then
null; -- Optional.
end if;
end Validate_Iterable_Aspect;
Index: sem_ch5.adb
===================================================================
--- sem_ch5.adb (revision 253559)
+++ sem_ch5.adb (working copy)
@@ -1937,12 +1937,19 @@
procedure Check_Reverse_Iteration (Typ : Entity_Id) is
begin
- if Reverse_Present (N)
- and then not Is_Array_Type (Typ)
- and then not Is_Reversible_Iterator (Typ)
- then
- Error_Msg_NE
- ("container type does not support reverse iteration", N, Typ);
+ if Reverse_Present (N) then
+ if Is_Array_Type (Typ)
+ or else Is_Reversible_Iterator (Typ)
+ or else
+ (Present (Find_Aspect (Typ, Aspect_Iterable))
+ and then Present
+ (Get_Iterable_Type_Primitive (Typ, Name_Previous)))
+ then
+ null;
+ else
+ Error_Msg_NE
+ ("container type does not support reverse iteration", N, Typ);
+ end if;
end if;
end Check_Reverse_Iteration;
@@ -2303,6 +2310,7 @@
("missing Element primitive for iteration", N);
else
Set_Etype (Def_Id, Etype (Elt));
+ Check_Reverse_Iteration (Typ);
end if;
end;
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2017-10-09 20:37 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-10-09 20:37 [Ada] Support for reverse iteration on formal containers Pierre-Marie de Rodat
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).