Step 362: C Generator (12/12 tests)
This commit is contained in:
@@ -2147,4 +2147,8 @@ target_link_libraries(step361_test PRIVATE
|
||||
tree_sitter_javascript tree_sitter_typescript
|
||||
tree_sitter_java tree_sitter_rust tree_sitter_go)
|
||||
|
||||
add_executable(step362_test tests/step362_test.cpp)
|
||||
target_include_directories(step362_test PRIVATE src)
|
||||
target_link_libraries(step362_test PRIVATE nlohmann_json::nlohmann_json)
|
||||
|
||||
# Step 12: Dear ImGui shell scaffolding created (main.cpp exists but not built due to dependencies)
|
||||
|
||||
@@ -159,6 +159,9 @@ public:
|
||||
} else if (language == "csharp") {
|
||||
CSharpGenerator gen;
|
||||
return gen.generate(ast);
|
||||
} else if (language == "c") {
|
||||
CGenerator gen;
|
||||
return gen.generate(ast);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
108
editor/src/ast/CGenerator.h
Normal file
108
editor/src/ast/CGenerator.h
Normal file
@@ -0,0 +1,108 @@
|
||||
#pragma once
|
||||
#include "ClassDeclaration.h"
|
||||
#include "GenericType.h"
|
||||
#include "AsyncNodes.h"
|
||||
#include "CppGenerator.h"
|
||||
|
||||
class CGenerator : public CppGenerator {
|
||||
public:
|
||||
std::string commentPrefix() const { return "// "; }
|
||||
|
||||
std::string generate(const ASTNode* node) override {
|
||||
return dispatchGenerate(this, node, "/* Unknown concept: ");
|
||||
}
|
||||
|
||||
std::string visitModule(const Module* module) override {
|
||||
std::ostringstream oss;
|
||||
for (auto* s : module->getChildren("statements")) oss << generate(s) << "\n";
|
||||
if (!module->getChildren("statements").empty()) oss << "\n";
|
||||
for (auto* c : module->getChildren("classes")) oss << generate(c) << "\n";
|
||||
for (auto* v : module->getChildren("variables")) oss << generate(v) << "\n";
|
||||
if (!module->getChildren("variables").empty()) oss << "\n";
|
||||
for (auto* f : module->getChildren("functions")) oss << generate(f) << "\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitClassDeclaration(const ASTNode* node) override {
|
||||
auto* cls = static_cast<const ClassDeclaration*>(node);
|
||||
std::ostringstream oss;
|
||||
oss << "typedef struct " << cls->name << " {\n";
|
||||
for (auto* f : cls->getChildren("fields")) {
|
||||
std::string line = generate(f);
|
||||
if (!line.empty() && line.back() == ';') line.pop_back();
|
||||
oss << " " << line << ";\n";
|
||||
}
|
||||
oss << "} " << cls->name << ";";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitMethodDeclaration(const ASTNode* node) override {
|
||||
auto* meth = static_cast<const MethodDeclaration*>(node);
|
||||
std::ostringstream oss;
|
||||
oss << "void " << meth->className << "_" << meth->name << "(";
|
||||
auto params = meth->getChildren("parameters");
|
||||
for (size_t i = 0; i < params.size(); ++i) {
|
||||
if (i > 0) oss << ", ";
|
||||
oss << visitParameter(static_cast<const Parameter*>(params[i]));
|
||||
}
|
||||
oss << ") {\n";
|
||||
for (auto* s : meth->getChildren("body")) oss << " " << generate(s) << "\n";
|
||||
oss << "}";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitNullLiteral(const NullLiteral* /*lit*/) override {
|
||||
return "NULL";
|
||||
}
|
||||
|
||||
std::string visitStringLiteral(const StringLiteral* lit) override {
|
||||
return "\"" + lit->value + "\"";
|
||||
}
|
||||
|
||||
std::string visitTypeAlias(const ASTNode* node) override {
|
||||
auto* ta = static_cast<const TypeAlias*>(node);
|
||||
return "typedef " + ta->targetType + " " + ta->aliasName + ";";
|
||||
}
|
||||
|
||||
std::string visitEnumDeclaration(const ASTNode* node) override {
|
||||
auto* e = static_cast<const EnumDeclaration*>(node);
|
||||
std::ostringstream oss;
|
||||
oss << "enum " << e->name << " { ";
|
||||
auto members = e->getChildren("members");
|
||||
for (size_t i = 0; i < members.size(); ++i) {
|
||||
auto* m = static_cast<const EnumMember*>(members[i]);
|
||||
if (i > 0) oss << ", ";
|
||||
oss << m->name;
|
||||
if (!m->value.empty()) oss << " = " << m->value;
|
||||
}
|
||||
oss << " };";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
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* p = static_cast<const PragmaDirective*>(node);
|
||||
return "#pragma " + p->directive;
|
||||
}
|
||||
|
||||
std::string visitMacroDefinition(const ASTNode* node) override {
|
||||
auto* m = static_cast<const MacroDefinition*>(node);
|
||||
std::ostringstream oss;
|
||||
oss << "#define " << m->name;
|
||||
if (m->isFunctionLike) {
|
||||
oss << "(";
|
||||
for (size_t i = 0; i < m->parameters.size(); ++i) {
|
||||
if (i > 0) oss << ", ";
|
||||
oss << m->parameters[i];
|
||||
}
|
||||
oss << ")";
|
||||
}
|
||||
if (!m->body.empty()) oss << " " << m->body;
|
||||
return oss.str();
|
||||
}
|
||||
};
|
||||
@@ -11,3 +11,4 @@
|
||||
#include "GoGenerator.h"
|
||||
#include "KotlinGenerator.h"
|
||||
#include "CSharpGenerator.h"
|
||||
#include "CGenerator.h"
|
||||
|
||||
164
editor/tests/step362_test.cpp
Normal file
164
editor/tests/step362_test.cpp
Normal file
@@ -0,0 +1,164 @@
|
||||
// Step 362: C Generator (12 tests)
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include "ast/CGenerator.h"
|
||||
#include "Pipeline.h"
|
||||
#include "ast/ClassDeclaration.h"
|
||||
#include "ast/EnumNamespaceNodes.h"
|
||||
#include "ast/PreprocessorNodes.h"
|
||||
#include "ast/Annotation.h"
|
||||
|
||||
int main() {
|
||||
int passed = 0;
|
||||
|
||||
// Test 1: function generation
|
||||
{
|
||||
CGenerator gen;
|
||||
Function fn("f1", "add");
|
||||
fn.setChild("returnType", new PrimitiveType("t1", "int"));
|
||||
fn.addChild("parameters", new Parameter("p1", "x"));
|
||||
auto* ret = new Return();
|
||||
ret->id = "r1";
|
||||
ret->setChild("value", new IntegerLiteral("i1", 1));
|
||||
fn.addChild("body", ret);
|
||||
auto out = gen.generate(&fn);
|
||||
assert(out.find("int add(") != std::string::npos);
|
||||
assert(out.find("return 1;") != std::string::npos);
|
||||
std::cout << "Test 1 PASSED: function generation\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 2: struct output from class
|
||||
{
|
||||
CGenerator gen;
|
||||
ClassDeclaration cls("c1", "Point");
|
||||
auto* x = new Variable("v1", "x");
|
||||
x->setChild("type", new PrimitiveType("t1", "int"));
|
||||
cls.addChild("fields", x);
|
||||
auto out = gen.generate(&cls);
|
||||
assert(out.find("typedef struct Point") != std::string::npos);
|
||||
assert(out.find("int x;") != std::string::npos);
|
||||
std::cout << "Test 2 PASSED: struct output\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 3: typedef output
|
||||
{
|
||||
CGenerator gen;
|
||||
TypeAlias ta("ta1", "Count", "unsigned int", false);
|
||||
auto out = gen.generate(&ta);
|
||||
assert(out == "typedef unsigned int Count;");
|
||||
std::cout << "Test 3 PASSED: typedef output\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 4: enum output
|
||||
{
|
||||
CGenerator gen;
|
||||
EnumDeclaration e("e1", "Color");
|
||||
e.addChild("members", new EnumMember("m1", "RED", "1"));
|
||||
e.addChild("members", new EnumMember("m2", "GREEN", "2"));
|
||||
auto out = gen.generate(&e);
|
||||
assert(out.find("enum Color") != std::string::npos);
|
||||
assert(out.find("RED = 1") != std::string::npos);
|
||||
std::cout << "Test 4 PASSED: enum output\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 5: preprocessor output
|
||||
{
|
||||
CGenerator gen;
|
||||
IncludeDirective inc("i1", "stdio.h", true);
|
||||
MacroDefinition mac("m1", "MAX");
|
||||
mac.body = "100";
|
||||
auto a = gen.generate(&inc);
|
||||
auto b = gen.generate(&mac);
|
||||
assert(a == "#include <stdio.h>");
|
||||
assert(b.find("#define MAX 100") != std::string::npos);
|
||||
std::cout << "Test 5 PASSED: preprocessor output\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 6: pointer type preserved
|
||||
{
|
||||
CGenerator gen;
|
||||
Variable v("v1", "name");
|
||||
v.setChild("type", new PrimitiveType("t1", "char*"));
|
||||
auto out = gen.generate(&v);
|
||||
assert(out.find("char* name;") != std::string::npos);
|
||||
std::cout << "Test 6 PASSED: pointer type\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 7: owner/manual annotation comment
|
||||
{
|
||||
CGenerator gen;
|
||||
Function fn("f1", "alloc");
|
||||
fn.setChild("returnType", new PrimitiveType("t1", "void*"));
|
||||
auto* owner = new OwnerAnnotation("a1", "Manual");
|
||||
fn.addChild("annotations", owner);
|
||||
auto out = gen.generate(&fn);
|
||||
assert(out.find("@owner") != std::string::npos || out.find("Owner") != std::string::npos);
|
||||
std::cout << "Test 7 PASSED: owner annotation comment\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 8: class (python-like) to c struct generation
|
||||
{
|
||||
CGenerator gen;
|
||||
ClassDeclaration cls("c1", "Widget");
|
||||
auto out = gen.generate(&cls);
|
||||
assert(out.find("typedef struct Widget") != std::string::npos);
|
||||
std::cout << "Test 8 PASSED: class to struct generation\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 9: c++ method to c-style function
|
||||
{
|
||||
CGenerator gen;
|
||||
MethodDeclaration m("m1", "render");
|
||||
m.className = "Widget";
|
||||
auto out = gen.generate(&m);
|
||||
assert(out.find("Widget_render(") != std::string::npos);
|
||||
std::cout << "Test 9 PASSED: method to c function naming\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 10: commentPrefix
|
||||
{
|
||||
CGenerator gen;
|
||||
assert(gen.commentPrefix() == "// ");
|
||||
std::cout << "Test 10 PASSED: comment prefix\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 11: C string literal + null
|
||||
{
|
||||
CGenerator gen;
|
||||
StringLiteral s("s1", "abc");
|
||||
NullLiteral n;
|
||||
auto a = gen.generate(&s);
|
||||
auto b = gen.generate(&n);
|
||||
assert(a == "\"abc\"");
|
||||
assert(b == "NULL");
|
||||
std::cout << "Test 11 PASSED: C string/null literal\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 12: pipeline generate route for c
|
||||
{
|
||||
Pipeline p;
|
||||
Function fn("f1", "work");
|
||||
std::string out = p.generate(&fn, "c");
|
||||
assert(!out.empty());
|
||||
assert(out.find("work(") != std::string::npos);
|
||||
std::cout << "Test 12 PASSED: pipeline generate route c\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
std::cout << "\nResults: " << passed << "/12\n";
|
||||
assert(passed == 12);
|
||||
return 0;
|
||||
}
|
||||
38
progress.md
38
progress.md
@@ -2085,6 +2085,44 @@ pipeline entry point in Sprint 14.
|
||||
- `step361_test` — PASS (12/12) new step coverage
|
||||
- `step360_test` — PASS (8/8) regression coverage
|
||||
|
||||
### Step 362: C Generator
|
||||
**Status:** PASS (12/12 tests)
|
||||
|
||||
Added a dedicated C generator and routed pipeline generation for `"c"`.
|
||||
The generator emits C-oriented forms for structs, enums, typedefs, macros,
|
||||
includes, and method-name lowering for class-style methods.
|
||||
|
||||
**Files created:**
|
||||
- `editor/src/ast/CGenerator.h` — C generation support:
|
||||
- module emission including statements/classes/functions
|
||||
- `ClassDeclaration` -> `typedef struct ...`
|
||||
- `MethodDeclaration` -> `ClassName_method(...)` naming
|
||||
- C null literal output (`NULL`)
|
||||
- C preprocessor and enum/type-alias output
|
||||
- `editor/tests/step362_test.cpp` — 12 tests covering:
|
||||
1. function generation
|
||||
2. struct output
|
||||
3. typedef output
|
||||
4. enum output
|
||||
5. preprocessor output
|
||||
6. pointer type output
|
||||
7. owner/manual annotation comment presence
|
||||
8. class-to-struct generation
|
||||
9. method-to-C function naming
|
||||
10. comment prefix
|
||||
11. string/null literal behavior
|
||||
12. pipeline `"c"` generation route
|
||||
|
||||
**Files modified:**
|
||||
- `editor/src/ast/Generator.h` — include `CGenerator.h`
|
||||
- `editor/src/Pipeline.h` — add generate routing for language `"c"`
|
||||
- `editor/CMakeLists.txt` — `step362_test` target
|
||||
|
||||
**Verification run:**
|
||||
- `step362_test` — PASS (12/12) new step coverage
|
||||
- `step361_test` — PASS (12/12) regression coverage
|
||||
- `step360_test` — PASS (8/8) regression coverage
|
||||
|
||||
# Roadmap Planning — Sprints 12-25+
|
||||
|
||||
## Status: Planning Complete (Sprints 12-19 detailed, 20-25 in roadmap.md)
|
||||
|
||||
Reference in New Issue
Block a user