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:
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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]);
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|||||||
221
editor/tests/step335_test.cpp
Normal file
221
editor/tests/step335_test.cpp
Normal 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;
|
||||||
|
}
|
||||||
55
progress.md
55
progress.md
@@ -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+
|
||||||
|
|||||||
Reference in New Issue
Block a user