diff --git a/packages/cxx-frontend/src/ASTCursor.ts b/packages/cxx-frontend/src/ASTCursor.ts index 0cf48a6f..05bb1608 100644 --- a/packages/cxx-frontend/src/ASTCursor.ts +++ b/packages/cxx-frontend/src/ASTCursor.ts @@ -78,12 +78,6 @@ class StackEntry { } } -interface AcceptArgs { - node: AST | Token; - depth: number; - slot?: ASTSlot; -} - /** * AST cursor. * diff --git a/packages/cxx-gen-ast/src/gen_ast_h.ts b/packages/cxx-gen-ast/src/gen_ast_h.ts index f414fc67..24cbb094 100644 --- a/packages/cxx-gen-ast/src/gen_ast_h.ts +++ b/packages/cxx-gen-ast/src/gen_ast_h.ts @@ -116,6 +116,17 @@ export function gen_ast_h({ ast, output }: { ast: AST; output: string }) { emit(` default: cxx_runtime_error("unexpected ${variantName}");`); emit(` } // switch`); emit(`}`); + emit(); + emit(`[[nodiscard]] inline auto is${variantName}(AST* ast) -> bool {`); + emit(` if (!ast) return false;`); + emit(` switch (ast->kind()) {`); + nodes.forEach(({ name }) => { + emit(` case ${name}::Kind: `); + }); + emit(` return true;`); + emit(` default: return false;`); + emit(` } // switch`); + emit(`}`); }); const out = `${cpy_header} diff --git a/src/frontend/cxx/cxx_document.cc b/src/frontend/cxx/cxx_document.cc index 9076fc66..fab243cd 100644 --- a/src/frontend/cxx/cxx_document.cc +++ b/src/frontend/cxx/cxx_document.cc @@ -21,6 +21,7 @@ #include "cxx_document.h" #include +#include #include #include #include @@ -208,4 +209,43 @@ auto CxxDocument::translationUnit() const -> TranslationUnit* { return &d->unit; } +namespace { + +struct Visit { + CxxDocument* doc_; + std::function visitor; + ASTSlot slotInfo; + + void preVisit(AST* ast) { + if (!ast) return; + + if (visitor(ast)) return; + + // do a pre-visit using the low-level AST API + + const auto slotCount = slotInfo(ast, 0).slotCount; + + for (int index = 0; index < slotCount; ++index) { + const auto childInfo = slotInfo(ast, index); + + if (childInfo.kind == ASTSlotKind::kNode) { + auto child = reinterpret_cast(childInfo.handle); + if (child) preVisit(child); + } else if (childInfo.kind == ASTSlotKind::kNodeList) { + auto list = reinterpret_cast*>(childInfo.handle); + for (auto node : ListView{list}) { + preVisit(node); + } + } + } + } +}; + +} // namespace + +void CxxDocument::preVisit(std::function visitor) { + auto ast = d->unit.ast(); + Visit{this, std::move(visitor)}.preVisit(ast); +} + } // namespace cxx::lsp \ No newline at end of file diff --git a/src/frontend/cxx/cxx_document.h b/src/frontend/cxx/cxx_document.h index e73fdc2c..5dddeb95 100644 --- a/src/frontend/cxx/cxx_document.h +++ b/src/frontend/cxx/cxx_document.h @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -42,6 +43,8 @@ class CxxDocument { [[nodiscard]] auto translationUnit() const -> TranslationUnit*; + void preVisit(std::function visitor); + private: struct Private; std::unique_ptr d; diff --git a/src/frontend/cxx/lsp_server.cc b/src/frontend/cxx/lsp_server.cc index 4821380a..8c6d2ab1 100644 --- a/src/frontend/cxx/lsp_server.cc +++ b/src/frontend/cxx/lsp_server.cc @@ -320,13 +320,17 @@ void Server::operator()(InitializeRequest request) { withUnsafeJson([&](json storage) { InitializeResponse response{storage}; - std::cerr << std::format("initializing response to {}\n", - request.get().dump()); + response.id(*request.id()); + + auto serverInfo = response.result().serverInfo(); + + serverInfo.name("cxx-lsp").version(CXX_VERSION); + auto capabilities = response.result().capabilities(); - response.result().serverInfo().name("cxx-lsp").version( - CXX_VERSION); capabilities.textDocumentSync(TextDocumentSyncKind::kIncremental); + capabilities.documentSymbolProvider(true); + sendToClient(response); }); } @@ -424,8 +428,18 @@ auto Server::latestDocument(const std::string& uri) return documents_[uri]; } -void Server::operator()(DocumentDiagnosticRequest request) { - logTrace(std::format("Did receive DocumentDiagnosticRequest")); +void Server::operator()(DocumentSymbolRequest request) { + logTrace(std::format("Did receive DocumentSymbolRequest")); + + auto uri = request.params().textDocument().uri(); + auto doc = latestDocument(uri); + + withUnsafeJson([&](json storage) { + DocumentSymbolResponse response(storage); + response.id(request.id()); + (void)response.result(); + sendToClient(response); + }); } void Server::operator()(CancelNotification notification) { @@ -448,7 +462,7 @@ void Server::operator()(SetTraceNotification notification) { trace_ = notification.params().value(); if (trace_ != TraceValue::kOff) { - logTrace("Trace level set to {}\n", to_string(trace_)); + logTrace("Trace level set to {}", to_string(trace_)); return; } } diff --git a/src/frontend/cxx/lsp_server.h b/src/frontend/cxx/lsp_server.h index bdcf51e1..7e727894 100644 --- a/src/frontend/cxx/lsp_server.h +++ b/src/frontend/cxx/lsp_server.h @@ -56,7 +56,7 @@ class Server { void operator()(DidCloseTextDocumentNotification notification); void operator()(DidChangeTextDocumentNotification notification); - void operator()(DocumentDiagnosticRequest request); + void operator()(DocumentSymbolRequest request); void operator()(SetTraceNotification notification); diff --git a/src/parser/cxx/ast.h b/src/parser/cxx/ast.h index f7836b8d..be9c95ba 100644 --- a/src/parser/cxx/ast.h +++ b/src/parser/cxx/ast.h @@ -4074,6 +4074,17 @@ auto visit(Visitor&& visitor, UnitAST* ast) { } // switch } +[[nodiscard]] inline auto isUnit(AST* ast) -> bool { + if (!ast) return false; + switch (ast->kind()) { + case TranslationUnitAST::Kind: + case ModuleUnitAST::Kind: + return true; + default: + return false; + } // switch +} + template auto visit(Visitor&& visitor, DeclarationAST* ast) { switch (ast->kind()) { @@ -4169,6 +4180,44 @@ auto visit(Visitor&& visitor, DeclarationAST* ast) { } // switch } +[[nodiscard]] inline auto isDeclaration(AST* ast) -> bool { + if (!ast) return false; + switch (ast->kind()) { + case SimpleDeclarationAST::Kind: + case AsmDeclarationAST::Kind: + case NamespaceAliasDefinitionAST::Kind: + case UsingDeclarationAST::Kind: + case UsingEnumDeclarationAST::Kind: + case UsingDirectiveAST::Kind: + case StaticAssertDeclarationAST::Kind: + case AliasDeclarationAST::Kind: + case OpaqueEnumDeclarationAST::Kind: + case FunctionDefinitionAST::Kind: + case TemplateDeclarationAST::Kind: + case ConceptDefinitionAST::Kind: + case DeductionGuideAST::Kind: + case ExplicitInstantiationAST::Kind: + case ExportDeclarationAST::Kind: + case ExportCompoundDeclarationAST::Kind: + case LinkageSpecificationAST::Kind: + case NamespaceDefinitionAST::Kind: + case EmptyDeclarationAST::Kind: + case AttributeDeclarationAST::Kind: + case ModuleImportDeclarationAST::Kind: + case ParameterDeclarationAST::Kind: + case AccessDeclarationAST::Kind: + case ForRangeDeclarationAST::Kind: + case StructuredBindingDeclarationAST::Kind: + case AsmOperandAST::Kind: + case AsmQualifierAST::Kind: + case AsmClobberAST::Kind: + case AsmGotoLabelAST::Kind: + return true; + default: + return false; + } // switch +} + template auto visit(Visitor&& visitor, StatementAST* ast) { switch (ast->kind()) { @@ -4234,6 +4283,34 @@ auto visit(Visitor&& visitor, StatementAST* ast) { } // switch } +[[nodiscard]] inline auto isStatement(AST* ast) -> bool { + if (!ast) return false; + switch (ast->kind()) { + case LabeledStatementAST::Kind: + case CaseStatementAST::Kind: + case DefaultStatementAST::Kind: + case ExpressionStatementAST::Kind: + case CompoundStatementAST::Kind: + case IfStatementAST::Kind: + case ConstevalIfStatementAST::Kind: + case SwitchStatementAST::Kind: + case WhileStatementAST::Kind: + case DoStatementAST::Kind: + case ForRangeStatementAST::Kind: + case ForStatementAST::Kind: + case BreakStatementAST::Kind: + case ContinueStatementAST::Kind: + case ReturnStatementAST::Kind: + case CoroutineReturnStatementAST::Kind: + case GotoStatementAST::Kind: + case DeclarationStatementAST::Kind: + case TryBlockStatementAST::Kind: + return true; + default: + return false; + } // switch +} + template auto visit(Visitor&& visitor, ExpressionAST* ast) { switch (ast->kind()) { @@ -4414,6 +4491,72 @@ auto visit(Visitor&& visitor, ExpressionAST* ast) { } // switch } +[[nodiscard]] inline auto isExpression(AST* ast) -> bool { + if (!ast) return false; + switch (ast->kind()) { + case GeneratedLiteralExpressionAST::Kind: + case CharLiteralExpressionAST::Kind: + case BoolLiteralExpressionAST::Kind: + case IntLiteralExpressionAST::Kind: + case FloatLiteralExpressionAST::Kind: + case NullptrLiteralExpressionAST::Kind: + case StringLiteralExpressionAST::Kind: + case UserDefinedStringLiteralExpressionAST::Kind: + case ThisExpressionAST::Kind: + case NestedExpressionAST::Kind: + case IdExpressionAST::Kind: + case LambdaExpressionAST::Kind: + case FoldExpressionAST::Kind: + case RightFoldExpressionAST::Kind: + case LeftFoldExpressionAST::Kind: + case RequiresExpressionAST::Kind: + case VaArgExpressionAST::Kind: + case SubscriptExpressionAST::Kind: + case CallExpressionAST::Kind: + case TypeConstructionAST::Kind: + case BracedTypeConstructionAST::Kind: + case SpliceMemberExpressionAST::Kind: + case MemberExpressionAST::Kind: + case PostIncrExpressionAST::Kind: + case CppCastExpressionAST::Kind: + case BuiltinBitCastExpressionAST::Kind: + case TypeidExpressionAST::Kind: + case TypeidOfTypeExpressionAST::Kind: + case SpliceExpressionAST::Kind: + case GlobalScopeReflectExpressionAST::Kind: + case NamespaceReflectExpressionAST::Kind: + case TypeIdReflectExpressionAST::Kind: + case ReflectExpressionAST::Kind: + case UnaryExpressionAST::Kind: + case AwaitExpressionAST::Kind: + case SizeofExpressionAST::Kind: + case SizeofTypeExpressionAST::Kind: + case SizeofPackExpressionAST::Kind: + case AlignofTypeExpressionAST::Kind: + case AlignofExpressionAST::Kind: + case NoexceptExpressionAST::Kind: + case NewExpressionAST::Kind: + case DeleteExpressionAST::Kind: + case CastExpressionAST::Kind: + case ImplicitCastExpressionAST::Kind: + case BinaryExpressionAST::Kind: + case ConditionalExpressionAST::Kind: + case YieldExpressionAST::Kind: + case ThrowExpressionAST::Kind: + case AssignmentExpressionAST::Kind: + case PackExpansionExpressionAST::Kind: + case DesignatedInitializerClauseAST::Kind: + case TypeTraitExpressionAST::Kind: + case ConditionExpressionAST::Kind: + case EqualInitializerAST::Kind: + case BracedInitListAST::Kind: + case ParenInitializerAST::Kind: + return true; + default: + return false; + } // switch +} + template auto visit(Visitor&& visitor, TemplateParameterAST* ast) { switch (ast->kind()) { @@ -4434,6 +4577,19 @@ auto visit(Visitor&& visitor, TemplateParameterAST* ast) { } // switch } +[[nodiscard]] inline auto isTemplateParameter(AST* ast) -> bool { + if (!ast) return false; + switch (ast->kind()) { + case TemplateTypeParameterAST::Kind: + case NonTypeTemplateParameterAST::Kind: + case TypenameTypeParameterAST::Kind: + case ConstraintTypeParameterAST::Kind: + return true; + default: + return false; + } // switch +} + template auto visit(Visitor&& visitor, SpecifierAST* ast) { switch (ast->kind()) { @@ -4550,6 +4706,51 @@ auto visit(Visitor&& visitor, SpecifierAST* ast) { } // switch } +[[nodiscard]] inline auto isSpecifier(AST* ast) -> bool { + if (!ast) return false; + switch (ast->kind()) { + case GeneratedTypeSpecifierAST::Kind: + case TypedefSpecifierAST::Kind: + case FriendSpecifierAST::Kind: + case ConstevalSpecifierAST::Kind: + case ConstinitSpecifierAST::Kind: + case ConstexprSpecifierAST::Kind: + case InlineSpecifierAST::Kind: + case StaticSpecifierAST::Kind: + case ExternSpecifierAST::Kind: + case ThreadLocalSpecifierAST::Kind: + case ThreadSpecifierAST::Kind: + case MutableSpecifierAST::Kind: + case VirtualSpecifierAST::Kind: + case ExplicitSpecifierAST::Kind: + case AutoTypeSpecifierAST::Kind: + case VoidTypeSpecifierAST::Kind: + case SizeTypeSpecifierAST::Kind: + case SignTypeSpecifierAST::Kind: + case VaListTypeSpecifierAST::Kind: + case IntegralTypeSpecifierAST::Kind: + case FloatingPointTypeSpecifierAST::Kind: + case ComplexTypeSpecifierAST::Kind: + case NamedTypeSpecifierAST::Kind: + case AtomicTypeSpecifierAST::Kind: + case UnderlyingTypeSpecifierAST::Kind: + case ElaboratedTypeSpecifierAST::Kind: + case DecltypeAutoSpecifierAST::Kind: + case DecltypeSpecifierAST::Kind: + case PlaceholderTypeSpecifierAST::Kind: + case ConstQualifierAST::Kind: + case VolatileQualifierAST::Kind: + case RestrictQualifierAST::Kind: + case EnumSpecifierAST::Kind: + case ClassSpecifierAST::Kind: + case TypenameSpecifierAST::Kind: + case SplicerTypeSpecifierAST::Kind: + return true; + default: + return false; + } // switch +} + template auto visit(Visitor&& visitor, PtrOperatorAST* ast) { switch (ast->kind()) { @@ -4567,6 +4768,18 @@ auto visit(Visitor&& visitor, PtrOperatorAST* ast) { } // switch } +[[nodiscard]] inline auto isPtrOperator(AST* ast) -> bool { + if (!ast) return false; + switch (ast->kind()) { + case PointerOperatorAST::Kind: + case ReferenceOperatorAST::Kind: + case PtrToMemberOperatorAST::Kind: + return true; + default: + return false; + } // switch +} + template auto visit(Visitor&& visitor, CoreDeclaratorAST* ast) { switch (ast->kind()) { @@ -4587,6 +4800,19 @@ auto visit(Visitor&& visitor, CoreDeclaratorAST* ast) { } // switch } +[[nodiscard]] inline auto isCoreDeclarator(AST* ast) -> bool { + if (!ast) return false; + switch (ast->kind()) { + case BitfieldDeclaratorAST::Kind: + case ParameterPackAST::Kind: + case IdDeclaratorAST::Kind: + case NestedDeclaratorAST::Kind: + return true; + default: + return false; + } // switch +} + template auto visit(Visitor&& visitor, DeclaratorChunkAST* ast) { switch (ast->kind()) { @@ -4601,6 +4827,17 @@ auto visit(Visitor&& visitor, DeclaratorChunkAST* ast) { } // switch } +[[nodiscard]] inline auto isDeclaratorChunk(AST* ast) -> bool { + if (!ast) return false; + switch (ast->kind()) { + case FunctionDeclaratorChunkAST::Kind: + case ArrayDeclaratorChunkAST::Kind: + return true; + default: + return false; + } // switch +} + template auto visit(Visitor&& visitor, UnqualifiedIdAST* ast) { switch (ast->kind()) { @@ -4636,6 +4873,24 @@ auto visit(Visitor&& visitor, UnqualifiedIdAST* ast) { } // switch } +[[nodiscard]] inline auto isUnqualifiedId(AST* ast) -> bool { + if (!ast) return false; + switch (ast->kind()) { + case NameIdAST::Kind: + case DestructorIdAST::Kind: + case DecltypeIdAST::Kind: + case OperatorFunctionIdAST::Kind: + case LiteralOperatorIdAST::Kind: + case ConversionFunctionIdAST::Kind: + case SimpleTemplateIdAST::Kind: + case LiteralOperatorTemplateIdAST::Kind: + case OperatorFunctionTemplateIdAST::Kind: + return true; + default: + return false; + } // switch +} + template auto visit(Visitor&& visitor, NestedNameSpecifierAST* ast) { switch (ast->kind()) { @@ -4656,6 +4911,19 @@ auto visit(Visitor&& visitor, NestedNameSpecifierAST* ast) { } // switch } +[[nodiscard]] inline auto isNestedNameSpecifier(AST* ast) -> bool { + if (!ast) return false; + switch (ast->kind()) { + case GlobalNestedNameSpecifierAST::Kind: + case SimpleNestedNameSpecifierAST::Kind: + case DecltypeNestedNameSpecifierAST::Kind: + case TemplateNestedNameSpecifierAST::Kind: + return true; + default: + return false; + } // switch +} + template auto visit(Visitor&& visitor, FunctionBodyAST* ast) { switch (ast->kind()) { @@ -4676,6 +4944,19 @@ auto visit(Visitor&& visitor, FunctionBodyAST* ast) { } // switch } +[[nodiscard]] inline auto isFunctionBody(AST* ast) -> bool { + if (!ast) return false; + switch (ast->kind()) { + case DefaultFunctionBodyAST::Kind: + case CompoundStatementFunctionBodyAST::Kind: + case TryStatementFunctionBodyAST::Kind: + case DeleteFunctionBodyAST::Kind: + return true; + default: + return false; + } // switch +} + template auto visit(Visitor&& visitor, TemplateArgumentAST* ast) { switch (ast->kind()) { @@ -4690,6 +4971,17 @@ auto visit(Visitor&& visitor, TemplateArgumentAST* ast) { } // switch } +[[nodiscard]] inline auto isTemplateArgument(AST* ast) -> bool { + if (!ast) return false; + switch (ast->kind()) { + case TypeTemplateArgumentAST::Kind: + case ExpressionTemplateArgumentAST::Kind: + return true; + default: + return false; + } // switch +} + template auto visit(Visitor&& visitor, ExceptionSpecifierAST* ast) { switch (ast->kind()) { @@ -4704,6 +4996,17 @@ auto visit(Visitor&& visitor, ExceptionSpecifierAST* ast) { } // switch } +[[nodiscard]] inline auto isExceptionSpecifier(AST* ast) -> bool { + if (!ast) return false; + switch (ast->kind()) { + case ThrowExceptionSpecifierAST::Kind: + case NoexceptSpecifierAST::Kind: + return true; + default: + return false; + } // switch +} + template auto visit(Visitor&& visitor, RequirementAST* ast) { switch (ast->kind()) { @@ -4724,6 +5027,19 @@ auto visit(Visitor&& visitor, RequirementAST* ast) { } // switch } +[[nodiscard]] inline auto isRequirement(AST* ast) -> bool { + if (!ast) return false; + switch (ast->kind()) { + case SimpleRequirementAST::Kind: + case CompoundRequirementAST::Kind: + case TypeRequirementAST::Kind: + case NestedRequirementAST::Kind: + return true; + default: + return false; + } // switch +} + template auto visit(Visitor&& visitor, NewInitializerAST* ast) { switch (ast->kind()) { @@ -4738,6 +5054,17 @@ auto visit(Visitor&& visitor, NewInitializerAST* ast) { } // switch } +[[nodiscard]] inline auto isNewInitializer(AST* ast) -> bool { + if (!ast) return false; + switch (ast->kind()) { + case NewParenInitializerAST::Kind: + case NewBracedInitializerAST::Kind: + return true; + default: + return false; + } // switch +} + template auto visit(Visitor&& visitor, MemInitializerAST* ast) { switch (ast->kind()) { @@ -4752,6 +5079,17 @@ auto visit(Visitor&& visitor, MemInitializerAST* ast) { } // switch } +[[nodiscard]] inline auto isMemInitializer(AST* ast) -> bool { + if (!ast) return false; + switch (ast->kind()) { + case ParenMemInitializerAST::Kind: + case BracedMemInitializerAST::Kind: + return true; + default: + return false; + } // switch +} + template auto visit(Visitor&& visitor, LambdaCaptureAST* ast) { switch (ast->kind()) { @@ -4778,6 +5116,21 @@ auto visit(Visitor&& visitor, LambdaCaptureAST* ast) { } // switch } +[[nodiscard]] inline auto isLambdaCapture(AST* ast) -> bool { + if (!ast) return false; + switch (ast->kind()) { + case ThisLambdaCaptureAST::Kind: + case DerefThisLambdaCaptureAST::Kind: + case SimpleLambdaCaptureAST::Kind: + case RefLambdaCaptureAST::Kind: + case RefInitLambdaCaptureAST::Kind: + case InitLambdaCaptureAST::Kind: + return true; + default: + return false; + } // switch +} + template auto visit(Visitor&& visitor, ExceptionDeclarationAST* ast) { switch (ast->kind()) { @@ -4792,6 +5145,17 @@ auto visit(Visitor&& visitor, ExceptionDeclarationAST* ast) { } // switch } +[[nodiscard]] inline auto isExceptionDeclaration(AST* ast) -> bool { + if (!ast) return false; + switch (ast->kind()) { + case EllipsisExceptionDeclarationAST::Kind: + case TypeExceptionDeclarationAST::Kind: + return true; + default: + return false; + } // switch +} + template auto visit(Visitor&& visitor, AttributeSpecifierAST* ast) { switch (ast->kind()) { @@ -4815,6 +5179,20 @@ auto visit(Visitor&& visitor, AttributeSpecifierAST* ast) { } // switch } +[[nodiscard]] inline auto isAttributeSpecifier(AST* ast) -> bool { + if (!ast) return false; + switch (ast->kind()) { + case CxxAttributeAST::Kind: + case GccAttributeAST::Kind: + case AlignasAttributeAST::Kind: + case AlignasTypeAttributeAST::Kind: + case AsmAttributeAST::Kind: + return true; + default: + return false; + } // switch +} + template auto visit(Visitor&& visitor, AttributeTokenAST* ast) { switch (ast->kind()) { @@ -4829,6 +5207,17 @@ auto visit(Visitor&& visitor, AttributeTokenAST* ast) { } // switch } +[[nodiscard]] inline auto isAttributeToken(AST* ast) -> bool { + if (!ast) return false; + switch (ast->kind()) { + case ScopedAttributeTokenAST::Kind: + case SimpleAttributeTokenAST::Kind: + return true; + default: + return false; + } // switch +} + template [[nodiscard]] auto ast_cast(AST* ast) -> T* { return ast && ast->kind() == T::Kind ? static_cast(ast) : nullptr;