source: src/AST/SymbolTable.hpp @ c141c09

Last change on this file since c141c09 was 85855b0, checked in by JiadaL <j82liang@…>, 5 months ago
  1. Implement enum cast; 2. Change valueE so that opague enum returns quasi_void; 3. change enum hiding interpretation and pass visiting scheme
  • Property mode set to 100644
File size: 11.1 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// SymbolTable.hpp --
8//
9// Author           : Aaron B. Moss
10// Created On       : Wed May 29 11:00:00 2019
11// Last Modified By : Aaron B. Moss
12// Last Modified On : Wed May 29 11:00:00 2019
13// Update Count     : 1
14//
15
16#pragma once
17
18#include <memory>                  // for shared_ptr, enable_shared_from_this
19#include <vector>
20
21#include "Fwd.hpp"
22#include "Node.hpp"                // for ptr, readonly
23#include "Common/CodeLocation.hpp"
24#include "Common/PersistentMap.hpp"
25
26namespace ResolvExpr {
27        class Cost;
28}
29
30namespace ast {
31
32/// Builds and stores the symbol table, mapping identifiers to declarations.
33class SymbolTable final : public std::enable_shared_from_this<ast::SymbolTable> {
34public:
35        /// special functions stored in dedicated tables, with different lookup keys
36        enum SpecialFunctionKind {CTOR, DTOR, ASSIGN, NUMBER_OF_KINDS};
37        static SpecialFunctionKind getSpecialFunctionKind(const std::string & name);
38
39        /// Stored information about a declaration
40        struct IdData {
41                readonly<DeclWithType> id = nullptr;  ///< Identifier of declaration
42                readonly<Expr> baseExpr = nullptr;    ///< Implied containing aggregate (from WithExpr)
43                readonly<Decl> deleter = nullptr;     ///< Node deleting this declaration (if non-null)
44                unsigned long scope = 0;              ///< Scope of identifier
45
46                IdData() = default;
47                IdData( const DeclWithType * i, const Expr * base, const Decl * del, unsigned long s )
48                : id( i ), baseExpr( base ), deleter( del ), scope( s ) {}
49
50                /// Create a new IdData, updating the deleter value.
51                IdData withDeleter( const Decl * decl ) const {
52                        return IdData( id, baseExpr, decl, scope );
53                }
54
55                /// Constructs an expression referring to this identifier.
56                /// Increments `cost` by cost of reference conversion
57                Expr * combine( const CodeLocation & loc, ResolvExpr::Cost & cost ) const;
58        };
59
60private:
61        /// wraps a reference to D with a scope
62        template<typename D>
63        struct scoped {
64                readonly<D> decl;     ///< wrapped declaration
65                unsigned long scope;  ///< scope of this declaration
66
67                scoped(const D * d, unsigned long s) : decl(d), scope(s) {}
68        };
69
70        using MangleTable = PersistentMap< std::string, IdData >;
71        using IdTable = PersistentMap< std::string, MangleTable::Ptr >;
72        using TypeTable = PersistentMap< std::string, scoped<NamedTypeDecl> >;
73        using StructTable = PersistentMap< std::string, scoped<StructDecl> >;
74        using EnumTable = PersistentMap< std::string, scoped<EnumDecl> >;
75        using UnionTable = PersistentMap< std::string, scoped<UnionDecl> >;
76        using TraitTable = PersistentMap< std::string, scoped<TraitDecl> >;
77
78        IdTable::Ptr idTable;          ///< identifier namespace
79        TypeTable::Ptr typeTable;      ///< type namespace
80        StructTable::Ptr structTable;  ///< struct namespace
81        EnumTable::Ptr enumTable;      ///< enum namespace
82        UnionTable::Ptr unionTable;    ///< union namespace
83        TraitTable::Ptr traitTable;    ///< trait namespace
84        IdTable::Ptr specialFunctionTable[NUMBER_OF_KINDS];
85
86        // using SpecialFuncTable = PersistentMap< std::string, IdTable::Ptr >; // fname (ctor/dtor/assign) - otypekey
87        // SpecialFuncTable::Ptr specialFuncTable;
88
89        using Ptr = std::shared_ptr<const SymbolTable>;
90
91        Ptr prevScope;                 ///< Symbol Table for parent scope
92        unsigned long scope;           ///< Scope index of this indexer
93        unsigned long repScope;        ///< Scope index of currently represented scope
94
95public:
96
97        /// Mode to control when (during which pass) user-caused name-declaration errors get reported.
98        /// The default setting `AssertClean` supports, "I expect all user-caused errors to have been
99        /// reported by now," or, "I wouldn't know what to do with an error; are there even any here?"
100        enum ErrorDetection {
101                AssertClean,               ///< invalid user decls => assert fails during addFoo (default)
102                ValidateOnAdd,             ///< invalid user decls => calls SemanticError during addFoo
103                IgnoreErrors               ///< acts as if unspecified decls were removed, forcing validity
104        };
105
106        explicit SymbolTable(
107                ErrorDetection             ///< mode for the lifetime of the symbol table (whole pass)
108        );
109        SymbolTable() : SymbolTable(AssertClean) {}
110        ~SymbolTable();
111
112        ErrorDetection getErrorMode() const {
113                return errorMode;
114        }
115
116        // when using an indexer manually (e.g., within a mutator traversal), it is necessary to
117        // tell the indexer explicitly when scopes begin and end
118        void enterScope();
119        void leaveScope();
120
121        /// Gets all declarations with the given ID
122        std::vector<IdData> lookupId( const std::string &id ) const;
123        /// Gets all declarations with the given ID, ignoring hidden members from enumeration
124        std::vector<IdData> lookupIdIgnoreHidden( const std::string &id ) const;
125        /// Gets special functions associated with a type; if no key is given, returns everything
126        std::vector<IdData> specialLookupId( SpecialFunctionKind kind, const std::string & otypeKey = "" ) const;
127        /// Gets the top-most type declaration with the given ID
128        const NamedTypeDecl * lookupType( const std::string &id ) const;
129        /// Gets the top-most struct declaration with the given ID
130        const StructDecl * lookupStruct( const std::string &id ) const;
131        /// Gets the top-most enum declaration with the given ID
132        const EnumDecl * lookupEnum( const std::string &id ) const;
133        /// Gets the top-most union declaration with the given ID
134        const UnionDecl * lookupUnion( const std::string &id ) const;
135        /// Gets the top-most trait declaration with the given ID
136        const TraitDecl * lookupTrait( const std::string &id ) const;
137
138        /// Gets the type declaration with the given ID at global scope
139        const NamedTypeDecl * globalLookupType( const std::string &id ) const;
140        /// Gets the struct declaration with the given ID at global scope
141        const StructDecl * globalLookupStruct( const std::string &id ) const;
142        /// Gets the union declaration with the given ID at global scope
143        const UnionDecl * globalLookupUnion( const std::string &id ) const;
144        /// Gets the enum declaration with the given ID at global scope
145        const EnumDecl * globalLookupEnum( const std::string &id ) const;
146
147        /// Adds an identifier declaration to the symbol table
148        void addId( const DeclWithType * decl, const Expr * baseExpr = nullptr );
149        /// Adds a deleted identifier declaration to the symbol table
150        void addDeletedId( const DeclWithType * decl, const Decl * deleter );
151
152        /// Adds a type to the symbol table
153        void addType( const NamedTypeDecl * decl );
154        /// Adds a struct declaration to the symbol table by name
155        void addStructId( const std::string & id );
156        /// Adds a struct declaration to the symbol table
157        void addStruct( const StructDecl * decl );
158        /// Adds an enum declaration to the symbol table
159        void addEnum( const EnumDecl * decl );
160        /// Adds a union declaration to the symbol table by name
161        void addUnionId( const std::string & id );
162        /// Adds a union declaration to the symbol table
163        void addUnion( const UnionDecl * decl );
164        /// Adds a trait declaration to the symbol table
165        void addTrait( const TraitDecl * decl );
166
167        /// adds all of the IDs from WithStmt exprs
168        void addWith( const std::vector< ptr<Expr> > & withExprs, const Decl * withStmt );
169
170        /// convenience function for adding a list of Ids to the indexer
171        void addIds( const std::vector< ptr<DeclWithType> > & decls );
172
173        /// convenience function for adding a list of forall parameters to the indexer
174        void addTypes( const std::vector< ptr<TypeDecl> > & tds );
175
176        /// convenience function for adding all of the declarations in a function type to the indexer
177        void addFunction( const FunctionDecl * );
178
179private:
180        void OnFindError( CodeLocation location, std::string error ) const;
181
182        template< typename T >
183        void OnFindError( const T * obj, const std::string & error ) const {
184                OnFindError( obj->location, toString( error, obj ) );
185        }
186
187        template< typename T >
188        void OnFindError( CodeLocation location, const T * obj, const std::string & error ) const {
189                OnFindError( location, toString( error, obj ) );
190        }
191
192        /// Ensures that a proper backtracking scope exists before a mutation
193        void lazyInitScope();
194
195        /// Gets the symbol table at a given scope
196        const SymbolTable * atScope( unsigned long i ) const;
197
198        /// Removes matching autogenerated constructors and destructors so that they will not be
199        /// selected. If returns false, passed decl should not be added.
200        bool removeSpecialOverrides( IdData & decl, MangleTable::Ptr & mangleTable );
201
202        /// Error detection mode given at construction (pass-specific).
203        /// Logically const, except that the symbol table's push-pop is achieved by autogenerated
204        /// assignment onto self.  The feield is left motuable to keep this code-gen simple.
205        /// Conceptual constness is preserved by all SymbolTable in a stack sharing the same mode.
206        ErrorDetection errorMode;
207
208        /// Options for handling identifier conflicts.
209        /// Varies according to AST location during traversal: captures semantics of the construct
210        /// being visited as "would shadow" vs "must not collide."
211        /// At a given AST location, is the same for every pass.
212        struct OnConflict {
213                enum {
214                        Error,  ///< Follow the current pass's ErrorDetection mode (may throw a semantic error)
215                        Delete  ///< Delete the earlier version with the delete statement
216                } mode;
217                const Decl * deleter;  ///< Statement that deletes this expression
218
219        private:
220                OnConflict() : mode(Error), deleter(nullptr) {}
221                OnConflict( const Decl * d ) : mode(Delete), deleter(d) {}
222        public:
223                OnConflict( const OnConflict& ) = default;
224
225                static OnConflict error() { return {}; }
226                static OnConflict deleteWith( const Decl * d ) { return { d }; }
227        };
228
229        /// true if the existing identifier conflicts with the added identifier
230        bool addedIdConflicts(
231                const IdData & existing, const DeclWithType * added, OnConflict handleConflicts,
232                const Decl * deleter );
233
234        /// true if redeclaration conflict between two types
235        bool addedTypeConflicts( const NamedTypeDecl * existing, const NamedTypeDecl * added ) const;
236
237        /// true if redeclaration conflict between two aggregate declarations
238        bool addedDeclConflicts( const AggregateDecl * existing, const AggregateDecl * added ) const;
239
240        /// common code for addId, addDeletedId, etc.
241        void addIdCommon(
242                const DeclWithType * decl, OnConflict handleConflicts,
243                const Expr * baseExpr = nullptr, const Decl * deleter = nullptr );
244
245        /// common code for addId when special decls are placed into separate tables
246        void addIdToTable(
247                const DeclWithType * decl, const std::string & lookupKey,
248                IdTable::Ptr & idTable, OnConflict handleConflicts,
249                const Expr * baseExpr = nullptr, const Decl * deleter = nullptr);
250
251        /// adds all of the members of the Aggregate (addWith helper)
252        void addMembers( const AggregateDecl * aggr, const Expr * expr, OnConflict handleConflicts );
253
254        /// returns true if there exists a declaration with C linkage and the given name with the same mangled name
255        bool hasCompatibleCDecl( const std::string &id, const std::string &mangleName ) const;
256        /// returns true if there exists a declaration with C linkage and the given name with a different mangled name
257        bool hasIncompatibleCDecl( const std::string &id, const std::string &mangleName ) const;
258};
259
260}
261
262
263// Local Variables: //
264// tab-width: 4 //
265// mode: c++ //
266// compile-command: "make install" //
267// End: //
Note: See TracBrowser for help on using the repository browser.