aboutsummaryrefslogtreecommitdiffstats
path: root/src/synth/elab-vhdl_utils.adb
blob: b3b6c1a60dd9f6bd6d81a5dea557c42c0d332f79 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
--  Utils for elaboration.
--  Copyright (C) 2022 Tristan Gingold
--
--  This file is part of GHDL.
--
--  This program is free software: you can redistribute it and/or modify
--  it under the terms of the GNU General Public License as published by
--  the Free Software Foundation, either version 2 of the License, or
--  (at your option) any later version.
--
--  This program 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
--  along with this program.  If not, see <gnu.org/licenses>.

with Types; use Types;
with Vhdl.Utils; use Vhdl.Utils;

package body Elab.Vhdl_Utils is
   function Association_Iterator_Build (Inter_Chain : Node; Assoc_Chain : Node)
                                       return Association_Iterator_Init is
   begin
      return Association_Iterator_Init'(Kind => Association_Function,
                                        Inter_Chain => Inter_Chain,
                                        Assoc_Chain => Assoc_Chain);
   end Association_Iterator_Build;

   function Association_Iterator_Build
     (Inter_Chain : Node; Left : Node; Right : Node)
     return Association_Iterator_Init is
   begin
      return Association_Iterator_Init'(Kind => Association_Operator,
                                        Inter_Chain => Inter_Chain,
                                        Left => Left,
                                        Right => Right);
   end Association_Iterator_Build;

   function Get_Iterator_Inter_Chain (Init : Association_Iterator_Init)
                                     return Node is
   begin
      return Init.Inter_Chain;
   end Get_Iterator_Inter_Chain;

   function Get_Iterator_Assoc_Chain (Init : Association_Iterator_Init)
                                     return Node is
   begin
      return Init.Assoc_Chain;
   end Get_Iterator_Assoc_Chain;

   procedure Association_Iterate_Init (Iterator : out Association_Iterator;
                                       Init : Association_Iterator_Init) is
   begin
      case Init.Kind is
         when Association_Function =>
            Iterator := (Kind => Association_Function,
                         Inter => Init.Inter_Chain,
                         First_Named_Assoc => Null_Node,
                         Assoc => Init.Assoc_Chain);
         when Association_Operator =>
            Iterator := (Kind => Association_Operator,
                         Inter => Init.Inter_Chain,
                         Op1 => Init.Left,
                         Op2 => Init.Right);
      end case;
   end Association_Iterate_Init;

   --  Return the next association.
   --  ASSOC can be:
   --  * an Iir_Kind_Association_By_XXX node (normal case)
   --  * Null_Iir if INTER is not associated (and has a default value).
   --  * an expression (for operator association).
   --  Associations are returned in the order of interfaces.
   procedure Association_Iterate_Next (Iterator : in out Association_Iterator;
                                       Inter : out Node;
                                       Assoc : out Node) is
   begin
      --  Next interface.
      Inter := Iterator.Inter;

      if Inter = Null_Node then
         --  End of iterator.
         Assoc := Null_Node;
         return;
      end if;

      --  Advance to the next interface for the next call.
      Iterator.Inter := Get_Chain (Iterator.Inter);

      case Iterator.Kind is
         when Association_Function =>
            if Iterator.First_Named_Assoc = Null_Node then
               Assoc := Iterator.Assoc;
               --  Still using association by position.
               if Assoc = Null_Node then
                  --  No more associations, all open.
                  return;
               end if;
               if Get_Formal (Assoc) = Null_Node then
                  --  Still by position, update for the next call.
                  Iterator.Assoc := Get_Chain (Assoc);
                  return;
               end if;
               Iterator.First_Named_Assoc := Assoc;
            end if;

            --  Search by name.
            declare
               Formal : Node;
            begin
               Assoc := Iterator.First_Named_Assoc;
               while Assoc /= Null_Node loop
                  Formal := Get_Formal (Assoc);
                  if Formal = Null_Node then
                     pragma Assert (Get_Artificial_Flag (Assoc));
                     Assoc := Null_Node;
                     return;
                  end if;
                  Formal := Get_Interface_Of_Formal (Formal);

                  --  Compare by identifier, as INTER can be the generic
                  --  interface, while FORMAL is the instantiated one.
                  if Get_Identifier (Formal) = Get_Identifier (Inter) then
                     --  Found.
                     --  Optimize in case assocs are in order.
                     if Assoc = Iterator.First_Named_Assoc then
                        Iterator.First_Named_Assoc := Get_Chain (Assoc);
                     end if;
                     return;
                  end if;
                  Assoc := Get_Chain (Assoc);
               end loop;
            end;

            --  Not found: open association.
            return;

         when Association_Operator =>
            Assoc := Iterator.Op1;
            Iterator.Op1 := Iterator.Op2;
            Iterator.Op2 := Null_Node;
      end case;
   end Association_Iterate_Next;

end Elab.Vhdl_Utils;