Step 340: C++ Generator — Preprocessor, Enum, Namespace (12/12 tests)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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<const IncludeDirective*>(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<const PragmaDirective*>(node);
|
||||
return "#pragma " + prag->directive;
|
||||
}
|
||||
|
||||
std::string visitMacroDefinition(const ASTNode* node) override {
|
||||
auto* mac = static_cast<const MacroDefinition*>(node);
|
||||
return "public const var " + mac->name + " = " + (mac->body.empty() ? "null" : mac->body) + ";";
|
||||
}
|
||||
|
||||
std::string visitEnumDeclaration(const ASTNode* node) override {
|
||||
auto* e = static_cast<const EnumDeclaration*>(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<const EnumMember*>(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<const NamespaceDeclaration*>(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<const TypeAlias*>(node);
|
||||
return "using " + ta->aliasName + " = " + ta->targetType + ";";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -320,6 +320,79 @@
|
||||
return "constexpr";
|
||||
}
|
||||
|
||||
// --- Preprocessor/Enum/Namespace visitors (Step 340) ---
|
||||
|
||||
std::string visitIncludeDirective(const ASTNode* node) override {
|
||||
auto* inc = static_cast<const IncludeDirective*>(node);
|
||||
if (inc->isSystem)
|
||||
return "#include <" + inc->path + ">";
|
||||
return "#include \"" + inc->path + "\"";
|
||||
}
|
||||
|
||||
std::string visitPragmaDirective(const ASTNode* node) override {
|
||||
auto* prag = static_cast<const PragmaDirective*>(node);
|
||||
return "#pragma " + prag->directive;
|
||||
}
|
||||
|
||||
std::string visitMacroDefinition(const ASTNode* node) override {
|
||||
auto* mac = static_cast<const MacroDefinition*>(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<const EnumDeclaration*>(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<const EnumMember*>(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<const NamespaceDeclaration*>(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<const TypeAlias*>(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 {
|
||||
|
||||
@@ -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<const IncludeDirective*>(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<const PragmaDirective*>(node);
|
||||
return ";; pragma " + prag->directive;
|
||||
}
|
||||
|
||||
std::string visitMacroDefinition(const ASTNode* node) override {
|
||||
auto* mac = static_cast<const MacroDefinition*>(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<const EnumDeclaration*>(node);
|
||||
std::ostringstream oss;
|
||||
auto members = e->getChildren("members");
|
||||
for (size_t i = 0; i < members.size(); ++i) {
|
||||
auto* m = static_cast<const EnumMember*>(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<const NamespaceDeclaration*>(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<const TypeAlias*>(node);
|
||||
return "(defalias '" + ta->aliasName + " '" + ta->targetType + ")";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -573,6 +573,53 @@ public:
|
||||
return "// @constexpr";
|
||||
}
|
||||
|
||||
// --- Preprocessor/Enum/Namespace visitors (Step 340) ---
|
||||
|
||||
std::string visitIncludeDirective(const ASTNode* node) override {
|
||||
auto* inc = static_cast<const IncludeDirective*>(node);
|
||||
return "import \"" + inc->path + "\"";
|
||||
}
|
||||
|
||||
std::string visitPragmaDirective(const ASTNode* node) override {
|
||||
auto* prag = static_cast<const PragmaDirective*>(node);
|
||||
return "// pragma " + prag->directive;
|
||||
}
|
||||
|
||||
std::string visitMacroDefinition(const ASTNode* node) override {
|
||||
auto* mac = static_cast<const MacroDefinition*>(node);
|
||||
return "const " + mac->name + " = " + (mac->body.empty() ? "0" : mac->body);
|
||||
}
|
||||
|
||||
std::string visitEnumDeclaration(const ASTNode* node) override {
|
||||
auto* e = static_cast<const EnumDeclaration*>(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<const EnumMember*>(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<const NamespaceDeclaration*>(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<const TypeAlias*>(node);
|
||||
return "type " + ta->aliasName + " = " + ta->targetType;
|
||||
}
|
||||
|
||||
private:
|
||||
static std::string emitImport(const Import* imp) {
|
||||
std::string moduleName = imp->moduleName.empty() ? "" : imp->moduleName;
|
||||
|
||||
@@ -652,6 +652,57 @@ public:
|
||||
return "// @constexpr";
|
||||
}
|
||||
|
||||
// --- Preprocessor/Enum/Namespace visitors (Step 340) ---
|
||||
|
||||
std::string visitIncludeDirective(const ASTNode* node) override {
|
||||
auto* inc = static_cast<const IncludeDirective*>(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<const PragmaDirective*>(node);
|
||||
return "// pragma " + prag->directive;
|
||||
}
|
||||
|
||||
std::string visitMacroDefinition(const ASTNode* node) override {
|
||||
auto* mac = static_cast<const MacroDefinition*>(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<const EnumDeclaration*>(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<const EnumMember*>(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<const NamespaceDeclaration*>(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<const TypeAlias*>(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;
|
||||
|
||||
@@ -624,6 +624,56 @@ public:
|
||||
return "// @constexpr";
|
||||
}
|
||||
|
||||
// --- Preprocessor/Enum/Namespace visitors (Step 340) ---
|
||||
|
||||
std::string visitIncludeDirective(const ASTNode* node) override {
|
||||
auto* inc = static_cast<const IncludeDirective*>(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<const PragmaDirective*>(node);
|
||||
return "// pragma " + prag->directive;
|
||||
}
|
||||
|
||||
std::string visitMacroDefinition(const ASTNode* node) override {
|
||||
auto* mac = static_cast<const MacroDefinition*>(node);
|
||||
return "const " + mac->name + " = " + (mac->body.empty() ? "undefined" : mac->body) + ";";
|
||||
}
|
||||
|
||||
std::string visitEnumDeclaration(const ASTNode* node) override {
|
||||
auto* e = static_cast<const EnumDeclaration*>(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<const EnumMember*>(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<const NamespaceDeclaration*>(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<const TypeAlias*>(node);
|
||||
return "/** @typedef {" + ta->targetType + "} " + ta->aliasName + " */";
|
||||
}
|
||||
|
||||
protected:
|
||||
bool includeTypes_ = false;
|
||||
|
||||
|
||||
@@ -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<const IncludeDirective*>(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<const PragmaDirective*>(node);
|
||||
return "// pragma " + prag->directive;
|
||||
}
|
||||
|
||||
std::string visitMacroDefinition(const ASTNode* node) override {
|
||||
auto* mac = static_cast<const MacroDefinition*>(node);
|
||||
return "const val " + mac->name + " = " + (mac->body.empty() ? "null" : mac->body);
|
||||
}
|
||||
|
||||
std::string visitEnumDeclaration(const ASTNode* node) override {
|
||||
auto* e = static_cast<const EnumDeclaration*>(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<const EnumMember*>(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<const NamespaceDeclaration*>(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<const TypeAlias*>(node);
|
||||
return "typealias " + ta->aliasName + " = " + ta->targetType;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<const IncludeDirective*>(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<const MacroDefinition*>(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<const EnumDeclaration*>(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<const EnumMember*>(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<const NamespaceDeclaration*>(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<const TypeAlias*>(node);
|
||||
return ta->aliasName + " = " + ta->targetType;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -607,6 +607,62 @@ public:
|
||||
return "// @constexpr";
|
||||
}
|
||||
|
||||
// --- Preprocessor/Enum/Namespace visitors (Step 340) ---
|
||||
|
||||
std::string visitIncludeDirective(const ASTNode* node) override {
|
||||
auto* inc = static_cast<const IncludeDirective*>(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<const PragmaDirective*>(node);
|
||||
return "#![" + prag->directive + "]";
|
||||
}
|
||||
|
||||
std::string visitMacroDefinition(const ASTNode* node) override {
|
||||
auto* mac = static_cast<const MacroDefinition*>(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<const EnumDeclaration*>(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<const EnumMember*>(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<const NamespaceDeclaration*>(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<const TypeAlias*>(node);
|
||||
return "type " + ta->aliasName + " = " + ta->targetType + ";";
|
||||
}
|
||||
|
||||
private:
|
||||
static std::string emitImport(const Import* imp) {
|
||||
std::string moduleName = imp->moduleName.empty() ? "crate" : imp->moduleName;
|
||||
|
||||
244
editor/tests/step340_test.cpp
Normal file
244
editor/tests/step340_test.cpp
Normal file
@@ -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 <cassert>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#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 <vector>");
|
||||
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<ASTNode>"; ta1.isUsing = true;
|
||||
TypeAlias ta2; ta2.aliasName = "NodeVec"; ta2.targetType = "std::vector<ASTNode*>"; ta2.isUsing = false;
|
||||
assert(gen.generate(&ta1) == "using NodePtr = std::shared_ptr<ASTNode>;");
|
||||
assert(gen.generate(&ta2) == "typedef std::vector<ASTNode*> 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;
|
||||
}
|
||||
Reference in New Issue
Block a user