diff --git a/src/parser/cxx/binder.cc b/src/parser/cxx/binder.cc index 01599df6..328d987e 100644 --- a/src/parser/cxx/binder.cc +++ b/src/parser/cxx/binder.cc @@ -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(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(parent)); + } + } + + auto className = get_name(control(), ast->unqualifiedId); + auto templateId = ast_cast(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 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()); @@ -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(); diff --git a/src/parser/cxx/binder.h b/src/parser/cxx/binder.h index bc86e0e8..c1c4616d 100644 --- a/src/parser/cxx/binder.h +++ b/src/parser/cxx/binder.h @@ -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 value); @@ -111,6 +117,8 @@ class Binder { void complete(LambdaExpressionAST* ast); + void bind(ParameterDeclarationClauseAST* ast); + class ScopeGuard { public: Binder* p = nullptr; diff --git a/src/parser/cxx/parser.cc b/src/parser/cxx/parser.cc index b2becbf9..e592a43a 100644 --- a/src/parser/cxx/parser.cc +++ b/src/parser/cxx/parser.cc @@ -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(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; } @@ -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(pool_); - if (match(TokenKind::T_DOT_DOT_DOT, ellipsisLoc)) { - parsed = true; + binder_.bind(ast); - auto ast = make_node(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* parameterDeclarationList = nullptr; - parse_parameter_declaration_list(parameterDeclarationList, - functionParametersSymbol)) { - parsed = true; - - auto ast = make_node(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*& 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; @@ -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(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 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); @@ -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; } diff --git a/src/parser/cxx/parser.h b/src/parser/cxx/parser.h index 2dbecd9f..e6cab81d 100644 --- a/src/parser/cxx/parser.h +++ b/src/parser/cxx/parser.h @@ -540,8 +540,7 @@ class Parser final { [[nodiscard]] auto parse_parameter_declaration_clause( ParameterDeclarationClauseAST*& yyast) -> bool; [[nodiscard]] auto parse_parameter_declaration_list( - List*& yyast, - FunctionParametersSymbol*& functionParametersSymbol) -> bool; + ParameterDeclarationClauseAST* ast) -> bool; [[nodiscard]] auto parse_parameter_declaration( ParameterDeclarationAST*& yyast, bool templParam) -> bool; [[nodiscard]] auto parse_initializer(ExpressionAST*& yyast,