2026-02-09 14:47:51 -07:00
|
|
|
#pragma once
|
|
|
|
|
#include "ProjectionGenerator.h"
|
Step 308: All 8 generators produce language-appropriate output for 9 new AST node types (8/8 tests)
Phase 11c complete (80/80 tests). Added visitor implementations for
ClassDeclaration, InterfaceDeclaration, MethodDeclaration, GenericType,
TypeParameter, AsyncFunction, AwaitExpression, LambdaExpression, and
DecoratorAnnotation to Rust, Go, Java, JavaScript/TypeScript, and Elisp
generators. Each generator emits idiomatic syntax: Rust struct+impl/trait/async fn/.await/|closure|,
Go type struct/interface/func receiver/<-channel/func(), Java class extends/interface/CompletableFuture/(x)->/@annotation,
JS class extends/async function/await/(x)=>/class, Elisp cl-defstruct/cl-defgeneric/cl-defmethod/(lambda).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 15:08:55 +00:00
|
|
|
#include "ClassDeclaration.h"
|
|
|
|
|
#include "GenericType.h"
|
|
|
|
|
#include "AsyncNodes.h"
|
2026-02-13 18:41:31 +00:00
|
|
|
#include "../SemannoAnnotationImpl.h"
|
2026-02-09 14:47:51 -07:00
|
|
|
|
2026-02-13 18:41:31 +00:00
|
|
|
class ElispGenerator : public ProjectionGenerator, public SemannoAnnotationImpl<ElispGenerator> {
|
2026-02-09 14:47:51 -07:00
|
|
|
public:
|
2026-02-13 18:41:31 +00:00
|
|
|
std::string commentPrefix() const { return ";; "; }
|
|
|
|
|
|
2026-02-09 14:47:51 -07:00
|
|
|
std::string generate(const ASTNode* node) override {
|
|
|
|
|
return dispatchGenerate(this, node, "; Unknown concept: ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitModule(const Module* module) override {
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
|
|
|
|
|
oss << "; Module: " << module->name << "\n\n";
|
|
|
|
|
|
|
|
|
|
// Process variables first
|
|
|
|
|
auto variables = module->getChildren("variables");
|
|
|
|
|
for (const auto* var : variables) {
|
|
|
|
|
oss << visitVariable(static_cast<const Variable*>(var)) << "\n";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!variables.empty()) {
|
|
|
|
|
oss << "\n";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Process functions
|
|
|
|
|
auto functions = module->getChildren("functions");
|
|
|
|
|
for (size_t i = 0; i < functions.size(); ++i) {
|
|
|
|
|
if (i > 0) oss << "\n"; // Add blank line between functions
|
|
|
|
|
oss << visitFunction(static_cast<const Function*>(functions[i]));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return oss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitFunction(const Function* function) override {
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
|
|
|
|
|
// Process annotations first
|
|
|
|
|
auto annotations = function->getChildren("annotations");
|
|
|
|
|
for (const auto* annotation : annotations) {
|
|
|
|
|
std::string annotationCode = generate(annotation);
|
|
|
|
|
if (!annotationCode.empty()) {
|
|
|
|
|
oss << annotationCode << "\n";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Generate function definition in Elisp
|
|
|
|
|
oss << "(defun " << function->name << " (";
|
|
|
|
|
|
|
|
|
|
auto parameters = function->getChildren("parameters");
|
|
|
|
|
for (size_t i = 0; i < parameters.size(); ++i) {
|
|
|
|
|
if (i > 0) oss << " ";
|
|
|
|
|
oss << visitParameter(static_cast<const Parameter*>(parameters[i]));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
oss << ")\n";
|
|
|
|
|
|
|
|
|
|
// Process function body
|
|
|
|
|
auto body = function->getChildren("body");
|
|
|
|
|
if (body.empty()) {
|
|
|
|
|
oss << " nil)\n"; // Return nil if no body
|
|
|
|
|
} else {
|
|
|
|
|
for (const auto* stmt : body) {
|
|
|
|
|
std::string stmtCode = generate(stmt);
|
|
|
|
|
// Indent each line of the statement
|
|
|
|
|
size_t pos = 0;
|
|
|
|
|
while (pos < stmtCode.length()) {
|
|
|
|
|
size_t newlinePos = stmtCode.find('\n', pos);
|
|
|
|
|
if (newlinePos == std::string::npos) {
|
|
|
|
|
oss << " " << stmtCode.substr(pos) << "\n";
|
|
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
oss << " " << stmtCode.substr(pos, newlinePos - pos) << "\n";
|
|
|
|
|
pos = newlinePos + 1;
|
|
|
|
|
if (pos >= stmtCode.length()) break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
oss << ")\n"; // Close the function
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return oss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitVariable(const Variable* variable) override {
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
oss << "(defvar " << variable->name << " ";
|
|
|
|
|
|
|
|
|
|
auto initializer = variable->getChild("initializer");
|
|
|
|
|
if (initializer) {
|
|
|
|
|
oss << generate(initializer);
|
|
|
|
|
} else {
|
|
|
|
|
oss << "nil";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
oss << ") ; Variable declaration\n";
|
|
|
|
|
return oss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitParameter(const Parameter* parameter) override {
|
|
|
|
|
// In Elisp, parameters are just symbols
|
|
|
|
|
return parameter->name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitAssignment(const Assignment* assignment) override {
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
|
|
|
|
|
auto target = assignment->getChild("target");
|
|
|
|
|
auto value = assignment->getChild("value");
|
|
|
|
|
|
|
|
|
|
if (target && value) {
|
|
|
|
|
oss << "(setq " << generate(target) << " " << generate(value) << ")";
|
|
|
|
|
} else if (target) {
|
|
|
|
|
oss << "(setq " << generate(target) << " nil)";
|
|
|
|
|
} else {
|
|
|
|
|
oss << "nil";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return oss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitReturn(const Return* ret) override {
|
|
|
|
|
// In Elisp, the last expression in a function is the return value
|
|
|
|
|
// So we just return the value expression
|
|
|
|
|
auto value = ret->getChild("value");
|
|
|
|
|
if (value) {
|
|
|
|
|
return generate(value);
|
|
|
|
|
} else {
|
|
|
|
|
return "nil";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitBinaryOperation(const BinaryOperation* binOp) override {
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
|
|
|
|
|
auto left = binOp->getChild("left");
|
|
|
|
|
auto right = binOp->getChild("right");
|
|
|
|
|
|
|
|
|
|
// Map operators to Elisp equivalents
|
|
|
|
|
std::string op = binOp->op;
|
|
|
|
|
if (op == "+") op = "+";
|
|
|
|
|
else if (op == "-") op = "-";
|
|
|
|
|
else if (op == "*") op = "*";
|
|
|
|
|
else if (op == "/") op = "/";
|
|
|
|
|
else if (op == "==") op = "=";
|
|
|
|
|
else if (op == "!=") op = "/=";
|
|
|
|
|
else if (op == "<") op = "<";
|
|
|
|
|
else if (op == ">") op = ">";
|
|
|
|
|
else if (op == "<=") op = "<=";
|
|
|
|
|
else if (op == ">=") op = ">=";
|
|
|
|
|
else if (op == "and") op = "and";
|
|
|
|
|
else if (op == "or") op = "or";
|
|
|
|
|
|
|
|
|
|
oss << "(" << op << " ";
|
|
|
|
|
if (left) {
|
|
|
|
|
oss << generate(left);
|
|
|
|
|
} else {
|
|
|
|
|
oss << "nil";
|
|
|
|
|
}
|
|
|
|
|
oss << " ";
|
|
|
|
|
if (right) {
|
|
|
|
|
oss << generate(right);
|
|
|
|
|
} else {
|
|
|
|
|
oss << "nil";
|
|
|
|
|
}
|
|
|
|
|
oss << ")";
|
|
|
|
|
|
|
|
|
|
return oss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitVariableReference(const VariableReference* varRef) override {
|
|
|
|
|
return varRef->variableName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitIntegerLiteral(const IntegerLiteral* lit) override {
|
|
|
|
|
return std::to_string(lit->value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitFloatLiteral(const FloatLiteral* lit) override {
|
|
|
|
|
return lit->value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitStringLiteral(const StringLiteral* lit) override {
|
|
|
|
|
// In Elisp, strings are enclosed in double quotes
|
|
|
|
|
return "\"" + lit->value + "\"";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitBooleanLiteral(const BooleanLiteral* lit) override {
|
|
|
|
|
return lit->value ? "t" : "nil";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitNullLiteral(const NullLiteral* lit) override {
|
|
|
|
|
return "nil";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitIfStatement(const IfStatement* stmt) override {
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
|
|
|
|
|
auto condition = stmt->getChild("condition");
|
|
|
|
|
auto thenBranch = stmt->getChildren("thenBranch");
|
|
|
|
|
auto elseBranch = stmt->getChildren("elseBranch");
|
|
|
|
|
|
|
|
|
|
oss << "(if ";
|
|
|
|
|
if (condition) {
|
|
|
|
|
oss << generate(condition);
|
|
|
|
|
} else {
|
|
|
|
|
oss << "nil"; // fallback
|
|
|
|
|
}
|
|
|
|
|
oss << "\n";
|
|
|
|
|
|
|
|
|
|
// Then branch
|
|
|
|
|
if (!thenBranch.empty()) {
|
|
|
|
|
for (size_t i = 0; i < thenBranch.size(); ++i) {
|
|
|
|
|
if (i > 0) oss << "\n";
|
|
|
|
|
oss << " " << generate(thenBranch[i]);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
oss << " nil";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Else branch
|
|
|
|
|
if (!elseBranch.empty()) {
|
|
|
|
|
oss << "\n";
|
|
|
|
|
for (size_t i = 0; i < elseBranch.size(); ++i) {
|
|
|
|
|
if (i > 0) oss << "\n";
|
|
|
|
|
oss << " " << generate(elseBranch[i]);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
oss << "\n nil";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
oss << ")";
|
|
|
|
|
return oss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitWhileLoop(const WhileLoop* loop) override {
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
|
|
|
|
|
auto condition = loop->getChild("condition");
|
|
|
|
|
auto body = loop->getChildren("body");
|
|
|
|
|
|
|
|
|
|
oss << "(while ";
|
|
|
|
|
if (condition) {
|
|
|
|
|
oss << generate(condition);
|
|
|
|
|
} else {
|
|
|
|
|
oss << "t"; // fallback to infinite loop
|
|
|
|
|
}
|
|
|
|
|
oss << "\n";
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < body.size(); ++i) {
|
|
|
|
|
if (i > 0) oss << "\n";
|
|
|
|
|
oss << " " << generate(body[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
oss << ")";
|
|
|
|
|
return oss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitForLoop(const ForLoop* loop) override {
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
|
|
|
|
|
auto iterable = loop->getChild("iterable");
|
|
|
|
|
auto body = loop->getChildren("body");
|
|
|
|
|
|
|
|
|
|
std::string iterator = loop->iteratorName.empty() ? "item" : loop->iteratorName;
|
|
|
|
|
|
|
|
|
|
oss << "(dolist (" << iterator << " ";
|
|
|
|
|
if (iterable) {
|
|
|
|
|
oss << generate(iterable);
|
|
|
|
|
} else {
|
|
|
|
|
oss << "nil"; // fallback
|
|
|
|
|
}
|
|
|
|
|
oss << ")\n";
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < body.size(); ++i) {
|
|
|
|
|
if (i > 0) oss << "\n";
|
|
|
|
|
oss << " " << generate(body[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
oss << ")";
|
|
|
|
|
return oss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitExpressionStatement(const ExpressionStatement* stmt) override {
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
|
|
|
|
|
auto expr = stmt->getChild("expression");
|
|
|
|
|
if (expr) {
|
|
|
|
|
oss << generate(expr);
|
|
|
|
|
} else {
|
|
|
|
|
oss << "nil";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return oss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitUnaryOperation(const UnaryOperation* unOp) override {
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
|
|
|
|
|
auto operand = unOp->getChild("operand");
|
|
|
|
|
std::string op = unOp->op;
|
|
|
|
|
|
|
|
|
|
// Map unary operators to Elisp equivalents
|
|
|
|
|
if (op == "!") op = "not";
|
|
|
|
|
else if (op == "-") op = "-";
|
|
|
|
|
else if (op == "+") op = "+";
|
|
|
|
|
|
|
|
|
|
oss << "(" << op << " ";
|
|
|
|
|
if (operand) {
|
|
|
|
|
oss << generate(operand);
|
|
|
|
|
} else {
|
|
|
|
|
oss << "nil";
|
|
|
|
|
}
|
|
|
|
|
oss << ")";
|
|
|
|
|
|
|
|
|
|
return oss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitFunctionCall(const FunctionCall* call) override {
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
oss << "(" << call->functionName;
|
|
|
|
|
|
|
|
|
|
auto arguments = call->getChildren("arguments");
|
|
|
|
|
for (const auto* arg : arguments) {
|
|
|
|
|
oss << " " << generate(arg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
oss << ")";
|
|
|
|
|
|
|
|
|
|
return oss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitBlock(const Block* block) override {
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
|
|
|
|
|
auto statements = block->getChildren("statements");
|
|
|
|
|
if (statements.empty()) {
|
|
|
|
|
oss << "nil";
|
|
|
|
|
} else {
|
|
|
|
|
oss << "(progn\n";
|
|
|
|
|
for (size_t i = 0; i < statements.size(); ++i) {
|
|
|
|
|
oss << " " << generate(statements[i]);
|
|
|
|
|
if (i < statements.size() - 1) oss << "\n";
|
|
|
|
|
}
|
|
|
|
|
oss << ")";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return oss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitListLiteral(const ListLiteral* lit) override {
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
oss << "(list";
|
|
|
|
|
|
|
|
|
|
auto elements = lit->getChildren("elements");
|
|
|
|
|
for (const auto* elem : elements) {
|
|
|
|
|
oss << " " << generate(elem);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
oss << ")";
|
|
|
|
|
|
|
|
|
|
return oss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitIndexAccess(const IndexAccess* access) override {
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
|
|
|
|
|
auto target = access->getChild("target");
|
|
|
|
|
auto index = access->getChild("index");
|
|
|
|
|
|
|
|
|
|
if (target && index) {
|
|
|
|
|
// In Elisp, accessing list/array elements
|
|
|
|
|
oss << "(nth " << generate(index) << " " << generate(target) << ")";
|
|
|
|
|
} else if (target) {
|
|
|
|
|
oss << generate(target);
|
|
|
|
|
} else {
|
|
|
|
|
oss << "nil";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return oss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitMemberAccess(const MemberAccess* access) override {
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
|
|
|
|
|
auto target = access->getChild("target");
|
|
|
|
|
if (target) {
|
|
|
|
|
// In Elisp, member access depends on the data structure
|
|
|
|
|
// For now, we'll represent it as a function call
|
|
|
|
|
oss << "(." << access->memberName << " " << generate(target) << ")";
|
|
|
|
|
} else {
|
|
|
|
|
oss << access->memberName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return oss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitPrimitiveType(const PrimitiveType* type) override {
|
|
|
|
|
// In Elisp, types are more dynamic, but we can represent them as symbols
|
|
|
|
|
std::string kind = type->kind;
|
|
|
|
|
if (kind == "int") return "integer";
|
|
|
|
|
if (kind == "float") return "float";
|
|
|
|
|
if (kind == "string") return "string";
|
|
|
|
|
if (kind == "bool") return "boolean";
|
|
|
|
|
if (kind == "char") return "character";
|
|
|
|
|
if (kind == "double") return "float";
|
|
|
|
|
if (kind == "long") return "integer";
|
|
|
|
|
if (kind == "short") return "integer";
|
|
|
|
|
if (kind == "byte") return "integer";
|
|
|
|
|
if (kind == "void") return "null";
|
|
|
|
|
|
|
|
|
|
return kind; // Return as-is if not a common type
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitListType(const ListType* type) override {
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
oss << "(list ";
|
|
|
|
|
|
|
|
|
|
auto elementType = type->getChild("elementType");
|
|
|
|
|
if (elementType) {
|
|
|
|
|
oss << generate(elementType);
|
|
|
|
|
} else {
|
|
|
|
|
oss << "t"; // t means any type in Elisp
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
oss << ")";
|
|
|
|
|
return oss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitSetType(const SetType* type) override {
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
oss << "(hash-table :test 'equal)";
|
|
|
|
|
return oss.str(); // Represent sets as hash tables with equal test
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitMapType(const MapType* type) override {
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
oss << "(hash-table :test 'equal)";
|
|
|
|
|
return oss.str(); // Represent maps as hash tables
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitTupleType(const TupleType* type) override {
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
oss << "(vector"; // Represent tuples as vectors
|
|
|
|
|
|
|
|
|
|
auto elementTypes = type->getChildren("elementTypes");
|
|
|
|
|
for (const auto* elemType : elementTypes) {
|
|
|
|
|
oss << " " << generate(elemType);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
oss << ")";
|
|
|
|
|
return oss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitArrayType(const ArrayType* type) override {
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
oss << "(vector ";
|
|
|
|
|
|
|
|
|
|
auto elementType = type->getChild("elementType");
|
|
|
|
|
if (elementType) {
|
|
|
|
|
oss << generate(elementType);
|
|
|
|
|
} else {
|
|
|
|
|
oss << "t";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
oss << ")";
|
|
|
|
|
return oss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitOptionalType(const OptionalType* type) override {
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
oss << "(or null ";
|
|
|
|
|
|
|
|
|
|
auto innerType = type->getChild("innerType");
|
|
|
|
|
if (innerType) {
|
|
|
|
|
oss << generate(innerType);
|
|
|
|
|
} else {
|
|
|
|
|
oss << "t";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
oss << ")";
|
|
|
|
|
return oss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitCustomType(const CustomType* type) override {
|
|
|
|
|
return type->typeName;
|
|
|
|
|
}
|
|
|
|
|
|
Step 308: All 8 generators produce language-appropriate output for 9 new AST node types (8/8 tests)
Phase 11c complete (80/80 tests). Added visitor implementations for
ClassDeclaration, InterfaceDeclaration, MethodDeclaration, GenericType,
TypeParameter, AsyncFunction, AwaitExpression, LambdaExpression, and
DecoratorAnnotation to Rust, Go, Java, JavaScript/TypeScript, and Elisp
generators. Each generator emits idiomatic syntax: Rust struct+impl/trait/async fn/.await/|closure|,
Go type struct/interface/func receiver/<-channel/func(), Java class extends/interface/CompletableFuture/(x)->/@annotation,
JS class extends/async function/await/(x)=>/class, Elisp cl-defstruct/cl-defgeneric/cl-defmethod/(lambda).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 15:08:55 +00:00
|
|
|
// --- New AST node visitors (Step 308) ---
|
|
|
|
|
|
|
|
|
|
std::string visitClassDeclaration(const ASTNode* node) override {
|
|
|
|
|
auto* cls = static_cast<const ClassDeclaration*>(node);
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
auto annotations = cls->getChildren("annotations");
|
|
|
|
|
for (const auto* a : annotations) oss << generate(a) << "\n";
|
|
|
|
|
oss << "(cl-defstruct " << cls->name;
|
|
|
|
|
if (!cls->superClass.empty()) oss << "\n (:include " << cls->superClass << ")";
|
|
|
|
|
auto fields = cls->getChildren("fields");
|
|
|
|
|
for (const auto* f : fields) {
|
|
|
|
|
auto* var = static_cast<const Variable*>(f);
|
|
|
|
|
oss << "\n (" << var->name << " nil)";
|
|
|
|
|
}
|
|
|
|
|
oss << ")\n";
|
|
|
|
|
auto methods = cls->getChildren("methods");
|
|
|
|
|
for (const auto* m : methods) oss << "\n" << generate(m);
|
|
|
|
|
return oss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitInterfaceDeclaration(const ASTNode* node) override {
|
|
|
|
|
auto* iface = static_cast<const InterfaceDeclaration*>(node);
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
oss << "; Interface: " << iface->name << "\n";
|
|
|
|
|
auto methods = iface->getChildren("methods");
|
|
|
|
|
for (const auto* m : methods) {
|
|
|
|
|
auto* meth = static_cast<const MethodDeclaration*>(m);
|
|
|
|
|
oss << "(cl-defgeneric " << meth->name << " (self))\n";
|
|
|
|
|
}
|
|
|
|
|
return oss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitMethodDeclaration(const ASTNode* node) override {
|
|
|
|
|
auto* meth = static_cast<const MethodDeclaration*>(node);
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
auto annotations = meth->getChildren("annotations");
|
|
|
|
|
for (const auto* a : annotations) oss << generate(a) << "\n";
|
|
|
|
|
oss << "(cl-defmethod " << meth->name << " ((self";
|
|
|
|
|
if (!meth->className.empty()) oss << " " << meth->className;
|
|
|
|
|
oss << ")";
|
|
|
|
|
auto params = meth->getChildren("parameters");
|
|
|
|
|
for (const auto* p : params) oss << " " << visitParameter(static_cast<const Parameter*>(p));
|
|
|
|
|
oss << ")\n";
|
|
|
|
|
auto body = meth->getChildren("body");
|
|
|
|
|
if (body.empty()) {
|
|
|
|
|
oss << " nil)\n";
|
|
|
|
|
} else {
|
|
|
|
|
for (const auto* s : body) oss << " " << generate(s) << "\n";
|
|
|
|
|
oss << ")\n";
|
|
|
|
|
}
|
|
|
|
|
return oss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitGenericType(const ASTNode* node) override {
|
|
|
|
|
auto* gen = static_cast<const GenericType*>(node);
|
|
|
|
|
return gen->baseName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitTypeParameter(const ASTNode* node) override {
|
|
|
|
|
auto* tp = static_cast<const TypeParameter*>(node);
|
|
|
|
|
return tp->name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitAsyncFunction(const ASTNode* node) override {
|
|
|
|
|
auto* af = static_cast<const AsyncFunction*>(node);
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
auto annotations = af->getChildren("annotations");
|
|
|
|
|
for (const auto* a : annotations) oss << generate(a) << "\n";
|
|
|
|
|
oss << "(defun " << af->name << " (";
|
|
|
|
|
auto params = af->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";
|
|
|
|
|
oss << " ;; async\n";
|
|
|
|
|
auto body = af->getChildren("body");
|
|
|
|
|
if (body.empty()) {
|
|
|
|
|
oss << " nil)\n";
|
|
|
|
|
} else {
|
|
|
|
|
for (const auto* s : body) oss << " " << generate(s) << "\n";
|
|
|
|
|
oss << ")\n";
|
|
|
|
|
}
|
|
|
|
|
return oss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitAwaitExpression(const ASTNode* node) override {
|
|
|
|
|
auto* aw = static_cast<const AwaitExpression*>(node);
|
|
|
|
|
auto* expr = aw->getChild("expression");
|
|
|
|
|
return "(async-get " + (expr ? generate(expr) : "nil") + ")";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitLambdaExpression(const ASTNode* node) override {
|
|
|
|
|
auto* lam = static_cast<const LambdaExpression*>(node);
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
oss << "(lambda (";
|
|
|
|
|
auto params = lam->getChildren("parameters");
|
|
|
|
|
for (size_t i = 0; i < params.size(); ++i) {
|
|
|
|
|
if (i > 0) oss << " ";
|
|
|
|
|
oss << static_cast<const Parameter*>(params[i])->name;
|
|
|
|
|
}
|
|
|
|
|
oss << ")";
|
|
|
|
|
auto body = lam->getChildren("body");
|
|
|
|
|
if (body.empty()) {
|
|
|
|
|
oss << " nil";
|
|
|
|
|
} else {
|
|
|
|
|
for (const auto* s : body) oss << "\n " << generate(s);
|
|
|
|
|
}
|
|
|
|
|
oss << ")";
|
|
|
|
|
return oss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitDecoratorAnnotation(const ASTNode* node) override {
|
|
|
|
|
auto* dec = static_cast<const DecoratorAnnotation*>(node);
|
|
|
|
|
return "; @" + dec->name;
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-09 14:47:51 -07:00
|
|
|
std::string visitDerefStrategy(const DerefStrategy* annotation) override {
|
|
|
|
|
// Convert deref strategy to Elisp annotation/comment
|
|
|
|
|
if (annotation->strategy == "batched") {
|
|
|
|
|
return "; @deref(batched) - Process in batches for efficiency";
|
|
|
|
|
} else if (annotation->strategy == "streamed") {
|
|
|
|
|
return "; @deref(streamed) - Stream processing";
|
|
|
|
|
} else if (annotation->strategy == "manual") {
|
|
|
|
|
return "; @deref(manual) - Manual memory management";
|
|
|
|
|
} else {
|
|
|
|
|
return "; @deref(" + annotation->strategy + ") - Memory dereference strategy";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitOptimizationLock(const OptimizationLock* annotation) override {
|
|
|
|
|
return "; @lock(" + annotation->lockedBy + ") - Optimization locked by " + annotation->lockedBy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitLangSpecific(const LangSpecific* annotation) override {
|
|
|
|
|
return "; @lang_specific(" + annotation->language + ", " + annotation->idiomType + ")";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitDeallocateAnnotation(const DeallocateAnnotation* annotation) override {
|
|
|
|
|
return "; @dealloc(" + annotation->strategy + ")";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitLifetimeAnnotation(const LifetimeAnnotation* annotation) override {
|
|
|
|
|
return "; @lifetime(" + annotation->strategy + ")";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitReclaimAnnotation(const ReclaimAnnotation* annotation) override {
|
|
|
|
|
return "; @reclaim(" + annotation->strategy + ")";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitOwnerAnnotation(const OwnerAnnotation* annotation) override {
|
|
|
|
|
return "; @owner(" + annotation->strategy + ")";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitAllocateAnnotation(const AllocateAnnotation* annotation) override {
|
|
|
|
|
return "; @allocate(" + annotation->strategy + ")";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitHotColdAnnotation(const HotColdAnnotation* annotation) override {
|
|
|
|
|
return "; @" + annotation->hint + " - Optimization hint";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitInlineAnnotation(const InlineAnnotation* annotation) override {
|
|
|
|
|
return "; @inline(" + annotation->mode + ")";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitPureAnnotation(const PureAnnotation*) override {
|
|
|
|
|
return "; @pure - No side effects";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string visitConstExprAnnotation(const ConstExprAnnotation*) override {
|
|
|
|
|
return "; @constexpr - Compile-time evaluable";
|
|
|
|
|
}
|
|
|
|
|
};
|