source: src/AST/SymbolTable.hpp@ 994030ce

Last change on this file since 994030ce was b9fe89b, checked in by Michael Brooks <mlbrooks@…>, 2 years ago

Make the symbol table's error-checking times explicit.

Previously, error checking happened on all WithSymbolTable uses. Error checking means having a symbol-table add operation potentially cause a user-visible error report. Now, this only happens on the resolver pass's symbol table, while other passes' run in an "assert no errors can happen" mode.

An "ignore errors for now" mode is implemented too, which will be used in upcoming commits, for pre-resolver passes that use the symbol table.

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