Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 127 additions & 0 deletions src/parser/cxx/binder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,128 @@ void Binder::bind(EnumSpecifierAST* ast, const DeclSpecs& underlyingTypeSpecs) {
}
}

void Binder::bind(ElaboratedTypeSpecifierAST* ast, DeclSpecs& declSpecs) {
auto className = get_name(control(), ast->unqualifiedId);
const auto location = ast->unqualifiedId->firstSourceLocation();

const auto _ = ScopeGuard{this};

if (ast->nestedNameSpecifier) {
auto parent = ast->nestedNameSpecifier->symbol;

if (parent && parent->isClassOrNamespace()) {
setScope(static_cast<ScopedSymbol*>(parent));
}
}

ClassSymbol* classSymbol = nullptr;

if (scope()->isClassOrNamespaceScope()) {
for (auto candidate : scope()->find(className) | views::classes) {
classSymbol = candidate;
break;
}
}

if (!classSymbol) {
const auto isUnion = ast->classKey == TokenKind::T_UNION;
classSymbol = control()->newClassSymbol(scope(), location);

classSymbol->setIsUnion(isUnion);
classSymbol->setName(className);
classSymbol->setTemplateParameters(currentTemplateParameters());
declaringScope()->addSymbol(classSymbol);
}

ast->symbol = classSymbol;

declSpecs.type = ast->symbol->type();
declSpecs.setTypeSpecifier(ast);
}

void Binder::bind(ClassSpecifierAST* ast, DeclSpecs& declSpecs) {
auto templateParameters = currentTemplateParameters();

if (ast->nestedNameSpecifier) {
auto parent = ast->nestedNameSpecifier->symbol;

if (parent && parent->isClassOrNamespace()) {
setScope(static_cast<ScopedSymbol*>(parent));
}
}

auto className = get_name(control(), ast->unqualifiedId);
auto templateId = ast_cast<SimpleTemplateIdAST>(ast->unqualifiedId);

auto location = ast->classLoc;
if (templateId) {
location = templateId->identifierLoc;
} else if (ast->unqualifiedId) {
location = ast->unqualifiedId->firstSourceLocation();
}

ClassSymbol* primaryTemplate = nullptr;

if (templateId && scope()->isTemplateParametersScope()) {
for (auto candidate : declaringScope()->find(className) | views::classes) {
primaryTemplate = candidate;
break;
}

if (!primaryTemplate) {
error(location, std::format("specialization of undeclared template '{}'",
templateId->identifier->name()));
}
}

ClassSymbol* classSymbol = nullptr;

if (className) {
for (auto candidate : declaringScope()->find(className) | views::classes) {
classSymbol = candidate;
break;
}
}

if (classSymbol && classSymbol->isComplete()) {
classSymbol = nullptr;
}

if (!classSymbol) {
const auto isUnion = ast->classKey == TokenKind::T_UNION;
classSymbol = control()->newClassSymbol(scope(), location);
classSymbol->setIsUnion(isUnion);
classSymbol->setName(className);
classSymbol->setTemplateParameters(templateParameters);

if (!primaryTemplate) {
declaringScope()->addSymbol(classSymbol);
} else {
std::vector<TemplateArgument> arguments;
// TODO: parse template arguments
primaryTemplate->addSpecialization(arguments, classSymbol);
}
}

classSymbol->setFinal(ast->isFinal);

ast->symbol = classSymbol;

declSpecs.setTypeSpecifier(ast);
declSpecs.type = classSymbol->type();
}

void Binder::complete(ClassSpecifierAST* ast) {
if (!inTemplate()) {
auto status = ast->symbol->buildClassLayout(control());
if (!status.has_value()) {
error(ast->symbol->location(), status.error());
}
}

ast->symbol->setComplete(true);
}

void Binder::bind(ParameterDeclarationAST* ast, const Decl& decl,
bool inTemplateParameters) {
ast->type = getDeclaratorType(unit_, ast->declarator, decl.specs.getType());
Expand Down Expand Up @@ -334,6 +456,11 @@ void Binder::complete(LambdaExpressionAST* ast) {
parentScope->addSymbol(ast->symbol);
}

void Binder::bind(ParameterDeclarationClauseAST* ast) {
ast->functionParametersSymbol =
control()->newFunctionParametersSymbol(scope(), {});
}

auto Binder::declareTypedef(DeclaratorAST* declarator, const Decl& decl)
-> TypeAliasSymbol* {
auto name = decl.getName();
Expand Down
8 changes: 8 additions & 0 deletions src/parser/cxx/binder.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@ class Binder {

void bind(EnumSpecifierAST* ast, const DeclSpecs& underlyingTypeSpec);

void bind(ElaboratedTypeSpecifierAST* ast, DeclSpecs& declSpecs);

void bind(ClassSpecifierAST* ast, DeclSpecs& declSpecs);

void complete(ClassSpecifierAST* ast);

void bind(EnumeratorAST* ast, const Type* type,
std::optional<ConstValue> value);

Expand All @@ -111,6 +117,8 @@ class Binder {

void complete(LambdaExpressionAST* ast);

void bind(ParameterDeclarationClauseAST* ast);

class ScopeGuard {
public:
Binder* p = nullptr;
Expand Down
142 changes: 14 additions & 128 deletions src/parser/cxx/parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5363,39 +5363,7 @@ auto Parser::parse_elaborated_type_specifier(
className = nameId->identifier;
}

const auto location = ast->unqualifiedId->firstSourceLocation();

const auto _ = Binder::ScopeGuard{&binder_};

if (ast->nestedNameSpecifier) {
auto parent = ast->nestedNameSpecifier->symbol;

if (parent && parent->isClassOrNamespace()) {
setScope(static_cast<ScopedSymbol*>(parent));
}
}

ClassSymbol* classSymbol = nullptr;

if (scope()->isClassOrNamespaceScope()) {
for (auto candidate : scope()->find(className) | views::classes) {
classSymbol = candidate;
break;
}
}

if (!classSymbol) {
const auto isUnion = classKey == TokenKind::T_UNION;
classSymbol = control_->newClassSymbol(scope(), location);

classSymbol->setIsUnion(isUnion);
classSymbol->setName(className);
classSymbol->setTemplateParameters(binder_.currentTemplateParameters());
binder_.declaringScope()->addSymbol(classSymbol);
}

ast->symbol = classSymbol;
specs.type = classSymbol->type();
binder_.bind(ast, specs);

return true;
}
Expand Down Expand Up @@ -6014,51 +5982,35 @@ auto Parser::parse_parameter_declaration_clause(

auto _ = Binder::ScopeGuard{&binder_};

bool parsed = false;

SourceLocation ellipsisLoc;
FunctionParametersSymbol* functionParametersSymbol = nullptr;
auto ast = make_node<ParameterDeclarationClauseAST>(pool_);

if (match(TokenKind::T_DOT_DOT_DOT, ellipsisLoc)) {
parsed = true;
binder_.bind(ast);

auto ast = make_node<ParameterDeclarationClauseAST>(pool_);
if (match(TokenKind::T_DOT_DOT_DOT, ast->ellipsisLoc)) {
yyast = ast;

ast->ellipsisLoc = ellipsisLoc;
ast->isVariadic = true;
ast->functionParametersSymbol =
control_->newFunctionParametersSymbol(scope(), {});
} else if (List<ParameterDeclarationAST*>* parameterDeclarationList = nullptr;
parse_parameter_declaration_list(parameterDeclarationList,
functionParametersSymbol)) {
parsed = true;

auto ast = make_node<ParameterDeclarationClauseAST>(pool_);
} else if (parse_parameter_declaration_list(ast)) {
yyast = ast;
ast->parameterDeclarationList = parameterDeclarationList;

match(TokenKind::T_COMMA, ast->commaLoc);
ast->isVariadic = match(TokenKind::T_DOT_DOT_DOT, ast->ellipsisLoc);
ast->functionParametersSymbol = functionParametersSymbol;
} else {
parsed = false;
}

const auto parsed = yyast != nullptr;

parameter_declaration_clauses_.set(start, currentLocation(), yyast, parsed);

return parsed;
}

auto Parser::parse_parameter_declaration_list(
List<ParameterDeclarationAST*>*& yyast,
FunctionParametersSymbol*& functionParametersSymbol) -> bool {
auto it = &yyast;
ParameterDeclarationClauseAST* ast) -> bool {
auto it = &ast->parameterDeclarationList;

auto _ = Binder::ScopeGuard{&binder_};

functionParametersSymbol = control_->newFunctionParametersSymbol(scope(), {});

setScope(functionParametersSymbol);
setScope(ast->functionParametersSymbol);

ParameterDeclarationAST* declaration = nullptr;

Expand Down Expand Up @@ -7794,72 +7746,13 @@ auto Parser::parse_class_specifier(
ast->isFinal = true;
}

auto _ = Binder::ScopeGuard{&binder_};

if (scope()->isTemplateParametersScope()) {
mark_maybe_template_name(unqualifiedId);
}

auto templateParameters = binder_.currentTemplateParameters();

if (nestedNameSpecifier) {
auto parent = nestedNameSpecifier->symbol;

if (parent && parent->isClassOrNamespace()) {
setScope(static_cast<ScopedSymbol*>(parent));
}
}

ClassSymbol* primaryTemplate = nullptr;

if (templateId && scope()->isTemplateParametersScope()) {
for (auto candidate :
binder_.declaringScope()->find(className) | views::classes) {
primaryTemplate = candidate;
break;
}

if (!primaryTemplate && config_.checkTypes) {
parse_error(location,
std::format("specialization of undeclared template '{}'",
className->name()));
}
}

ClassSymbol* classSymbol = nullptr;

if (className) {
for (auto candidate :
binder_.declaringScope()->find(className) | views::classes) {
classSymbol = candidate;
break;
}
}

if (classSymbol && classSymbol->isComplete()) {
classSymbol = nullptr;
}

if (!classSymbol) {
classSymbol = control_->newClassSymbol(scope(), location);
classSymbol->setIsUnion(isUnion);
classSymbol->setName(className);
classSymbol->setTemplateParameters(templateParameters);

if (!primaryTemplate) {
binder_.declaringScope()->addSymbol(classSymbol);
} else {
std::vector<TemplateArgument> arguments;
// TODO: parse template arguments
primaryTemplate->addSpecialization(arguments, classSymbol);
}
}

if (finalLoc) {
classSymbol->setFinal(true);
}
auto _ = Binder::ScopeGuard{&binder_};

ast->symbol = classSymbol;
binder_.bind(ast, specs);

setScope(ast->symbol);

Expand All @@ -7874,14 +7767,7 @@ auto Parser::parse_class_specifier(
expect(TokenKind::T_RBRACE, ast->rbraceLoc);
}

if (!binder_.inTemplate()) {
auto status = classSymbol->buildClassLayout(control_);
if (!status.has_value() && config_.checkTypes) {
parse_error(classSymbol->location(), status.error());
}
}

classSymbol->setComplete(true);
binder_.complete(ast);

return true;
}
Expand Down
3 changes: 1 addition & 2 deletions src/parser/cxx/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -540,8 +540,7 @@ class Parser final {
[[nodiscard]] auto parse_parameter_declaration_clause(
ParameterDeclarationClauseAST*& yyast) -> bool;
[[nodiscard]] auto parse_parameter_declaration_list(
List<ParameterDeclarationAST*>*& yyast,
FunctionParametersSymbol*& functionParametersSymbol) -> bool;
ParameterDeclarationClauseAST* ast) -> bool;
[[nodiscard]] auto parse_parameter_declaration(
ParameterDeclarationAST*& yyast, bool templParam) -> bool;
[[nodiscard]] auto parse_initializer(ExpressionAST*& yyast,
Expand Down