Step 335: C++ Generator — Inheritance + Templates (12/12 tests)

Updated CppGenerator, PythonGenerator, JavaGenerator for multiple inheritance
output using getBases(). C++ emits template prefix + access specifiers + virtual.
Python uses direct multi-base. Java uses extends + implements adaptation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Bill
2026-02-16 00:29:54 -07:00
parent b75fba72d8
commit 6464c88483
6 changed files with 331 additions and 4 deletions

View File

@@ -2014,4 +2014,8 @@ target_link_libraries(step334_test PRIVATE
tree_sitter_javascript tree_sitter_typescript tree_sitter_javascript tree_sitter_typescript
tree_sitter_java tree_sitter_rust tree_sitter_go) tree_sitter_java tree_sitter_rust tree_sitter_go)
add_executable(step335_test tests/step335_test.cpp)
target_include_directories(step335_test PRIVATE src)
target_link_libraries(step335_test PRIVATE nlohmann_json::nlohmann_json)
# Step 12: Dear ImGui shell scaffolding created (main.cpp exists but not built due to dependencies) # Step 12: Dear ImGui shell scaffolding created (main.cpp exists but not built due to dependencies)

View File

@@ -110,8 +110,36 @@
std::ostringstream oss; std::ostringstream oss;
auto annotations = cls->getChildren("annotations"); auto annotations = cls->getChildren("annotations");
for (const auto* a : annotations) oss << generate(a) << "\n"; for (const auto* a : annotations) oss << generate(a) << "\n";
// Template prefix if has GenericType children with isClassTemplate
auto tpChildren = cls->getChildren("typeParameters");
for (const auto* tpc : tpChildren) {
if (tpc->conceptType == "GenericType") {
auto* gt = static_cast<const GenericType*>(tpc);
if (gt->isClassTemplate) {
oss << "template<";
auto params = gt->getChildren("typeParameters");
for (size_t i = 0; i < params.size(); ++i) {
if (i > 0) oss << ", ";
auto* tp = static_cast<const TypeParameter*>(params[i]);
if (tp->isVariadic) oss << "typename... " << tp->name;
else oss << "typename " << tp->name;
}
oss << ">\n";
break;
}
}
}
oss << "class " << cls->name; oss << "class " << cls->name;
if (!cls->superClass.empty()) oss << " : public " << cls->superClass; auto bases = cls->getBases();
if (!bases.empty()) {
oss << " : ";
for (size_t i = 0; i < bases.size(); ++i) {
if (i > 0) oss << ", ";
oss << bases[i].accessSpecifier;
if (bases[i].isVirtual) oss << " virtual";
oss << " " << bases[i].name;
}
}
oss << " {\npublic:\n"; oss << " {\npublic:\n";
auto fields = cls->getChildren("fields"); auto fields = cls->getChildren("fields");
for (const auto* f : fields) for (const auto* f : fields)

View File

@@ -451,10 +451,21 @@ public:
for (const auto* a : annotations) oss << generate(a) << "\n"; for (const auto* a : annotations) oss << generate(a) << "\n";
if (cls->isAbstract) oss << "abstract "; if (cls->isAbstract) oss << "abstract ";
oss << "class " << cls->name; oss << "class " << cls->name;
if (!cls->superClass.empty()) oss << " extends " << cls->superClass; auto bases = cls->getBases();
if (!bases.empty()) {
// First base → extends, rest → implements (Java adaptation)
oss << " extends " << bases[0].name;
if (bases.size() > 1) {
oss << " implements ";
for (size_t i = 1; i < bases.size(); ++i) {
if (i > 1) oss << ", ";
oss << bases[i].name;
}
}
}
auto interfaces = cls->getChildren("interfaces"); auto interfaces = cls->getChildren("interfaces");
if (!interfaces.empty()) { if (!interfaces.empty()) {
oss << " implements "; oss << (bases.size() > 1 ? ", " : " implements ");
for (size_t i = 0; i < interfaces.size(); ++i) { for (size_t i = 0; i < interfaces.size(); ++i) {
if (i > 0) oss << ", "; if (i > 0) oss << ", ";
oss << generate(interfaces[i]); oss << generate(interfaces[i]);

View File

@@ -538,7 +538,15 @@ public:
auto annotations = cls->getChildren("annotations"); auto annotations = cls->getChildren("annotations");
for (const auto* a : annotations) oss << generate(a) << "\n"; for (const auto* a : annotations) oss << generate(a) << "\n";
oss << "class " << cls->name; oss << "class " << cls->name;
if (!cls->superClass.empty()) oss << "(" << cls->superClass << ")"; auto bases = cls->getBases();
if (!bases.empty()) {
oss << "(";
for (size_t i = 0; i < bases.size(); ++i) {
if (i > 0) oss << ", ";
oss << bases[i].name;
}
oss << ")";
}
oss << ":\n"; oss << ":\n";
auto fields = cls->getChildren("fields"); auto fields = cls->getChildren("fields");
auto methods = cls->getChildren("methods"); auto methods = cls->getChildren("methods");

View File

@@ -0,0 +1,221 @@
// Step 335: C++ Generator — Inheritance + Templates (12 tests)
// Tests C++ output for multiple inheritance, virtual, template classes,
// cross-language adaptation
#include <cassert>
#include <iostream>
#include <string>
#include "ast/ClassDeclaration.h"
#include "ast/GenericType.h"
#include "ast/AsyncNodes.h"
#include "ast/CppGenerator.h"
#include "ast/PythonGenerator.h"
#include "ast/JavaGenerator.h"
#include "ast/RustGenerator.h"
#include "ast/Serialization.h"
int main() {
int passed = 0;
// Test 1: C++ multiple inheritance output
{
auto* cls = new ClassDeclaration("cls1", "Widget");
cls->addBase("Base", "public");
cls->addBase("Mixin", "public");
CppGenerator gen;
std::string out = gen.generate(cls);
assert(out.find("class Widget") != std::string::npos);
assert(out.find("public Base") != std::string::npos);
assert(out.find("public Mixin") != std::string::npos);
delete cls;
std::cout << "Test 1 PASSED: C++ multiple inheritance output\n";
passed++;
}
// Test 2: Access specifier output
{
auto* cls = new ClassDeclaration("cls2", "D");
cls->addBase("A", "public");
cls->addBase("B", "protected");
cls->addBase("C", "private");
CppGenerator gen;
std::string out = gen.generate(cls);
assert(out.find("public A") != std::string::npos);
assert(out.find("protected B") != std::string::npos);
assert(out.find("private C") != std::string::npos);
delete cls;
std::cout << "Test 2 PASSED: Access specifier output\n";
passed++;
}
// Test 3: Virtual keyword present
{
auto* cls = new ClassDeclaration("cls3", "D");
cls->addBase("Base", "public", true);
CppGenerator gen;
std::string out = gen.generate(cls);
assert(out.find("virtual") != std::string::npos);
assert(out.find("Base") != std::string::npos);
delete cls;
std::cout << "Test 3 PASSED: Virtual keyword present\n";
passed++;
}
// Test 4: Template class output
{
auto* cls = new ClassDeclaration("cls4", "Container");
auto* gt = new GenericType("gt1", "Container");
gt->isClassTemplate = true;
auto* tp = new TypeParameter("tp1", "T");
gt->addChild("typeParameters", tp);
cls->addChild("typeParameters", gt);
CppGenerator gen;
std::string out = gen.generate(cls);
assert(out.find("template") != std::string::npos);
assert(out.find("typename T") != std::string::npos || out.find("T") != std::string::npos);
assert(out.find("class Container") != std::string::npos);
delete cls;
std::cout << "Test 4 PASSED: Template class output\n";
passed++;
}
// Test 5: CRTP output
{
auto* cls = new ClassDeclaration("cls5", "Derived");
cls->addBase("Base<Derived>", "public");
CppGenerator gen;
std::string out = gen.generate(cls);
assert(out.find("Base<Derived>") != std::string::npos);
delete cls;
std::cout << "Test 5 PASSED: CRTP output\n";
passed++;
}
// Test 6: Cross-language C++ → Python (multiple bases → direct multiple inheritance)
{
auto* cls = new ClassDeclaration("cls6", "D");
cls->addBase("A", "public");
cls->addBase("B", "public");
PythonGenerator gen;
std::string out = gen.generate(cls);
// Python should show both bases
assert(out.find("class D") != std::string::npos);
assert(out.find("A") != std::string::npos);
assert(out.find("B") != std::string::npos);
delete cls;
std::cout << "Test 6 PASSED: C++ → Python multiple inheritance\n";
passed++;
}
// Test 7: Cross-language C++ → Java (multiple bases → extends + implements)
{
auto* cls = new ClassDeclaration("cls7", "Widget");
cls->addBase("Base", "public");
cls->addBase("Drawable", "public");
JavaGenerator gen;
std::string out = gen.generate(cls);
assert(out.find("class Widget") != std::string::npos);
// Java should at least show first as extends
assert(out.find("Base") != std::string::npos);
delete cls;
std::cout << "Test 7 PASSED: C++ → Java inheritance output\n";
passed++;
}
// Test 8: Cross-language C++ → Rust (no inheritance, traits)
{
auto* cls = new ClassDeclaration("cls8", "Widget");
cls->addBase("Base", "public");
RustGenerator gen;
std::string out = gen.generate(cls);
assert(out.find("Widget") != std::string::npos);
// Rust uses struct, not class inheritance
assert(!out.empty());
delete cls;
std::cout << "Test 8 PASSED: C++ → Rust struct output\n";
passed++;
}
// Test 9: Template class with variadic
{
auto* cls = new ClassDeclaration("cls9", "Tuple");
auto* gt = new GenericType("gt2", "Tuple");
gt->isClassTemplate = true;
auto* tp1 = new TypeParameter("tp2", "Head");
auto* tp2 = new TypeParameter("tp3", "Tail");
tp2->isVariadic = true;
gt->addChild("typeParameters", tp1);
gt->addChild("typeParameters", tp2);
cls->addChild("typeParameters", gt);
CppGenerator gen;
std::string out = gen.generate(cls);
assert(out.find("template") != std::string::npos);
assert(out.find("Tail") != std::string::npos);
assert(out.find("...") != std::string::npos); // variadic pack
delete cls;
std::cout << "Test 9 PASSED: Variadic template class output\n";
passed++;
}
// Test 10: Combined template + multiple inheritance output
{
auto* cls = new ClassDeclaration("cls10", "MyGen");
cls->addBase("ProjectionGenerator", "public");
cls->addBase("SemannoAnnotationImpl<MyGen>", "public");
auto* gt = new GenericType("gt3", "MyGen");
gt->isClassTemplate = true;
auto* tp = new TypeParameter("tp4", "T");
gt->addChild("typeParameters", tp);
cls->addChild("typeParameters", gt);
CppGenerator gen;
std::string out = gen.generate(cls);
assert(out.find("template") != std::string::npos);
assert(out.find("class MyGen") != std::string::npos);
assert(out.find("ProjectionGenerator") != std::string::npos);
assert(out.find("SemannoAnnotationImpl<MyGen>") != std::string::npos);
delete cls;
std::cout << "Test 10 PASSED: Combined template + multiple inheritance\n";
passed++;
}
// Test 11: Method with visibility in class
{
auto* cls = new ClassDeclaration("cls11", "Foo");
cls->addBase("Bar", "public");
auto* meth = new MethodDeclaration("m1", "doStuff");
meth->className = "Foo";
meth->isVirtual = true;
cls->addChild("methods", meth);
CppGenerator gen;
std::string out = gen.generate(cls);
assert(out.find("virtual") != std::string::npos);
assert(out.find("doStuff") != std::string::npos);
delete cls;
std::cout << "Test 11 PASSED: Method with visibility in class\n";
passed++;
}
// Test 12: Roundtrip: AST → generate → verify structure
{
auto* cls = new ClassDeclaration("cls12", "Stack");
cls->addBase("Container", "public");
cls->addBase("Serializable", "public");
cls->isAbstract = true;
auto* field = new Variable("v1", "size_");
cls->addChild("fields", field);
CppGenerator gen;
std::string out = gen.generate(cls);
assert(out.find("class Stack") != std::string::npos);
assert(out.find("Container") != std::string::npos);
assert(out.find("Serializable") != std::string::npos);
assert(out.find("size_") != std::string::npos);
assert(out.length() > 20);
delete cls;
std::cout << "Test 12 PASSED: Full class generation roundtrip\n";
passed++;
}
std::cout << "\nResults: " << passed << "/12 tests passed\n";
return (passed == 12) ? 0 : 1;
}

View File

@@ -1491,6 +1491,61 @@ diamond inheritance detection via static hasDiamondInheritance() with BFS traver
access specifiers, virtual inheritance, JSON roundtrip, diamond detection, legacy access specifiers, virtual inheritance, JSON roundtrip, diamond detection, legacy
migration, addBase helper, full serialization roundtrip migration, addBase helper, full serialization roundtrip
### Step 333: Template Class Declarations
**Status:** PASS (12/12 tests)
Extended GenericType with isClassTemplate flag and TypeParameter with isVariadic for
variadic template packs. Added isCRTPClass() helper for CRTP pattern detection. Full
serialization round-trip for both flags.
**Files modified:**
- `editor/src/ast/GenericType.h` — isCRTPClass() helper, isClassTemplate/isVariadic
already had fields, replaced stub isCRTP()
- `editor/src/ast/Serialization.h` — isClassTemplate for GenericType, isVariadic for
TypeParameter in propertiesToJson/createNode/setPropertiesFromJson
- `editor/src/CompactAST.h` — getNodeName for GenericType ("template:name"), TypeParameter
- `editor/CMakeLists.txt` — step333_test target
**Files created:**
- `editor/tests/step333_test.cpp` — 12 tests: isClassTemplate flag, isVariadic,
CRTP detection, JSON roundtrip, CompactAST output
### Step 334: C++ Parser — Inheritance + Templates
**Status:** PASS (12/12 tests)
Extended CppParser to extract multiple base classes from tree-sitter CST, including
access specifiers and virtual keyword. Iterates ALL children (named + unnamed) of
base_class_clause to detect virtual (unnamed node), access_specifier, and type identifiers.
**Files modified:**
- `editor/src/ast/CppParser.h` — Rewrote base_class_clause parsing to iterate all
children with pending access/virtual state machine
- `editor/CMakeLists.txt` — step334_test target with tree-sitter libraries
**Files created:**
- `editor/tests/step334_test.cpp` — 12 tests: single/multiple inheritance, access
specifiers, virtual, template classes, CRTP detection, struct default public
### Step 335: C++ Generator — Inheritance + Templates
**Status:** PASS (12/12 tests)
Updated CppGenerator, PythonGenerator, and JavaGenerator to emit correct inheritance
syntax using getBases(). C++ outputs access specifiers + virtual keyword + template
prefix. Python outputs direct multiple inheritance. Java uses first base as extends,
rest as implements.
**Files modified:**
- `editor/src/ast/CppGeneratorTypes.h` — visitClassDeclaration: template prefix from
GenericType.isClassTemplate, multiple inheritance with access specifiers + virtual
- `editor/src/ast/PythonGenerator.h` — visitClassDeclaration: getBases() for multi-base
- `editor/src/ast/JavaGenerator.h` — visitClassDeclaration: extends + implements adaptation
- `editor/CMakeLists.txt` — step335_test target
**Files created:**
- `editor/tests/step335_test.cpp` — 12 tests: C++ multi-inheritance, access specifiers,
virtual, template class, CRTP, cross-language (Python/Java/Rust), variadic templates,
combined template + inheritance, method visibility, full roundtrip
--- ---
# Roadmap Planning — Sprints 12-25+ # Roadmap Planning — Sprints 12-25+