# cppast-d **Repository Path**: zjh6/cppast-d ## Basic Information - **Project Name**: cppast-d - **Description**: No description available - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-07-24 - **Last Updated**: 2026-07-24 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # cppast-d ![CI](https://github.com/laeeth/cppast-d/workflows/CI/badge.svg) Idiomatic D library for C++ AST parsing via libclang. **Status**: Alpha — declaration, expression, and statement parsing are solid. See [Support Matrix](#support-matrix) below. ## Overview `cppast-d` parses C++ declarations and produces a structured, idiomatic D AST. It is inspired by the [cppast](https://github.com/foonathan/cppast) C++ library but redesigned from scratch for D: - **GC-managed**: no manual memory management - **D-first API**: ranges, delegates, `final switch`, `@safe` - **Declaration printer**: preview C++ forward declarations from parsed AST - **Native C++ shim**: a small `extern "C"` wrapper around the Clang C++ AST is used to expose constructs that the stable libclang C API hides (variable templates, explicit specializations, `decltype`, etc.). See [`docs/native-shim.md`](docs/native-shim.md). ## Quick Start ```d import cppastd; auto root = parseFile("myheader.hpp", ["-std=c++20"]); foreach (child; root.children) writeln(child.name); ``` ## Advanced Parsing For full control over parsing, use `parseFileEx`: ```d import cppastd; CppParseOptions opts; opts.args = ["-std=c++20", "-I/path/to/includes"]; opts.detailedPreprocessingRecord = true; // macros and #include directives opts.skipFunctionBodies = false; // parse function bodies opts.nonFatalDiagnostics = true; // don't throw on parse errors auto result = parseFileEx("myheader.hpp", opts); // result.root — CppFile AST root // result.diagnostics — clang frontend diagnostics // result.warnings — recoverable parser warnings // result.skippedCursors — cursors the parser did not recognize // result.hasErrors — true if Error/Fatal diagnostics were present ``` ### Diagnostics `parseFileEx` returns diagnostics from the clang frontend: ```d auto result = parseFileEx("header.hpp", opts); foreach (d; result.diagnostics) writeln(d.severity, ": ", d.file, ":", d.line, ": ", d.message); ``` By default, parse errors throw `CppParseException`. Set `opts.nonFatalDiagnostics = true` to collect errors in the result instead. ### Skipped Cursors Cursors that the parser does not have a handler for are collected in `result.skippedCursors`. This helps identify gaps in parser coverage: ```d foreach (sc; result.skippedCursors) writeln("Skipped: ", sc.kind, " '", sc.spelling, "' at ", sc.file, ":", sc.line); ``` ### Function Bodies Function bodies are parsed when `opts.skipFunctionBodies = false`. The printer can optionally emit bodies: ```d CppPrintOptions pOpts; pOpts.emitFunctionBodies = true; auto buf = appender!string; printTree(entity, buf, 0, pOpts); ``` ## Support Matrix | Feature | Status | Notes | |---------|--------|-------| | **Namespaces** | Complete | `inline` detected via `clang_Cursor_isInlineNamespace` | | **Classes / structs / unions** | Good | Inheritance (structured `bases`), abstract, template parameter names, explicit specializations via shim, partial-specialization flag | | **Functions / methods** | Good | Virtual, pure, static, explicit, deleted, defaulted, ctor/dtor/copy/move assignment, operator detection, `inline`, `const`, `volatile`, `ref` qualifier, `noexcept` (with condition), `consteval` | | **Variables / fields** | Good | `mutable`, bit-field (width extracted), variable templates via shim | | **Enums** | Complete | `enum class` scoping, explicit underlying type via tokens | | **Type aliases** | Good | Structured `underlyingType` | | **Function parameters** | Good | Type string; default values extracted via tokenization (best-effort) | | **Access specifiers** | Complete | Nodes appear in AST and are **propagated** to individual members | | **Using directives / declarations** | Good | Names extracted | | **Static assertions** | Good | Condition and message extracted via tokens (best-effort) | | **Friend declarations** | Partial | Referenced declaration spelling and kind (class / function / type alias) extracted via tokens and child cursors | | **Templates (classes / functions)** | Good | Parameter names, kinds, defaults, variadics, and pack expansions detected; partial specializations flagged; all template argument kinds (type, integral, template, expression, pack) recognized | | **Comments** | Complete | Attached doc comments from libclang | | **Preprocessor** | Partial | Macro/include entities available with `DetailedPreprocessingRecord`; replacement list/parameters via tokens | | **Attributes (`[[...]]`)** | Good | `[[nodiscard]]`, `[[deprecated]]`, `[[maybe_unused]]`, platform availability extracted; token-based fallback for unknown attributes | | **Expressions** | Good | Full hierarchy (literal, unary, binary, member, call, declRef, cast, paren, arraySubscript, conditional, initList, lambda, new, delete, throw). Parsed for default arguments, static asserts, and function bodies. Rich printing for all expression kinds. | | **Statements** | Good | Compound, return, if, for, while, do-while, switch, case, default, break, continue, null, goto, label, decl, expression, try, catch, cxxForRange, and asm statements are parsed and printed. | | **Printer** | Good | Forward-declaration preview for common cases; not a full code generator | | **Diagnostics** | Complete | `parseFileEx` exposes clang diagnostics with severity, file, line, column | For detailed limitations, see [`docs/known-limitations.md`](docs/known-limitations.md). ## Building ```bash dub build --config app # build CLI tool dub build # build library dub test # run unit tests dub run --config app # run CLI ``` ### Requirements - D compiler: DMD or LDC2 - libclang 22 (or compatible version) - [libclang-d](https://github.com/atilaneves/libclang-d) bindings. Currently requires local clone at `../libclang`; registry release is planned once the path dependency is resolved. - C++ toolchain (`clang++` with C++17 support and `libclang-cpp` / `libLLVM` development libraries) for the native shim. ### Setup Clone both `cppast-d` and `libclang` as siblings: ```bash git clone https://codeberg.org/dlang-public/libclang.git git clone https://codeberg.org/dlang-public/cppast-d.git cd cppast-d dub build ``` The `../libclang` sibling directory is required because `dub.sdl` uses a relative path dependency. CI handles this automatically by checking out both repositories. ## Source Text and Tokens Get the original source text for any parsed node: ```d import cppastd.source; auto text = sourceText(fn); // "int foo(int a, int b);" auto tokens = tokenSpellings(fn); // ["int", "foo", "(", "int", "a", ",", "int", "b", ")", ";"] ``` ## Typed Accessors Convenience helpers avoid manual `cast()` loops: ```d import cppastd.traverse; auto body = bodyOf(fn); // CppCompoundStatement or null auto params = parameters(fn); // CppFunctionParameter[] auto flds = fields(cls); // CppField[] (excludes methods) auto methods_ = methods(cls); // CppFunction[] (excludes ctors/dtors) auto ctors = constructors(cls); // CppFunction[] auto qn = qualifiedName(method); // "ns::Class::method" auto parent = nearestParentOfType!CppClass(method); // owning class ``` ## Symbol Index O(1) lookup by USR, name, or qualified name: ```d import cppastd.traverse; auto idx = buildSymbolIndex(root); auto entity = resolveUsr(idx, usr); auto overloads = overloadSet(idx, "foo"); // all overloads of foo ``` ## Architecture ``` source/ ├── app.d # CLI executable ├── ut_main.d # Minimal entry point for dub unittest └── cppastd/ ├── ast/ │ ├── entity.d # CppEntity hierarchy (19+ entity types) │ ├── type.d # CppType hierarchy (9 type classes) │ ├── expression.d # CppExpression hierarchy │ └── printer.d # Debug declaration printer ├── diagnostic.d # Parse diagnostic types ├── tokens.d # Token-based source extraction helpers ├── package.d # Public API re-export module └── parser/ ├── package.d # Dispatcher: parseFile, parseCursor ├── context.d # CppParseOptions, CppParseResult, ParserContext ├── entities.d # Entity-specific parsers (class, function, enum, namespace, ...) ├── types.d # Type parser (builtin, pointer, reference, function, ...) ├── expressions.d # Expression parser (literal, unary, binary, call, cast, ...) ├── statements.d # Statement parser (compound, if, for, while, switch, ...) └── util.d # Shared cursor-kind / token micro-helpers ``` ## Example Output For a parsed C++ file, the printer produces C++-like forward declarations (best-effort): ```cpp namespace foo { class Base { public: virtual void baseMethod(); }; class Bar : public Base { public: explicit Bar(int x); virtual void baz() = 0; static void helper(); private: int field_; mutable int counter_; }; enum class Color {Red, Green, Blue}; void standaloneFunc(const char * name, int count); template class Box { public: T value; }; } ``` ## API Usage ### Advanced Parsing with Options ```d import cppastd; CppParseOptions opts; opts.detailedPreprocessingRecord = true; opts.args = ["-std=c++20", "-I/path/to/headers"]; auto result = parseFileEx("myheader.hpp", opts); if (result.hasErrors) foreach (d; result.diagnostics) writeln(d.severity, ": ", d.message); foreach (child; result.root.children) printTree(child); ``` ### Working with Attributes ```d foreach (attr; func.attributes) writeln(attr.name, " deprecated? ", attr.isDeprecated); ``` ### Working with Comments ```d if (!entity.comment.isNull) writeln("Doc: ", entity.comment.get); ``` ## Testing Run with `dub test`. All tests pass on DMD and LDC2 for 64-bit Linux. ## Design Philosophy 1. **D first**: idiomatic D code, no C++ patterns 2. **GC-managed**: automatic memory management 3. **Separate concerns**: pure AST abstraction over libclang bindings 4. **Incremental**: features added as needed, not all-at-once ## License Proprietary — Copyright (c) 2026 ## See Also - [`docs/quality-consolidation-plan.md`](docs/quality-consolidation-plan.md) — master plan for turning the prototype into a production-grade library - [`docs/known-limitations.md`](docs/known-limitations.md) — detailed known limitations - [`docs/native-shim.md`](docs/native-shim.md) — why the C++ shim exists and how it builds - [`docs/critique-and-release-plan.md`](docs/critique-and-release-plan.md) — candid review and earlier remediation plan - [cppast](https://github.com/foonathan/cppast) — original C++ library that inspired this design - [libclang-d](https://github.com/atilaneves/libclang-d) — D bindings for libclang