blob: 4233ce81b7eb71886ebf20dc0895e1e57b211bb0 [file] [log] [blame]
------------------------------------------------------------------------------
-- --
-- GNAT COMPILER COMPONENTS --
-- --
-- G E N _ I L . G E N --
-- --
-- S p e c --
-- --
-- Copyright (C) 2020-2022, 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 some exceptions. This means Flags are
-- initialized to False, Node_Ids and List_Ids are initialized to Empty,
-- and enumeration fields are initialized to 'First of the type (assuming
-- there is no representation clause).
--
-- Elists default to No_Elist.
--
-- Fields of type Uint (but not its subtypes) are initialized to No_Uint.
-- Fields of subtypes Valid_Uint, Unat, Upos, Nonzero_Uint, and Ureal have
-- no default; it is an error to call a getter before calling the setter.
-- Likewise, other types whose range does not include zero have no default
-- (see package Types for the ranges).
--
-- If a node is created by a function in Nmake, then the defaults are
-- different from what is specified above. The parameters of Make_...
-- functions can have defaults specified; see Create_Syntactic_Field.
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;