Step 362: C Generator (12/12 tests)

This commit is contained in:
Bill
2026-02-16 09:31:12 -07:00
parent dbec5aa514
commit 31f12d0323
6 changed files with 318 additions and 0 deletions

View File

@@ -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)

View File

@@ -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
View 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();
}
};

View File

@@ -11,3 +11,4 @@
#include "GoGenerator.h"
#include "KotlinGenerator.h"
#include "CSharpGenerator.h"
#include "CGenerator.h"

View 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;
}

View File

@@ -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)