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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
|
------------------------------------------------------------------------------
-- --
-- GNAT COMPILER COMPONENTS --
-- --
-- G E N _ I L . G E N --
-- --
-- S p e c --
-- --
-- Copyright (C) 2020-2021, Free Software Foundation, Inc. --
-- --
-- GNAT is free software; you can redistribute it and/or modify it under --
-- terms of the GNU General Public License as published by the Free Soft- --
-- ware Foundation; either version 3, or (at your option) any later ver- --
-- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
-- OUT 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 GNAT; see file COPYING3. If not, go to --
-- http://www.gnu.org/licenses for a complete copy of the license. --
-- --
-- GNAT was originally developed by the GNAT team at New York University. --
-- Extensive contributions were provided by Ada Core Technologies Inc. --
-- --
------------------------------------------------------------------------------
-- "Language design is library design and library design is language design".
-- -- Bjarne Stroustrup
-- This package provides a "little language" for defining type hierarchies,
-- which we call "Gen_IL.Gen". In particular, it is used to describe the type
-- hierarchies rooted at Node_Id and Entity_Id in the intermediate language
-- used by GNAT.
-- The type hierarchy is a strict hierarchy (treeish, no multiple
-- inheritance). We have "abstract" and "concrete" types. Each type has a
-- "parent", except for the root type (Node_Id or Entity_Id). All leaf types
-- in the hierarchy are concrete; all nonleaf types (including the two root
-- types) are abstract. One can create instances of concrete, but not
-- abstract, types.
--
-- Descendants of Node_Id/Node_Kind are node types, and descendants of
-- Entity_Id/Entity_Kind are entity types.
--
-- Types have "fields". Each type inherits all the fields from its parent, and
-- may add new ones. A node field can be marked "syntactic"; entity fields are
-- never syntactic. A nonsyntactic field is "semantic".
--
-- If a field is syntactic, then the constructors in Nmake take a parameter to
-- initialize that field. In addition, the tree-traversal routines in Atree
-- (Traverse_Func and Traverse_Proc) traverse syntactic fields that are of
-- type Node_Id (or subtypes of Node_Id) or List_Id. Finally, (with some
-- exceptions documented in the body) the setter for a syntactic node or list
-- field "Set_F (N, Val)" will set the Parent of Val to N, unless Val is Empty
-- or Error[_List].
--
-- Note that the same field can be syntactic in some node types but semantic
-- in other node types. This is an added complexity that we might want to
-- eliminate someday. We shouldn't add any new such cases.
--
-- A "program" written in the Gen_IL.Gen language consists of calls to the
-- "Create_..." routines below, followed by a call to Compile, also below. In
-- order to understand what's going on, you need to look not only at the
-- Gen_IL.Gen "code", but at the output of the compiler -- at least, look at
-- the specs of Sinfo.Nodes and Einfo.Entities, because GNAT invokes those
-- directly. It's not like a normal language where you don't usually have to
-- look at the generated machine code.
--
-- Thus, the Gen_IL.Gen code is really Ada code, and when you run it as an Ada
-- program, it generates the above-mentioned files. The program is somewhat
-- unusual in that it has no input. Everything it needs to generate code is
-- embodied in it.
-- Why don't we just use a variant record, instead of inventing a wheel?
-- Or a hierarchy of tagged types?
--
-- The key feature that Ada's variant records and tagged types lack, and that
-- this little language has, is that if two types have a field with the same
-- name, then those are the same field, even though they weren't inherited
-- from a common ancestor. Such fields are required to have the same type, the
-- same default value, and the same extra precondition.
with Gen_IL.Types; use Gen_IL.Types;
pragma Warnings (Off);
with Gen_IL.Fields; use Gen_IL.Fields; -- for children
pragma Warnings (On);
with Gen_IL.Internals; use Gen_IL.Internals;
use Gen_IL.Internals.Type_Vectors;
use Gen_IL.Internals.Field_Vectors;
package Gen_IL.Gen is
procedure Create_Root_Node_Type
(T : Abstract_Node;
Fields : Field_Sequence := No_Fields)
with Pre => T = Node_Kind;
-- Create the root node type (Node_Kind), which is an abstract type
procedure Create_Abstract_Node_Type
(T : Abstract_Node; Parent : Abstract_Type;
Fields : Field_Sequence := No_Fields);
-- Create an abstract node type (other than the root node type)
procedure Create_Concrete_Node_Type
(T : Concrete_Node; Parent : Abstract_Type;
Fields : Field_Sequence := No_Fields;
Nmake_Assert : String := "");
-- Create a concrete node type. Every node is an instance of a concrete
-- node type. Nmake_Assert is an assertion to put in the Make_... function
-- in the generated Nmake package. It should be a String that represents a
-- Boolean expression.
procedure Create_Root_Entity_Type
(T : Abstract_Entity;
Fields : Field_Sequence := No_Fields)
with Pre => T = Entity_Kind;
-- Create the root entity type (Entity_Kind), which is an abstract type
procedure Create_Abstract_Entity_Type
(T : Abstract_Entity; Parent : Abstract_Type;
Fields : Field_Sequence := No_Fields);
-- Create an abstract entity type (other than the root entity type)
procedure Create_Concrete_Entity_Type
(T : Concrete_Entity; Parent : Abstract_Type;
Fields : Field_Sequence := No_Fields);
-- Create a concrete entity type. Every entity is an instance of a concrete
-- entity type.
function Create_Syntactic_Field
(Field : Node_Field;
Field_Type : Type_Enum;
Default_Value : Field_Default_Value := No_Default;
Pre, Pre_Get, Pre_Set : String := "") return Field_Desc;
-- Create a syntactic field of a node type. Entities do not have syntactic
-- fields.
function Create_Semantic_Field
(Field : Field_Enum;
Field_Type : Type_Enum;
Type_Only : Type_Only_Enum := No_Type_Only;
Pre, Pre_Get, Pre_Set : String := "") return Field_Desc;
-- Create a semantic field of a node or entity type
-- Create_Syntactic_Field is used for syntactic fields of nodes. The order
-- of calls to Create_Syntactic_Field determines the order of the formal
-- parameters of the Make_... functions in Nmake.
--
-- Create_Semantic_Field is used for semantic fields of nodes, and all
-- fields of entities are considered semantic. The order of calls doesn't
-- make any difference.
--
-- Field_Type is the type of the field. Default_Value is the default value
-- for the parameter of the Make_... function in Nmake; this is effective
-- only for syntactic fields. Flag fields of syntactic nodes always have a
-- default value, which is False unless specified as Default_True. Pre is
-- an additional precondition for the field getter and setter, in addition
-- to the precondition that asserts that the type has that field. It should
-- be a String that represents a Boolean expression. Pre_Get and Pre_Set
-- are similar to Pre, but for the getter or setter only, respectively.
--
-- If multiple calls to these occur for the same Field but different types,
-- the Field_Type, Pre, Pre_Get, and Pre_Set must match. Default_Value
-- should match for syntactic fields. See the declaration of Type_Only_Enum
-- for Type_Only.
--
-- (The matching Default_Value requirement is a simplification from the
-- earlier hand-written version.)
-- When adding new node or entity kinds, or adding new fields, all back
-- ends must be made aware of the changes. In addition, the documentation
-- in Sinfo or Einfo needs to be updated.
-- To add a new node or entity type, add it to the enumeration type in
-- Gen_IL.Types, taking care that it is in the approprate range
-- (Abstract_Node, Abstract_Entity, Concrete_Node, or Concrete_Entity).
-- Then add a call to one of the above type-creation procedures to
-- Gen_IL.Gen.Gen_Nodes or Gen_IL.Gen.Gen_Entities.
--
-- To add a new field to a type, add it to the enumeration type in
-- Gen_IL.Fields in the appropriate range. Then add a call to one of
-- the above field-creation procedures to Gen_IL.Gen.Gen_Nodes or
-- Gen_IL.Gen.Gen_Entities.
--
-- If a type or field name does not follow the usual Mixed_Case convention,
-- such as "SPARK_Pragma", then you have to add a special case to one of
-- the Image functions in Gen_IL.Internals and in Treepr.
-- Forward references are not allowed. So if you say:
--
-- Create..._Type (..., Parent => P);
--
-- then Create..._Type must have already been called to create P.
--
-- Likewise, if you say:
--
-- Create..._Field (T, F, Field_Type, ...);
--
-- then Create..._Type must have already been called to create T and
-- (if it's a node or entity type) to create Field_Type.
--
-- To delete a node or entity type, delete it from Gen_IL.Types, update the
-- subranges in Gen_IL.Internals if necessary, and delete all occurrences
-- from Gen_IL.Gen.Gen_Entities. To delete a field, delete it from
-- Gen_IL.Fields, and delete all occurrences from Gen_IL.Gen.Gen_Entities.
-- If a field is not set, it is initialized by default to whatever value is
-- represented by all-zero bits, with two exceptions: Elist fields default
-- to No_Elist, and Uint fields default to Uint_0. In retrospect, it would
-- have been better to use No_Uint instead of Uint_0.
procedure Create_Node_Union_Type
(T : Abstract_Node; Children : Type_Array);
procedure Create_Entity_Union_Type
(T : Abstract_Entity; Children : Type_Array);
-- Create a "union" type that is the union of the Children. This is used
-- for nonhierachical types. This is the opposite of the normal "object
-- oriented" routines above, which create child types based on existing
-- parents. Here we are creating parent types based on existing child
-- types. A union type is considered to be an abstract type because it has
-- multiple children. We do not allow union types to have their own fields,
-- because that would introduce the well-known complexity of multiple
-- inheritance. That restriction could be relaxed, but for now, union types
-- are mainly for allowing things like "Pre => X in Some_Union_Type".
Illegal : exception;
-- Exception raised when Gen_IL code (in particular in Gen_Nodes and
-- Gen_Entities) is illegal. We don't try elaborate error recovery, but
-- hopefully the exception message will indicate what's wrong. You might
-- have to go in the debugger to see which line it's complaining about.
procedure Compile;
private
function Sy
(Field : Node_Field;
Field_Type : Type_Enum;
Default_Value : Field_Default_Value := No_Default;
Pre, Pre_Get, Pre_Set : String := "") return Field_Sequence;
function Sm
(Field : Field_Enum;
Field_Type : Type_Enum;
Type_Only : Type_Only_Enum := No_Type_Only;
Pre, Pre_Get, Pre_Set : String := "") return Field_Sequence;
-- The above functions return Field_Sequence. This is a trick to get around
-- the fact that Ada doesn't allow singleton positional aggregates. It
-- allows us to write things like:
--
-- Cc (N_Empty, Node_Kind,
-- (Sy (Chars, Name_Id, Default_No_Name)));
--
-- where that thing pretending to be an aggregate is really a parenthesized
-- expression. See Gen_Nodes for documentation of the functions these are
-- standing in for.
end Gen_IL.Gen;
|