Skip to content

Commit 6f95874

Browse files
committed
Move Binder out of Parser so that it can be reused during template instantiation
Signed-off-by: Roberto Raggi <[email protected]>
1 parent 53eaeef commit 6f95874

File tree

7 files changed

+587
-429
lines changed

7 files changed

+587
-429
lines changed

src/parser/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ add_library(cxx-parser
2727
cxx/ast_slot.cc
2828
cxx/ast.cc
2929
cxx/base_classes.cc
30+
cxx/binder.cc
3031
cxx/cli.cc
3132
cxx/const_expression_evaluator.cc
3233
cxx/const_value.cc

src/parser/cxx/ast.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2114,6 +2114,7 @@ class ConditionExpressionAST final : public ExpressionAST {
21142114
List<SpecifierAST*>* declSpecifierList = nullptr;
21152115
DeclaratorAST* declarator = nullptr;
21162116
ExpressionAST* initializer = nullptr;
2117+
Symbol* symbol = nullptr;
21172118

21182119
void accept(ASTVisitor* visitor) override { visitor->visit(this); }
21192120

@@ -2368,6 +2369,7 @@ class EnumeratorAST final : public AST {
23682369
SourceLocation equalLoc;
23692370
ExpressionAST* expression = nullptr;
23702371
const Identifier* identifier = nullptr;
2372+
EnumeratorSymbol* symbol = nullptr;
23712373

23722374
void accept(ASTVisitor* visitor) override { visitor->visit(this); }
23732375

src/parser/cxx/binder.cc

Lines changed: 331 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,331 @@
1+
// Copyright (c) 2025 Roberto Raggi <[email protected]>
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a copy
4+
// of this software and associated documentation files (the "Software"), to deal
5+
// in the Software without restriction, including without limitation the rights
6+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
// copies of the Software, and to permit persons to whom the Software is
8+
// furnished to do so, subject to the following conditions:
9+
//
10+
// The above copyright notice and this permission notice shall be included in
11+
// all copies or substantial portions of the Software.
12+
//
13+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19+
// SOFTWARE.
20+
21+
#include <cxx/binder.h>
22+
23+
// cxx
24+
#include <cxx/ast.h>
25+
#include <cxx/control.h>
26+
#include <cxx/decl.h>
27+
#include <cxx/decl_specs.h>
28+
#include <cxx/memory_layout.h>
29+
#include <cxx/names.h>
30+
#include <cxx/scope.h>
31+
#include <cxx/symbols.h>
32+
#include <cxx/translation_unit.h>
33+
#include <cxx/types.h>
34+
35+
#include <format>
36+
37+
namespace cxx {
38+
39+
Binder::Binder(TranslationUnit* unit) : unit_(unit) {}
40+
41+
auto Binder::translationUnit() const -> TranslationUnit* { return unit_; }
42+
43+
void Binder::setTranslationUnit(TranslationUnit* unit) { unit_ = unit; }
44+
45+
auto Binder::control() const -> Control* {
46+
return unit_ ? unit_->control() : nullptr;
47+
}
48+
49+
auto Binder::reportErrors() const -> bool { return reportErrors_; }
50+
51+
void Binder::setReportErrors(bool reportErrors) {
52+
reportErrors_ = reportErrors;
53+
}
54+
55+
void Binder::error(SourceLocation loc, std::string message) {
56+
if (!reportErrors_) return;
57+
unit_->error(loc, std::move(message));
58+
}
59+
60+
void Binder::warning(SourceLocation loc, std::string message) {
61+
if (!reportErrors_) return;
62+
unit_->warning(loc, std::move(message));
63+
}
64+
65+
auto Binder::inTemplate() const -> bool { return inTemplate_; }
66+
67+
auto Binder::currentTemplateParameters() const -> TemplateParametersSymbol* {
68+
auto templateParameters =
69+
symbol_cast<TemplateParametersSymbol>(scope()->owner());
70+
71+
return templateParameters;
72+
}
73+
74+
auto Binder::declaringScope() const -> Scope* {
75+
if (!scope_) return nullptr;
76+
if (!scope_->isTemplateParametersScope()) return scope_;
77+
return scope_->enclosingNonTemplateParametersScope();
78+
}
79+
80+
auto Binder::scope() const -> Scope* { return scope_; }
81+
82+
void Binder::setScope(Scope* scope) {
83+
scope_ = scope;
84+
inTemplate_ = false;
85+
86+
for (auto current = scope_; current; current = current->parent()) {
87+
if (current->isTemplateParametersScope()) {
88+
inTemplate_ = true;
89+
break;
90+
}
91+
}
92+
}
93+
94+
void Binder::setScope(ScopedSymbol* symbol) { setScope(symbol->scope()); }
95+
96+
auto Binder::enterBlock(SourceLocation loc) -> BlockSymbol* {
97+
auto blockSymbol = control()->newBlockSymbol(scope_, loc);
98+
scope_->addSymbol(blockSymbol);
99+
setScope(blockSymbol->scope());
100+
return blockSymbol;
101+
}
102+
103+
void Binder::bind(EnumSpecifierAST* ast, const DeclSpecs& underlyingTypeSpecs) {
104+
const auto underlyingType = underlyingTypeSpecs.getType();
105+
106+
const auto location = ast->unqualifiedId
107+
? ast->unqualifiedId->firstSourceLocation()
108+
: ast->lbraceLoc;
109+
110+
auto enumName = get_name(control(), ast->unqualifiedId);
111+
112+
if (ast->classLoc) {
113+
auto enumSymbol = control()->newScopedEnumSymbol(scope(), location);
114+
ast->symbol = enumSymbol;
115+
116+
enumSymbol->setName(enumName);
117+
enumSymbol->setUnderlyingType(underlyingType);
118+
scope()->addSymbol(enumSymbol);
119+
120+
setScope(enumSymbol);
121+
} else {
122+
auto enumSymbol = control()->newEnumSymbol(scope(), location);
123+
ast->symbol = enumSymbol;
124+
125+
enumSymbol->setName(enumName);
126+
enumSymbol->setUnderlyingType(underlyingType);
127+
scope()->addSymbol(enumSymbol);
128+
129+
setScope(enumSymbol);
130+
}
131+
}
132+
133+
void Binder::bind(ParameterDeclarationAST* ast, const Decl& decl,
134+
bool inTemplateParameters) {
135+
ast->type = getDeclaratorType(unit_, ast->declarator, decl.specs.getType());
136+
137+
if (auto declId = decl.declaratorId; declId && declId->unqualifiedId) {
138+
auto paramName = get_name(control(), declId->unqualifiedId);
139+
if (auto identifier = name_cast<Identifier>(paramName)) {
140+
ast->identifier = identifier;
141+
} else {
142+
error(declId->unqualifiedId->firstSourceLocation(),
143+
"expected an identifier");
144+
}
145+
}
146+
147+
if (!inTemplateParameters) {
148+
auto parameterSymbol =
149+
control()->newParameterSymbol(scope_, decl.location());
150+
parameterSymbol->setName(ast->identifier);
151+
parameterSymbol->setType(ast->type);
152+
scope_->addSymbol(parameterSymbol);
153+
}
154+
}
155+
156+
void Binder::bind(EnumeratorAST* ast, const Type* type,
157+
std::optional<ConstValue> value) {
158+
auto symbol = control()->newEnumeratorSymbol(scope(), ast->identifierLoc);
159+
ast->symbol = symbol;
160+
161+
symbol->setName(ast->identifier);
162+
symbol->setType(type);
163+
ast->symbol->setValue(value);
164+
scope()->addSymbol(symbol);
165+
166+
if (auto enumSymbol = symbol_cast<EnumSymbol>(scope()->owner())) {
167+
auto enumeratorSymbol =
168+
control()->newEnumeratorSymbol(scope(), ast->identifierLoc);
169+
enumeratorSymbol->setName(ast->identifier);
170+
enumeratorSymbol->setType(type);
171+
enumeratorSymbol->setValue(value);
172+
173+
auto parentScope = enumSymbol->enclosingScope();
174+
parentScope->addSymbol(enumeratorSymbol);
175+
}
176+
}
177+
178+
auto Binder::declareTypeAlias(SourceLocation identifierLoc, TypeIdAST* typeId)
179+
-> TypeAliasSymbol* {
180+
auto name = unit_->identifier(identifierLoc);
181+
auto symbol = control()->newTypeAliasSymbol(scope(), identifierLoc);
182+
symbol->setName(name);
183+
if (typeId) symbol->setType(typeId->type);
184+
symbol->setTemplateParameters(currentTemplateParameters());
185+
declaringScope()->addSymbol(symbol);
186+
return symbol;
187+
}
188+
189+
auto Binder::declareTypedef(DeclaratorAST* declarator, const Decl& decl)
190+
-> TypeAliasSymbol* {
191+
auto name = decl.getName();
192+
auto type = getDeclaratorType(unit_, declarator, decl.specs.getType());
193+
auto symbol = control()->newTypeAliasSymbol(scope(), decl.location());
194+
symbol->setName(name);
195+
symbol->setType(type);
196+
scope()->addSymbol(symbol);
197+
return symbol;
198+
}
199+
200+
auto Binder::declareFunction(DeclaratorAST* declarator, const Decl& decl)
201+
-> FunctionSymbol* {
202+
auto name = decl.getName();
203+
auto type = getDeclaratorType(unit_, declarator, decl.specs.getType());
204+
205+
auto parentScope = scope();
206+
207+
if (parentScope->isBlockScope()) {
208+
parentScope = parentScope->enclosingNamespaceScope();
209+
}
210+
211+
auto functionSymbol = control()->newFunctionSymbol(scope(), decl.location());
212+
applySpecifiers(functionSymbol, decl.specs);
213+
functionSymbol->setName(name);
214+
functionSymbol->setType(type);
215+
functionSymbol->setTemplateParameters(currentTemplateParameters());
216+
217+
if (isConstructor(functionSymbol)) {
218+
auto enclosingClass = symbol_cast<ClassSymbol>(scope()->owner());
219+
220+
if (enclosingClass) {
221+
enclosingClass->addConstructor(functionSymbol);
222+
}
223+
224+
return functionSymbol;
225+
}
226+
227+
auto scope = declaringScope();
228+
229+
OverloadSetSymbol* overloadSet = nullptr;
230+
231+
for (Symbol* candidate : scope->find(functionSymbol->name())) {
232+
overloadSet = symbol_cast<OverloadSetSymbol>(candidate);
233+
if (overloadSet) break;
234+
235+
if (auto previousFunction = symbol_cast<FunctionSymbol>(candidate)) {
236+
overloadSet = control()->newOverloadSetSymbol(scope, {});
237+
overloadSet->setName(functionSymbol->name());
238+
overloadSet->addFunction(previousFunction);
239+
scope->replaceSymbol(previousFunction, overloadSet);
240+
break;
241+
}
242+
}
243+
244+
if (overloadSet) {
245+
overloadSet->addFunction(functionSymbol);
246+
} else {
247+
scope->addSymbol(functionSymbol);
248+
}
249+
250+
return functionSymbol;
251+
}
252+
253+
auto Binder::declareField(DeclaratorAST* declarator, const Decl& decl)
254+
-> FieldSymbol* {
255+
auto name = decl.getName();
256+
auto type = getDeclaratorType(unit_, declarator, decl.specs.getType());
257+
auto fieldSymbol = control()->newFieldSymbol(scope(), decl.location());
258+
applySpecifiers(fieldSymbol, decl.specs);
259+
fieldSymbol->setName(name);
260+
fieldSymbol->setType(type);
261+
fieldSymbol->setMutable(decl.specs.isMutable);
262+
if (auto alignment = control()->memoryLayout()->alignmentOf(type)) {
263+
fieldSymbol->setAlignment(alignment.value());
264+
}
265+
scope()->addSymbol(fieldSymbol);
266+
return fieldSymbol;
267+
}
268+
269+
auto Binder::declareVariable(DeclaratorAST* declarator, const Decl& decl)
270+
-> VariableSymbol* {
271+
auto name = decl.getName();
272+
auto symbol = control()->newVariableSymbol(scope(), decl.location());
273+
auto type = getDeclaratorType(unit_, declarator, decl.specs.getType());
274+
applySpecifiers(symbol, decl.specs);
275+
symbol->setName(name);
276+
symbol->setType(type);
277+
symbol->setTemplateParameters(currentTemplateParameters());
278+
declaringScope()->addSymbol(symbol);
279+
return symbol;
280+
}
281+
282+
auto Binder::declareMemberSymbol(DeclaratorAST* declarator, const Decl& decl)
283+
-> Symbol* {
284+
if (decl.specs.isTypedef) return declareTypedef(declarator, decl);
285+
286+
if (getFunctionPrototype(declarator))
287+
return declareFunction(declarator, decl);
288+
289+
return declareField(declarator, decl);
290+
}
291+
292+
void Binder::applySpecifiers(FunctionSymbol* symbol, const DeclSpecs& specs) {
293+
symbol->setStatic(specs.isStatic);
294+
symbol->setExtern(specs.isExtern);
295+
symbol->setFriend(specs.isFriend);
296+
symbol->setConstexpr(specs.isConstexpr);
297+
symbol->setConsteval(specs.isConsteval);
298+
symbol->setInline(specs.isInline);
299+
symbol->setVirtual(specs.isVirtual);
300+
symbol->setExplicit(specs.isExplicit);
301+
}
302+
303+
void Binder::applySpecifiers(VariableSymbol* symbol, const DeclSpecs& specs) {
304+
symbol->setStatic(specs.isStatic);
305+
symbol->setThreadLocal(specs.isThreadLocal);
306+
symbol->setExtern(specs.isExtern);
307+
symbol->setConstexpr(specs.isConstexpr);
308+
symbol->setConstinit(specs.isConstinit);
309+
symbol->setInline(specs.isInline);
310+
}
311+
312+
void Binder::applySpecifiers(FieldSymbol* symbol, const DeclSpecs& specs) {
313+
symbol->setStatic(specs.isStatic);
314+
symbol->setThreadLocal(specs.isThreadLocal);
315+
symbol->setConstexpr(specs.isConstexpr);
316+
symbol->setConstinit(specs.isConstinit);
317+
symbol->setInline(specs.isInline);
318+
}
319+
320+
auto Binder::isConstructor(Symbol* symbol) const -> bool {
321+
auto functionSymbol = symbol_cast<FunctionSymbol>(symbol);
322+
if (!functionSymbol) return false;
323+
if (!functionSymbol->enclosingScope()) return false;
324+
auto classSymbol =
325+
symbol_cast<ClassSymbol>(functionSymbol->enclosingScope()->owner());
326+
if (!classSymbol) return false;
327+
if (classSymbol->name() != functionSymbol->name()) return false;
328+
return true;
329+
}
330+
331+
} // namespace cxx

0 commit comments

Comments
 (0)