From e958c778f3fefd836fa9d39f543e3ca15f6bf653 Mon Sep 17 00:00:00 2001 From: Bill Date: Mon, 16 Feb 2026 08:17:50 -0700 Subject: [PATCH] =?UTF-8?q?Step=20340:=20C++=20Generator=20=E2=80=94=20Pre?= =?UTF-8?q?processor,=20Enum,=20Namespace=20(12/12=20tests)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.6 --- editor/CMakeLists.txt | 9 + editor/src/ast/CSharpGenerator.h | 55 ++++++ editor/src/ast/CppGeneratorTypes.h | 73 ++++++++ editor/src/ast/ElispGenerator.h | 58 +++++++ editor/src/ast/GoGenerator.h | 47 ++++++ editor/src/ast/JavaGenerator.h | 51 ++++++ editor/src/ast/JavaScriptGenerator.h | 50 ++++++ editor/src/ast/KotlinGenerator.h | 51 ++++++ editor/src/ast/ProjectionGenerator.h | 24 +++ editor/src/ast/PythonGenerator.h | 58 +++++++ editor/src/ast/RustGenerator.h | 56 ++++++ editor/tests/step340_test.cpp | 244 +++++++++++++++++++++++++++ 12 files changed, 776 insertions(+) create mode 100644 editor/tests/step340_test.cpp diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index 74a546c..24e137e 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -2044,4 +2044,13 @@ target_link_libraries(step339_test PRIVATE tree_sitter_javascript tree_sitter_typescript tree_sitter_java tree_sitter_rust tree_sitter_go) +add_executable(step340_test tests/step340_test.cpp) +target_include_directories(step340_test PRIVATE src) +target_link_libraries(step340_test PRIVATE + nlohmann_json::nlohmann_json + unofficial::tree-sitter::tree-sitter + tree_sitter_python tree_sitter_cpp tree_sitter_elisp + tree_sitter_javascript tree_sitter_typescript + tree_sitter_java tree_sitter_rust tree_sitter_go) + # Step 12: Dear ImGui shell scaffolding created (main.cpp exists but not built due to dependencies) diff --git a/editor/src/ast/CSharpGenerator.h b/editor/src/ast/CSharpGenerator.h index 26d2d58..d87a0b8 100644 --- a/editor/src/ast/CSharpGenerator.h +++ b/editor/src/ast/CSharpGenerator.h @@ -354,4 +354,59 @@ public: std::string visitInlineAnnotation(const InlineAnnotation* a) override { return semanno(a); } std::string visitPureAnnotation(const PureAnnotation* a) override { return semanno(a); } std::string visitConstExprAnnotation(const ConstExprAnnotation* a) override { return semanno(a); } + + // --- Preprocessor/Enum/Namespace visitors (Step 340) --- + + std::string visitIncludeDirective(const ASTNode* node) override { + auto* inc = static_cast(node); + std::string mod = inc->path; + auto dot = mod.rfind('.'); + if (dot != std::string::npos) mod = mod.substr(0, dot); + for (auto& c : mod) { if (c == '/' || c == '\\') c = '.'; } + return "using " + mod + ";"; + } + + std::string visitPragmaDirective(const ASTNode* node) override { + auto* prag = static_cast(node); + return "#pragma " + prag->directive; + } + + std::string visitMacroDefinition(const ASTNode* node) override { + auto* mac = static_cast(node); + return "public const var " + mac->name + " = " + (mac->body.empty() ? "null" : mac->body) + ";"; + } + + std::string visitEnumDeclaration(const ASTNode* node) override { + auto* e = static_cast(node); + std::ostringstream oss; + oss << "enum " << e->name; + if (!e->underlyingType.empty()) oss << " : " << e->underlyingType; + oss << "\n{\n"; + auto members = e->getChildren("members"); + for (size_t i = 0; i < members.size(); ++i) { + auto* m = static_cast(members[i]); + oss << " " << m->name; + if (!m->value.empty()) oss << " = " << m->value; + if (i + 1 < members.size()) oss << ","; + oss << "\n"; + } + oss << "}"; + return oss.str(); + } + + std::string visitNamespaceDeclaration(const ASTNode* node) override { + auto* ns = static_cast(node); + std::ostringstream oss; + oss << "namespace " << ns->name << "\n{\n"; + auto body = ns->getChildren("body"); + for (const auto* child : body) + oss << " " << generate(child) << "\n"; + oss << "}"; + return oss.str(); + } + + std::string visitTypeAlias(const ASTNode* node) override { + auto* ta = static_cast(node); + return "using " + ta->aliasName + " = " + ta->targetType + ";"; + } }; diff --git a/editor/src/ast/CppGeneratorTypes.h b/editor/src/ast/CppGeneratorTypes.h index 839e0b4..cd04599 100644 --- a/editor/src/ast/CppGeneratorTypes.h +++ b/editor/src/ast/CppGeneratorTypes.h @@ -320,6 +320,79 @@ return "constexpr"; } + // --- Preprocessor/Enum/Namespace visitors (Step 340) --- + + std::string visitIncludeDirective(const ASTNode* node) override { + auto* inc = static_cast(node); + if (inc->isSystem) + return "#include <" + inc->path + ">"; + return "#include \"" + inc->path + "\""; + } + + std::string visitPragmaDirective(const ASTNode* node) override { + auto* prag = static_cast(node); + return "#pragma " + prag->directive; + } + + std::string visitMacroDefinition(const ASTNode* node) override { + auto* mac = static_cast(node); + std::ostringstream oss; + oss << "#define " << mac->name; + if (mac->isFunctionLike) { + oss << "("; + for (size_t i = 0; i < mac->parameters.size(); ++i) { + if (i > 0) oss << ", "; + oss << mac->parameters[i]; + } + oss << ")"; + } + if (!mac->body.empty()) oss << " " << mac->body; + return oss.str(); + } + + std::string visitEnumDeclaration(const ASTNode* node) override { + auto* e = static_cast(node); + std::ostringstream oss; + if (e->isScoped) + oss << "enum class " << e->name; + else + oss << "enum " << e->name; + if (!e->underlyingType.empty()) + oss << " : " << e->underlyingType; + oss << " {\n"; + auto members = e->getChildren("members"); + for (size_t i = 0; i < members.size(); ++i) { + auto* m = static_cast(members[i]); + oss << " " << m->name; + if (!m->value.empty()) oss << " = " << m->value; + if (i + 1 < members.size()) oss << ","; + oss << "\n"; + } + oss << "};\n"; + return oss.str(); + } + + std::string visitNamespaceDeclaration(const ASTNode* node) override { + auto* ns = static_cast(node); + std::ostringstream oss; + if (ns->name.empty()) + oss << "namespace {\n"; + else + oss << "namespace " << ns->name << " {\n"; + auto body = ns->getChildren("body"); + for (const auto* child : body) + oss << " " << generate(child) << "\n"; + oss << "}\n"; + return oss.str(); + } + + std::string visitTypeAlias(const ASTNode* node) override { + auto* ta = static_cast(node); + if (ta->isUsing) + return "using " + ta->aliasName + " = " + ta->targetType + ";"; + return "typedef " + ta->targetType + " " + ta->aliasName + ";"; + } + private: // Check enclosing function's memory annotations to determine smart-pointer wrapper std::string getMemoryTypeWrapper(const Variable* variable) const { diff --git a/editor/src/ast/ElispGenerator.h b/editor/src/ast/ElispGenerator.h index b55828a..e913b71 100644 --- a/editor/src/ast/ElispGenerator.h +++ b/editor/src/ast/ElispGenerator.h @@ -665,4 +665,62 @@ public: std::string visitConstExprAnnotation(const ConstExprAnnotation*) override { return "; @constexpr - Compile-time evaluable"; } + + // --- Preprocessor/Enum/Namespace visitors (Step 340) --- + + std::string visitIncludeDirective(const ASTNode* node) override { + auto* inc = static_cast(node); + std::string mod = inc->path; + auto dot = mod.rfind('.'); + if (dot != std::string::npos) mod = mod.substr(0, dot); + return "(require '" + mod + ")"; + } + + std::string visitPragmaDirective(const ASTNode* node) override { + auto* prag = static_cast(node); + return ";; pragma " + prag->directive; + } + + std::string visitMacroDefinition(const ASTNode* node) override { + auto* mac = static_cast(node); + if (mac->isFunctionLike) { + std::ostringstream oss; + oss << "(defmacro " << mac->name << " ("; + for (size_t i = 0; i < mac->parameters.size(); ++i) { + if (i > 0) oss << " "; + oss << mac->parameters[i]; + } + oss << ")\n " << (mac->body.empty() ? "nil" : mac->body) << ")"; + return oss.str(); + } + return "(defconst " + mac->name + " " + (mac->body.empty() ? "nil" : mac->body) + ")"; + } + + std::string visitEnumDeclaration(const ASTNode* node) override { + auto* e = static_cast(node); + std::ostringstream oss; + auto members = e->getChildren("members"); + for (size_t i = 0; i < members.size(); ++i) { + auto* m = static_cast(members[i]); + oss << "(defconst " << e->name << "-" << m->name << " " + << (m->value.empty() ? std::to_string(i) : m->value) << ")"; + if (i + 1 < members.size()) oss << "\n"; + } + return oss.str(); + } + + std::string visitNamespaceDeclaration(const ASTNode* node) override { + auto* ns = static_cast(node); + std::ostringstream oss; + oss << ";; namespace " << ns->name << "\n"; + auto body = ns->getChildren("body"); + for (const auto* child : body) + oss << generate(child) << "\n"; + return oss.str(); + } + + std::string visitTypeAlias(const ASTNode* node) override { + auto* ta = static_cast(node); + return "(defalias '" + ta->aliasName + " '" + ta->targetType + ")"; + } }; diff --git a/editor/src/ast/GoGenerator.h b/editor/src/ast/GoGenerator.h index 71d5988..b08ac09 100644 --- a/editor/src/ast/GoGenerator.h +++ b/editor/src/ast/GoGenerator.h @@ -573,6 +573,53 @@ public: return "// @constexpr"; } + // --- Preprocessor/Enum/Namespace visitors (Step 340) --- + + std::string visitIncludeDirective(const ASTNode* node) override { + auto* inc = static_cast(node); + return "import \"" + inc->path + "\""; + } + + std::string visitPragmaDirective(const ASTNode* node) override { + auto* prag = static_cast(node); + return "// pragma " + prag->directive; + } + + std::string visitMacroDefinition(const ASTNode* node) override { + auto* mac = static_cast(node); + return "const " + mac->name + " = " + (mac->body.empty() ? "0" : mac->body); + } + + std::string visitEnumDeclaration(const ASTNode* node) override { + auto* e = static_cast(node); + std::ostringstream oss; + oss << "type " << e->name << " int\n\nconst (\n"; + auto members = e->getChildren("members"); + for (size_t i = 0; i < members.size(); ++i) { + auto* m = static_cast(members[i]); + oss << " " << m->name; + if (i == 0) oss << " " << e->name << " = iota"; + oss << "\n"; + } + oss << ")"; + return oss.str(); + } + + std::string visitNamespaceDeclaration(const ASTNode* node) override { + auto* ns = static_cast(node); + std::ostringstream oss; + oss << "package " << ns->name << "\n"; + auto body = ns->getChildren("body"); + for (const auto* child : body) + oss << generate(child) << "\n"; + return oss.str(); + } + + std::string visitTypeAlias(const ASTNode* node) override { + auto* ta = static_cast(node); + return "type " + ta->aliasName + " = " + ta->targetType; + } + private: static std::string emitImport(const Import* imp) { std::string moduleName = imp->moduleName.empty() ? "" : imp->moduleName; diff --git a/editor/src/ast/JavaGenerator.h b/editor/src/ast/JavaGenerator.h index a6253f2..1de2b6c 100644 --- a/editor/src/ast/JavaGenerator.h +++ b/editor/src/ast/JavaGenerator.h @@ -652,6 +652,57 @@ public: return "// @constexpr"; } + // --- Preprocessor/Enum/Namespace visitors (Step 340) --- + + std::string visitIncludeDirective(const ASTNode* node) override { + auto* inc = static_cast(node); + std::string mod = inc->path; + auto dot = mod.rfind('.'); + if (dot != std::string::npos) mod = mod.substr(0, dot); + for (auto& c : mod) { if (c == '/' || c == '\\') c = '.'; } + return "import " + mod + ";"; + } + + std::string visitPragmaDirective(const ASTNode* node) override { + auto* prag = static_cast(node); + return "// pragma " + prag->directive; + } + + std::string visitMacroDefinition(const ASTNode* node) override { + auto* mac = static_cast(node); + return "public static final var " + mac->name + " = " + (mac->body.empty() ? "null" : mac->body) + ";"; + } + + std::string visitEnumDeclaration(const ASTNode* node) override { + auto* e = static_cast(node); + std::ostringstream oss; + oss << "enum " << e->name << " {\n"; + auto members = e->getChildren("members"); + for (size_t i = 0; i < members.size(); ++i) { + auto* m = static_cast(members[i]); + oss << " " << m->name; + if (i + 1 < members.size()) oss << ","; + oss << "\n"; + } + oss << "}\n"; + return oss.str(); + } + + std::string visitNamespaceDeclaration(const ASTNode* node) override { + auto* ns = static_cast(node); + std::ostringstream oss; + oss << "package " << ns->name << ";\n"; + auto body = ns->getChildren("body"); + for (const auto* child : body) + oss << generate(child) << "\n"; + return oss.str(); + } + + std::string visitTypeAlias(const ASTNode* node) override { + auto* ta = static_cast(node); + return "// type alias: " + ta->aliasName + " = " + ta->targetType; + } + private: static std::string emitImport(const Import* imp) { std::string moduleName = imp->moduleName.empty() ? "module" : imp->moduleName; diff --git a/editor/src/ast/JavaScriptGenerator.h b/editor/src/ast/JavaScriptGenerator.h index 9626082..605608b 100644 --- a/editor/src/ast/JavaScriptGenerator.h +++ b/editor/src/ast/JavaScriptGenerator.h @@ -624,6 +624,56 @@ public: return "// @constexpr"; } + // --- Preprocessor/Enum/Namespace visitors (Step 340) --- + + std::string visitIncludeDirective(const ASTNode* node) override { + auto* inc = static_cast(node); + std::string mod = inc->path; + auto dot = mod.rfind('.'); + if (dot != std::string::npos) mod = mod.substr(0, dot); + return "import '" + mod + "';"; + } + + std::string visitPragmaDirective(const ASTNode* node) override { + auto* prag = static_cast(node); + return "// pragma " + prag->directive; + } + + std::string visitMacroDefinition(const ASTNode* node) override { + auto* mac = static_cast(node); + return "const " + mac->name + " = " + (mac->body.empty() ? "undefined" : mac->body) + ";"; + } + + std::string visitEnumDeclaration(const ASTNode* node) override { + auto* e = static_cast(node); + std::ostringstream oss; + oss << "const " << e->name << " = Object.freeze({\n"; + auto members = e->getChildren("members"); + for (size_t i = 0; i < members.size(); ++i) { + auto* m = static_cast(members[i]); + oss << " " << m->name << ": " << (m->value.empty() ? std::to_string(i) : m->value); + if (i + 1 < members.size()) oss << ","; + oss << "\n"; + } + oss << "});"; + return oss.str(); + } + + std::string visitNamespaceDeclaration(const ASTNode* node) override { + auto* ns = static_cast(node); + std::ostringstream oss; + oss << "// namespace " << ns->name << "\n"; + auto body = ns->getChildren("body"); + for (const auto* child : body) + oss << generate(child) << "\n"; + return oss.str(); + } + + std::string visitTypeAlias(const ASTNode* node) override { + auto* ta = static_cast(node); + return "/** @typedef {" + ta->targetType + "} " + ta->aliasName + " */"; + } + protected: bool includeTypes_ = false; diff --git a/editor/src/ast/KotlinGenerator.h b/editor/src/ast/KotlinGenerator.h index 4e323ec..aa54fa3 100644 --- a/editor/src/ast/KotlinGenerator.h +++ b/editor/src/ast/KotlinGenerator.h @@ -374,4 +374,55 @@ public: std::string visitInlineAnnotation(const InlineAnnotation* a) override { return semanno(a); } std::string visitPureAnnotation(const PureAnnotation* a) override { return semanno(a); } std::string visitConstExprAnnotation(const ConstExprAnnotation* a) override { return semanno(a); } + + // --- Preprocessor/Enum/Namespace visitors (Step 340) --- + + std::string visitIncludeDirective(const ASTNode* node) override { + auto* inc = static_cast(node); + std::string mod = inc->path; + auto dot = mod.rfind('.'); + if (dot != std::string::npos) mod = mod.substr(0, dot); + for (auto& c : mod) { if (c == '/' || c == '\\') c = '.'; } + return "import " + mod; + } + + std::string visitPragmaDirective(const ASTNode* node) override { + auto* prag = static_cast(node); + return "// pragma " + prag->directive; + } + + std::string visitMacroDefinition(const ASTNode* node) override { + auto* mac = static_cast(node); + return "const val " + mac->name + " = " + (mac->body.empty() ? "null" : mac->body); + } + + std::string visitEnumDeclaration(const ASTNode* node) override { + auto* e = static_cast(node); + std::ostringstream oss; + oss << "enum class " << e->name << " {\n"; + auto members = e->getChildren("members"); + for (size_t i = 0; i < members.size(); ++i) { + auto* m = static_cast(members[i]); + oss << " " << m->name; + if (i + 1 < members.size()) oss << ","; + oss << "\n"; + } + oss << "}"; + return oss.str(); + } + + std::string visitNamespaceDeclaration(const ASTNode* node) override { + auto* ns = static_cast(node); + std::ostringstream oss; + oss << "package " << ns->name << "\n"; + auto body = ns->getChildren("body"); + for (const auto* child : body) + oss << generate(child) << "\n"; + return oss.str(); + } + + std::string visitTypeAlias(const ASTNode* node) override { + auto* ta = static_cast(node); + return "typealias " + ta->aliasName + " = " + ta->targetType; + } }; diff --git a/editor/src/ast/ProjectionGenerator.h b/editor/src/ast/ProjectionGenerator.h index cd5aab7..449e44f 100644 --- a/editor/src/ast/ProjectionGenerator.h +++ b/editor/src/ast/ProjectionGenerator.h @@ -14,6 +14,8 @@ #include "Annotation.h" #include "AnnotationVisitors.h" #include "HostBoundary.h" +#include "PreprocessorNodes.h" +#include "EnumNamespaceNodes.h" class ProjectionGenerator : public virtual AnnotationVisitorExtended { public: @@ -75,6 +77,14 @@ public: virtual std::string visitLambdaExpression(const ASTNode* node) { return ""; } virtual std::string visitDecoratorAnnotation(const ASTNode* node) { return ""; } + // Preprocessor/Enum/Namespace visitors (Step 340) + virtual std::string visitIncludeDirective(const ASTNode* node) { return ""; } + virtual std::string visitPragmaDirective(const ASTNode* node) { return ""; } + virtual std::string visitMacroDefinition(const ASTNode* node) { return ""; } + virtual std::string visitEnumDeclaration(const ASTNode* node) { return ""; } + virtual std::string visitNamespaceDeclaration(const ASTNode* node) { return ""; } + virtual std::string visitTypeAlias(const ASTNode* node) { return ""; } + // Host boundary visitors virtual std::string visitHostCall(const HostCall* node) { return ""; } virtual std::string visitScheduleTask(const ScheduleTask* node) { return ""; } @@ -350,6 +360,20 @@ std::string dispatchGenerate(Gen* gen, const ASTNode* node, const std::string& u } else if (node->conceptType == "DecoratorAnnotation") { return gen->visitDecoratorAnnotation(node); } + // Preprocessor/Enum/Namespace dispatch (Step 340) + else if (node->conceptType == "IncludeDirective") { + return gen->visitIncludeDirective(node); + } else if (node->conceptType == "PragmaDirective") { + return gen->visitPragmaDirective(node); + } else if (node->conceptType == "MacroDefinition") { + return gen->visitMacroDefinition(node); + } else if (node->conceptType == "EnumDeclaration") { + return gen->visitEnumDeclaration(node); + } else if (node->conceptType == "NamespaceDeclaration") { + return gen->visitNamespaceDeclaration(node); + } else if (node->conceptType == "TypeAlias") { + return gen->visitTypeAlias(node); + } return unknownPrefix + node->conceptType; } diff --git a/editor/src/ast/PythonGenerator.h b/editor/src/ast/PythonGenerator.h index c842e22..0624169 100644 --- a/editor/src/ast/PythonGenerator.h +++ b/editor/src/ast/PythonGenerator.h @@ -727,4 +727,62 @@ public: std::string visitConstExprAnnotation(const ConstExprAnnotation*) override { return "# @constexpr - Compile-time evaluable"; } + + // --- Preprocessor/Enum/Namespace visitors (Step 340) --- + + std::string visitIncludeDirective(const ASTNode* node) override { + auto* inc = static_cast(node); + std::string mod = inc->path; + auto dot = mod.rfind('.'); + if (dot != std::string::npos) mod = mod.substr(0, dot); + for (auto& c : mod) { if (c == '/' || c == '\\') c = '.'; } + return "import " + mod; + } + + std::string visitPragmaDirective(const ASTNode*) override { + return "# pragma (no Python equivalent)"; + } + + std::string visitMacroDefinition(const ASTNode* node) override { + auto* mac = static_cast(node); + if (mac->isFunctionLike) { + std::ostringstream oss; + oss << "def " << mac->name << "("; + for (size_t i = 0; i < mac->parameters.size(); ++i) { + if (i > 0) oss << ", "; + oss << mac->parameters[i]; + } + oss << "):\n return " << (mac->body.empty() ? "None" : mac->body); + return oss.str(); + } + return mac->name + " = " + (mac->body.empty() ? "None" : mac->body); + } + + std::string visitEnumDeclaration(const ASTNode* node) override { + auto* e = static_cast(node); + std::ostringstream oss; + oss << "class " << e->name << "(Enum):\n"; + auto members = e->getChildren("members"); + for (size_t i = 0; i < members.size(); ++i) { + auto* m = static_cast(members[i]); + oss << " " << m->name << " = " << (m->value.empty() ? std::to_string(i) : m->value) << "\n"; + } + if (members.empty()) oss << " pass\n"; + return oss.str(); + } + + std::string visitNamespaceDeclaration(const ASTNode* node) override { + auto* ns = static_cast(node); + std::ostringstream oss; + oss << "# namespace " << ns->name << "\n"; + auto body = ns->getChildren("body"); + for (const auto* child : body) + oss << generate(child) << "\n"; + return oss.str(); + } + + std::string visitTypeAlias(const ASTNode* node) override { + auto* ta = static_cast(node); + return ta->aliasName + " = " + ta->targetType; + } }; diff --git a/editor/src/ast/RustGenerator.h b/editor/src/ast/RustGenerator.h index b2141df..0c016ad 100644 --- a/editor/src/ast/RustGenerator.h +++ b/editor/src/ast/RustGenerator.h @@ -607,6 +607,62 @@ public: return "// @constexpr"; } + // --- Preprocessor/Enum/Namespace visitors (Step 340) --- + + std::string visitIncludeDirective(const ASTNode* node) override { + auto* inc = static_cast(node); + std::string mod = inc->path; + auto dot = mod.rfind('.'); + if (dot != std::string::npos) mod = mod.substr(0, dot); + for (auto& c : mod) { if (c == '/' || c == '\\') c = ':'; } + return "use " + mod + ";"; + } + + std::string visitPragmaDirective(const ASTNode* node) override { + auto* prag = static_cast(node); + return "#![" + prag->directive + "]"; + } + + std::string visitMacroDefinition(const ASTNode* node) override { + auto* mac = static_cast(node); + std::ostringstream oss; + oss << "macro_rules! " << mac->name << " {\n"; + oss << " () => { " << (mac->body.empty() ? "" : mac->body) << " };\n"; + oss << "}"; + return oss.str(); + } + + std::string visitEnumDeclaration(const ASTNode* node) override { + auto* e = static_cast(node); + std::ostringstream oss; + oss << "enum " << e->name << " {\n"; + auto members = e->getChildren("members"); + for (size_t i = 0; i < members.size(); ++i) { + auto* m = static_cast(members[i]); + oss << " " << m->name; + if (!m->value.empty()) oss << " = " << m->value; + oss << ",\n"; + } + oss << "}"; + return oss.str(); + } + + std::string visitNamespaceDeclaration(const ASTNode* node) override { + auto* ns = static_cast(node); + std::ostringstream oss; + oss << "mod " << ns->name << " {\n"; + auto body = ns->getChildren("body"); + for (const auto* child : body) + oss << " " << generate(child) << "\n"; + oss << "}"; + return oss.str(); + } + + std::string visitTypeAlias(const ASTNode* node) override { + auto* ta = static_cast(node); + return "type " + ta->aliasName + " = " + ta->targetType + ";"; + } + private: static std::string emitImport(const Import* imp) { std::string moduleName = imp->moduleName.empty() ? "crate" : imp->moduleName; diff --git a/editor/tests/step340_test.cpp b/editor/tests/step340_test.cpp new file mode 100644 index 0000000..0210704 --- /dev/null +++ b/editor/tests/step340_test.cpp @@ -0,0 +1,244 @@ +// Step 340: C++ Generator — Preprocessor, Enum, Namespace (12 tests) +// Tests code generation for preprocessor directives, enums, namespaces, type aliases +// across all 10 generators (C++, Python, Java, Rust, Go, JS, Elisp, Kotlin, C#, + TS inherits JS) + +#include +#include +#include +#include "ast/PreprocessorNodes.h" +#include "ast/EnumNamespaceNodes.h" +#include "ast/Serialization.h" +#include "ast/PythonGenerator.h" +#include "ast/CppGenerator.h" +#include "ast/JavaGenerator.h" +#include "ast/RustGenerator.h" +#include "ast/GoGenerator.h" +#include "ast/JavaScriptGenerator.h" +#include "ast/ElispGenerator.h" +#include "ast/KotlinGenerator.h" +#include "ast/CSharpGenerator.h" + +int main() { + int passed = 0; + + // Test 1: C++ #include output (system vs local) + { + CppGenerator gen; + IncludeDirective inc1; inc1.path = "vector"; inc1.isSystem = true; + IncludeDirective inc2; inc2.path = "ast/ASTNode.h"; inc2.isSystem = false; + std::string out1 = gen.generate(&inc1); + std::string out2 = gen.generate(&inc2); + assert(out1 == "#include "); + assert(out2 == "#include \"ast/ASTNode.h\""); + std::cout << "Test 1 PASSED: C++ #include output\n"; + passed++; + } + + // Test 2: C++ enum class output + { + CppGenerator gen; + EnumDeclaration e; e.name = "Color"; e.isScoped = true; e.underlyingType = "int"; + e.addChild("members", new EnumMember("m1", "Red", "0")); + e.addChild("members", new EnumMember("m2", "Green", "1")); + e.addChild("members", new EnumMember("m3", "Blue", "2")); + std::string out = gen.generate(&e); + assert(out.find("enum class Color : int") != std::string::npos); + assert(out.find("Red = 0") != std::string::npos); + assert(out.find("Green = 1") != std::string::npos); + assert(out.find("Blue = 2") != std::string::npos); + std::cout << "Test 2 PASSED: C++ enum class output\n"; + passed++; + } + + // Test 3: C++ namespace output + { + CppGenerator gen; + NamespaceDeclaration ns; ns.name = "whetstone"; + auto* func = new Function(); func->name = "helper"; + ns.addChild("body", func); + std::string out = gen.generate(&ns); + assert(out.find("namespace whetstone {") != std::string::npos); + assert(out.find("helper") != std::string::npos); + assert(out.find("}") != std::string::npos); + std::cout << "Test 3 PASSED: C++ namespace output\n"; + passed++; + } + + // Test 4: Python enum → class(Enum) output + { + PythonGenerator gen; + EnumDeclaration e; e.name = "Color"; e.isScoped = true; + e.addChild("members", new EnumMember("m1", "RED", "1")); + e.addChild("members", new EnumMember("m2", "GREEN", "2")); + std::string out = gen.generate(&e); + assert(out.find("class Color(Enum)") != std::string::npos); + assert(out.find("RED = 1") != std::string::npos); + assert(out.find("GREEN = 2") != std::string::npos); + std::cout << "Test 4 PASSED: Python enum output\n"; + passed++; + } + + // Test 5: Java enum output + { + JavaGenerator gen; + EnumDeclaration e; e.name = "Status"; + e.addChild("members", new EnumMember("m1", "ACTIVE")); + e.addChild("members", new EnumMember("m2", "INACTIVE")); + std::string out = gen.generate(&e); + assert(out.find("enum Status") != std::string::npos); + assert(out.find("ACTIVE") != std::string::npos); + assert(out.find("INACTIVE") != std::string::npos); + std::cout << "Test 5 PASSED: Java enum output\n"; + passed++; + } + + // Test 6: Rust enum output + { + RustGenerator gen; + EnumDeclaration e; e.name = "Direction"; + e.addChild("members", new EnumMember("m1", "North", "0")); + e.addChild("members", new EnumMember("m2", "South", "1")); + std::string out = gen.generate(&e); + assert(out.find("enum Direction") != std::string::npos); + assert(out.find("North = 0") != std::string::npos); + assert(out.find("South = 1") != std::string::npos); + std::cout << "Test 6 PASSED: Rust enum output\n"; + passed++; + } + + // Test 7: Go enum → iota output + { + GoGenerator gen; + EnumDeclaration e; e.name = "Color"; + e.addChild("members", new EnumMember("m1", "Red")); + e.addChild("members", new EnumMember("m2", "Green")); + std::string out = gen.generate(&e); + assert(out.find("type Color int") != std::string::npos); + assert(out.find("iota") != std::string::npos); + assert(out.find("Red") != std::string::npos); + std::cout << "Test 7 PASSED: Go enum → iota output\n"; + passed++; + } + + // Test 8: Cross-language include adaptation (C++ → Python, Java, Rust, Go, JS) + { + IncludeDirective inc; inc.path = "ast/ASTNode.h"; inc.isSystem = false; + + PythonGenerator pyGen; + assert(pyGen.generate(&inc).find("import") != std::string::npos); + + JavaGenerator javaGen; + assert(javaGen.generate(&inc).find("import") != std::string::npos); + + RustGenerator rustGen; + assert(rustGen.generate(&inc).find("use") != std::string::npos); + + GoGenerator goGen; + assert(goGen.generate(&inc).find("import") != std::string::npos); + + JavaScriptGenerator jsGen; + assert(jsGen.generate(&inc).find("import") != std::string::npos); + + ElispGenerator elispGen; + assert(elispGen.generate(&inc).find("require") != std::string::npos); + + KotlinGenerator ktGen; + assert(ktGen.generate(&inc).find("import") != std::string::npos); + + CSharpGenerator csGen; + assert(csGen.generate(&inc).find("using") != std::string::npos); + + std::cout << "Test 8 PASSED: Cross-language include adaptation (8 generators)\n"; + passed++; + } + + // Test 9: C++ using alias and typedef + { + CppGenerator gen; + TypeAlias ta1; ta1.aliasName = "NodePtr"; ta1.targetType = "std::shared_ptr"; ta1.isUsing = true; + TypeAlias ta2; ta2.aliasName = "NodeVec"; ta2.targetType = "std::vector"; ta2.isUsing = false; + assert(gen.generate(&ta1) == "using NodePtr = std::shared_ptr;"); + assert(gen.generate(&ta2) == "typedef std::vector NodeVec;"); + std::cout << "Test 9 PASSED: C++ using alias and typedef\n"; + passed++; + } + + // Test 10: Kotlin enum class + C# enum output + { + KotlinGenerator ktGen; + EnumDeclaration e1; e1.name = "Level"; + e1.addChild("members", new EnumMember("m1", "LOW")); + e1.addChild("members", new EnumMember("m2", "HIGH")); + std::string ktOut = ktGen.generate(&e1); + assert(ktOut.find("enum class Level") != std::string::npos); + assert(ktOut.find("LOW") != std::string::npos); + + CSharpGenerator csGen; + EnumDeclaration e2; e2.name = "Level"; e2.underlyingType = "byte"; + e2.addChild("members", new EnumMember("m1", "Low", "1")); + e2.addChild("members", new EnumMember("m2", "High", "2")); + std::string csOut = csGen.generate(&e2); + assert(csOut.find("enum Level : byte") != std::string::npos); + assert(csOut.find("Low = 1") != std::string::npos); + + std::cout << "Test 10 PASSED: Kotlin + C# enum output\n"; + passed++; + } + + // Test 11: C++ #pragma and #define output + { + CppGenerator gen; + PragmaDirective prag; prag.directive = "once"; + assert(gen.generate(&prag) == "#pragma once"); + + MacroDefinition mac; mac.name = "MAX"; mac.isFunctionLike = true; + mac.parameters = {"a", "b"}; + mac.body = "((a) > (b) ? (a) : (b))"; + std::string macOut = gen.generate(&mac); + assert(macOut.find("#define MAX(a, b)") != std::string::npos); + assert(macOut.find("((a) > (b) ? (a) : (b))") != std::string::npos); + + std::cout << "Test 11 PASSED: C++ #pragma and #define output\n"; + passed++; + } + + // Test 12: All 9 generators produce non-empty output for all 6 new types + { + IncludeDirective inc; inc.path = "header.h"; inc.isSystem = false; + PragmaDirective prag; prag.directive = "once"; + MacroDefinition mac; mac.name = "FOO"; mac.body = "42"; + EnumDeclaration enumDecl; enumDecl.name = "E"; + enumDecl.addChild("members", new EnumMember("m1", "A")); + NamespaceDeclaration ns; ns.name = "ns"; + TypeAlias ta; ta.aliasName = "Alias"; ta.targetType = "int"; ta.isUsing = true; + + const ASTNode* nodes[] = {&inc, &prag, &mac, &enumDecl, &ns, &ta}; + + CppGenerator cppGen; + PythonGenerator pyGen; + JavaGenerator javaGen; + RustGenerator rustGen; + GoGenerator goGen; + JavaScriptGenerator jsGen; + ElispGenerator elispGen; + KotlinGenerator ktGen; + CSharpGenerator csGen; + + ProjectionGenerator* gens[] = {&cppGen, &pyGen, &javaGen, &rustGen, &goGen, &jsGen, &elispGen, &ktGen, &csGen}; + + int nonEmpty = 0; + for (int g = 0; g < 9; g++) { + for (int n = 0; n < 6; n++) { + std::string out = gens[g]->generate(nodes[n]); + if (!out.empty()) nonEmpty++; + } + } + assert(nonEmpty == 54); + std::cout << "Test 12 PASSED: All 9 generators produce non-empty output for all 6 types (" << nonEmpty << "/54)\n"; + passed++; + } + + std::cout << "\nResults: " << passed << "/12\n"; + assert(passed == 12); + return 0; +}