Refactor editor state/utils and split generators
This commit is contained in:
@@ -38,28 +38,28 @@ FetchContent_Declare(
|
||||
FetchContent_Declare(
|
||||
tree-sitter-javascript
|
||||
GIT_REPOSITORY https://github.com/tree-sitter/tree-sitter-javascript.git
|
||||
GIT_TAG master
|
||||
GIT_TAG v0.23.1
|
||||
GIT_SHALLOW TRUE
|
||||
)
|
||||
|
||||
FetchContent_Declare(
|
||||
tree-sitter-typescript
|
||||
GIT_REPOSITORY https://github.com/tree-sitter/tree-sitter-typescript.git
|
||||
GIT_TAG master
|
||||
GIT_TAG v0.23.2
|
||||
GIT_SHALLOW TRUE
|
||||
)
|
||||
|
||||
FetchContent_Declare(
|
||||
tree-sitter-java
|
||||
GIT_REPOSITORY https://github.com/tree-sitter/tree-sitter-java.git
|
||||
GIT_TAG master
|
||||
GIT_TAG v0.23.5
|
||||
GIT_SHALLOW TRUE
|
||||
)
|
||||
|
||||
FetchContent_Declare(
|
||||
tree-sitter-rust
|
||||
GIT_REPOSITORY https://github.com/tree-sitter/tree-sitter-rust.git
|
||||
GIT_TAG master
|
||||
GIT_TAG v0.23.3
|
||||
GIT_SHALLOW TRUE
|
||||
SOURCE_DIR ${CMAKE_BINARY_DIR}/_deps/tree-sitter-rust-src2
|
||||
BINARY_DIR ${CMAKE_BINARY_DIR}/_deps/tree-sitter-rust-build2
|
||||
@@ -68,14 +68,14 @@ FetchContent_Declare(
|
||||
FetchContent_Declare(
|
||||
tree-sitter-go
|
||||
GIT_REPOSITORY https://github.com/tree-sitter/tree-sitter-go.git
|
||||
GIT_TAG master
|
||||
GIT_TAG v0.23.4
|
||||
GIT_SHALLOW TRUE
|
||||
)
|
||||
|
||||
FetchContent_Declare(
|
||||
tinyfiledialogs
|
||||
GIT_REPOSITORY https://github.com/native-toolkit/tinyfiledialogs.git
|
||||
GIT_TAG master
|
||||
GIT_TAG 2.9.3
|
||||
GIT_SHALLOW TRUE
|
||||
)
|
||||
|
||||
|
||||
1196
editor/src/EditorState.h
Normal file
1196
editor/src/EditorState.h
Normal file
File diff suppressed because it is too large
Load Diff
698
editor/src/EditorUtils.h
Normal file
698
editor/src/EditorUtils.h
Normal file
@@ -0,0 +1,698 @@
|
||||
#pragma once
|
||||
|
||||
#include "EditorState.h"
|
||||
|
||||
#include "imgui.h"
|
||||
#include "SyntaxHighlighter.h"
|
||||
#include "CodeEditorWidget.h"
|
||||
#include "FileTree.h"
|
||||
#include "WelcomeScreen.h"
|
||||
#include "FileDialog.h"
|
||||
#include "LSPClient.h"
|
||||
#include "BufferManager.h"
|
||||
#include "ast/Serialization.h"
|
||||
#include "ast/Generator.h"
|
||||
#include "ast/Annotation.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <climits>
|
||||
#include <memory>
|
||||
|
||||
static int countLines(const std::string& text) {
|
||||
int lines = 1;
|
||||
for (char c : text) {
|
||||
if (c == '\n') ++lines;
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
static std::string generateForLanguage(const Module* ast, const std::string& language) {
|
||||
if (!ast) return "";
|
||||
if (language == "python") {
|
||||
PythonGenerator gen;
|
||||
return gen.generate(ast);
|
||||
}
|
||||
if (language == "cpp") {
|
||||
CppGenerator gen;
|
||||
return gen.generate(ast);
|
||||
}
|
||||
if (language == "elisp") {
|
||||
ElispGenerator gen;
|
||||
return gen.generate(ast);
|
||||
}
|
||||
PythonGenerator gen;
|
||||
return gen.generate(ast);
|
||||
}
|
||||
|
||||
static std::unique_ptr<Module> cloneModule(const Module* ast) {
|
||||
if (!ast) return nullptr;
|
||||
json j = toJson(ast);
|
||||
ASTNode* node = fromJson(j);
|
||||
if (!node || node->conceptType != "Module") return nullptr;
|
||||
return std::unique_ptr<Module>(static_cast<Module*>(node));
|
||||
}
|
||||
|
||||
static bool isAnnotationNode(const ASTNode* node) {
|
||||
if (!node) return false;
|
||||
if (node->conceptType.find("Annotation") != std::string::npos) return true;
|
||||
if (node->conceptType == "DerefStrategy") return true;
|
||||
if (node->conceptType == "OptimizationLock") return true;
|
||||
if (node->conceptType == "LangSpecific") return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int countAnnotationNodes(const ASTNode* node) {
|
||||
if (!node) return 0;
|
||||
int count = isAnnotationNode(node) ? 1 : 0;
|
||||
for (auto* child : node->allChildren()) {
|
||||
count += countAnnotationNodes(child);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static std::string findOptimizationBlockReason(const ASTNode* node) {
|
||||
if (!node) return "";
|
||||
for (auto* anno : node->getChildren("annotations")) {
|
||||
if (anno->conceptType == "OwnerAnnotation") {
|
||||
auto* oa = static_cast<const OwnerAnnotation*>(anno);
|
||||
if (oa->strategy == "Single") {
|
||||
return "@Owner(Single) blocks optimization (aliasing risk)";
|
||||
}
|
||||
}
|
||||
if (anno->conceptType == "DeallocateAnnotation") {
|
||||
auto* da = static_cast<const DeallocateAnnotation*>(anno);
|
||||
if (da->strategy == "Explicit") {
|
||||
return "@Deallocate(Explicit) blocks optimization (reorder risk)";
|
||||
}
|
||||
}
|
||||
if (anno->conceptType == "AllocateAnnotation") {
|
||||
auto* aa = static_cast<const AllocateAnnotation*>(anno);
|
||||
if (aa->strategy == "Static") {
|
||||
return "@Allocate(Static) blocks optimization (dynamic alloc risk)";
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto* child : node->allChildren()) {
|
||||
std::string found = findOptimizationBlockReason(child);
|
||||
if (!found.empty()) return found;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
static std::string findOptimizationLockWarning(const ASTNode* node) {
|
||||
if (!node) return "";
|
||||
if (node->conceptType == "OptimizationLock") {
|
||||
auto* lock = static_cast<const OptimizationLock*>(node);
|
||||
if (lock->lockLevel == "warning") {
|
||||
return "OptimizationLock: " + lock->lockReason +
|
||||
" (locked by " + lock->lockedBy + ")";
|
||||
}
|
||||
}
|
||||
for (auto* child : node->allChildren()) {
|
||||
std::string found = findOptimizationLockWarning(child);
|
||||
if (!found.empty()) return found;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
static ImVec4 transformColorForName(const std::string& name) {
|
||||
if (name == "constant-fold") return ImVec4(0.45f, 0.85f, 0.45f, 1.0f);
|
||||
if (name == "dead-code-elim") return ImVec4(0.90f, 0.45f, 0.45f, 1.0f);
|
||||
return ImVec4(0.75f, 0.75f, 0.75f, 1.0f);
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// ImGui InputTextMultiline with std::string resize callback
|
||||
// ---------------------------------------------------------------------------
|
||||
struct InputTextCallbackData {
|
||||
std::string* str;
|
||||
};
|
||||
|
||||
static int InputTextCallback(ImGuiInputTextCallbackData* data) {
|
||||
auto* userData = static_cast<InputTextCallbackData*>(data->UserData);
|
||||
if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) {
|
||||
userData->str->resize(data->BufTextLen);
|
||||
data->Buf = userData->str->data();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool InputTextMultilineStr(const char* label, std::string* str,
|
||||
const ImVec2& size, ImGuiInputTextFlags flags = 0) {
|
||||
flags |= ImGuiInputTextFlags_CallbackResize;
|
||||
InputTextCallbackData cbData{str};
|
||||
// Ensure buffer has room
|
||||
if (str->capacity() < str->size() + 256)
|
||||
str->reserve(str->size() + 4096);
|
||||
return ImGui::InputTextMultiline(label, str->data(), str->capacity() + 1,
|
||||
size, flags, InputTextCallback, &cbData);
|
||||
}
|
||||
|
||||
static bool InputTextStr(const char* label, std::string* str, ImGuiInputTextFlags flags = 0) {
|
||||
flags |= ImGuiInputTextFlags_CallbackResize;
|
||||
InputTextCallbackData cbData{str};
|
||||
if (str->capacity() < str->size() + 64)
|
||||
str->reserve(str->size() + 256);
|
||||
return ImGui::InputText(label, str->data(), str->capacity() + 1,
|
||||
flags, InputTextCallback, &cbData);
|
||||
}
|
||||
|
||||
static bool annotationInfo(const ASTNode* anno, ImU32& color, std::string& label) {
|
||||
if (!anno) return false;
|
||||
if (anno->conceptType == "ReclaimAnnotation") {
|
||||
auto* a = static_cast<const ReclaimAnnotation*>(anno);
|
||||
if (a->strategy == "Tracing") {
|
||||
color = IM_COL32(80, 140, 220, 255);
|
||||
label = "@Reclaim(Tracing)";
|
||||
return true;
|
||||
}
|
||||
} else if (anno->conceptType == "OwnerAnnotation") {
|
||||
auto* a = static_cast<const OwnerAnnotation*>(anno);
|
||||
if (a->strategy == "Single") {
|
||||
color = IM_COL32(220, 160, 60, 255);
|
||||
label = "@Owner(Single)";
|
||||
return true;
|
||||
}
|
||||
} else if (anno->conceptType == "DeallocateAnnotation") {
|
||||
auto* a = static_cast<const DeallocateAnnotation*>(anno);
|
||||
if (a->strategy == "Explicit") {
|
||||
color = IM_COL32(220, 80, 80, 255);
|
||||
label = "@Deallocate(Explicit)";
|
||||
return true;
|
||||
}
|
||||
} else if (anno->conceptType == "LifetimeAnnotation") {
|
||||
auto* a = static_cast<const LifetimeAnnotation*>(anno);
|
||||
if (a->strategy == "RAII") {
|
||||
color = IM_COL32(80, 180, 100, 255);
|
||||
label = "@Lifetime(RAII)";
|
||||
return true;
|
||||
}
|
||||
} else if (anno->conceptType == "AllocateAnnotation") {
|
||||
auto* a = static_cast<const AllocateAnnotation*>(anno);
|
||||
if (a->strategy == "Static") {
|
||||
color = IM_COL32(160, 160, 160, 255);
|
||||
label = "@Allocate(Static)";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static std::string annotationLabel(const ASTNode* anno) {
|
||||
if (!anno) return "";
|
||||
if (anno->conceptType == "ReclaimAnnotation") {
|
||||
auto* a = static_cast<const ReclaimAnnotation*>(anno);
|
||||
return "@Reclaim(" + a->strategy + ")";
|
||||
}
|
||||
if (anno->conceptType == "OwnerAnnotation") {
|
||||
auto* a = static_cast<const OwnerAnnotation*>(anno);
|
||||
return "@Owner(" + a->strategy + ")";
|
||||
}
|
||||
if (anno->conceptType == "DeallocateAnnotation") {
|
||||
auto* a = static_cast<const DeallocateAnnotation*>(anno);
|
||||
return "@Deallocate(" + a->strategy + ")";
|
||||
}
|
||||
if (anno->conceptType == "LifetimeAnnotation") {
|
||||
auto* a = static_cast<const LifetimeAnnotation*>(anno);
|
||||
return "@Lifetime(" + a->strategy + ")";
|
||||
}
|
||||
if (anno->conceptType == "AllocateAnnotation") {
|
||||
auto* a = static_cast<const AllocateAnnotation*>(anno);
|
||||
return "@Allocate(" + a->strategy + ")";
|
||||
}
|
||||
return anno->conceptType;
|
||||
}
|
||||
|
||||
static std::string nodeDisplayName(const ASTNode* node) {
|
||||
if (!node) return "";
|
||||
if (node->conceptType == "Function") return static_cast<const Function*>(node)->name;
|
||||
if (node->conceptType == "Variable") return static_cast<const Variable*>(node)->name;
|
||||
return node->conceptType;
|
||||
}
|
||||
|
||||
static std::string nextAnnotationId() {
|
||||
static int counter = 0;
|
||||
return "anno_ui_" + std::to_string(counter++);
|
||||
}
|
||||
|
||||
static Annotation* createAnnotationNode(const std::string& type, const std::string& strategy) {
|
||||
if (type == "ReclaimAnnotation") {
|
||||
auto* a = new ReclaimAnnotation(nextAnnotationId(), strategy);
|
||||
return a;
|
||||
}
|
||||
if (type == "OwnerAnnotation") {
|
||||
auto* a = new OwnerAnnotation(nextAnnotationId(), strategy);
|
||||
return a;
|
||||
}
|
||||
if (type == "DeallocateAnnotation") {
|
||||
auto* a = new DeallocateAnnotation(nextAnnotationId(), strategy);
|
||||
return a;
|
||||
}
|
||||
if (type == "LifetimeAnnotation") {
|
||||
auto* a = new LifetimeAnnotation(nextAnnotationId(), strategy);
|
||||
return a;
|
||||
}
|
||||
if (type == "AllocateAnnotation") {
|
||||
auto* a = new AllocateAnnotation(nextAnnotationId(), strategy);
|
||||
return a;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static int spanScore(const ASTNode* node) {
|
||||
if (!node || !node->hasSpan()) return INT_MAX;
|
||||
int lines = node->spanEndLine - node->spanStartLine;
|
||||
int cols = node->spanEndCol - node->spanStartCol;
|
||||
return lines * 10000 + cols;
|
||||
}
|
||||
|
||||
static bool spanContains(const ASTNode* node, int line, int col) {
|
||||
if (!node || !node->hasSpan()) return false;
|
||||
if (line < node->spanStartLine || line > node->spanEndLine) return false;
|
||||
if (line == node->spanStartLine && col < node->spanStartCol) return false;
|
||||
if (line == node->spanEndLine && col > node->spanEndCol) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static ASTNode* findNodeAtPosition(ASTNode* node, int line, int col) {
|
||||
if (!node) return nullptr;
|
||||
ASTNode* best = nullptr;
|
||||
if (spanContains(node, line, col)) best = node;
|
||||
for (auto* child : node->allChildren()) {
|
||||
ASTNode* cand = findNodeAtPosition(child, line, col);
|
||||
if (cand) {
|
||||
if (!best || spanScore(cand) < spanScore(best)) best = cand;
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
static ASTNode* findAnnotationTarget(ASTNode* node, int line) {
|
||||
if (!node) return nullptr;
|
||||
ASTNode* best = nullptr;
|
||||
if (node->hasSpan() && line >= node->spanStartLine && line <= node->spanEndLine) {
|
||||
if (node->conceptType == "Function" || node->conceptType == "Variable") {
|
||||
best = node;
|
||||
}
|
||||
}
|
||||
for (auto* child : node->allChildren()) {
|
||||
ASTNode* cand = findAnnotationTarget(child, line);
|
||||
if (cand) {
|
||||
if (!best || spanScore(cand) < spanScore(best)) best = cand;
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
static ASTNode* findNodeById(ASTNode* node, const std::string& id) {
|
||||
if (!node) return nullptr;
|
||||
if (node->id == id) return node;
|
||||
for (auto* child : node->allChildren()) {
|
||||
if (auto* found = findNodeById(child, id)) return found;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void collectAnnotationMarkers(const ASTNode* node, std::vector<AnnotationMarker>& out) {
|
||||
if (!node) return;
|
||||
if (node->hasSpan()) {
|
||||
for (const auto* anno : node->getChildren("annotations")) {
|
||||
ImU32 color = 0;
|
||||
std::string label;
|
||||
if (annotationInfo(anno, color, label)) {
|
||||
AnnotationMarker marker;
|
||||
marker.line = node->spanStartLine;
|
||||
marker.color = color;
|
||||
marker.message = label;
|
||||
out.push_back(std::move(marker));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto* child : node->allChildren()) {
|
||||
collectAnnotationMarkers(child, out);
|
||||
}
|
||||
}
|
||||
|
||||
struct OutlineItem {
|
||||
std::string name;
|
||||
std::string kind;
|
||||
int line = -1;
|
||||
int col = -1;
|
||||
std::vector<OutlineItem> children;
|
||||
};
|
||||
|
||||
static OutlineItem makeOutlineItem(const std::string& name,
|
||||
const std::string& kind,
|
||||
const ASTNode* node) {
|
||||
OutlineItem item;
|
||||
item.name = name;
|
||||
item.kind = kind;
|
||||
if (node && node->hasSpan()) {
|
||||
item.line = node->spanStartLine;
|
||||
item.col = node->spanStartCol;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
static void collectOutlineFromFunction(const Function* fn, std::vector<OutlineItem>& out) {
|
||||
OutlineItem item = makeOutlineItem(fn->name, "Function", fn);
|
||||
for (auto* p : fn->getChildren("parameters")) {
|
||||
if (p->conceptType == "Parameter") {
|
||||
auto* param = static_cast<const Parameter*>(p);
|
||||
item.children.push_back(makeOutlineItem(param->name, "Parameter", param));
|
||||
}
|
||||
}
|
||||
for (auto* child : fn->getChildren("body")) {
|
||||
if (child->conceptType == "Variable") {
|
||||
auto* var = static_cast<const Variable*>(child);
|
||||
item.children.push_back(makeOutlineItem(var->name, "Variable", var));
|
||||
}
|
||||
}
|
||||
out.push_back(std::move(item));
|
||||
}
|
||||
|
||||
static void collectOutlineFromAST(const Module* mod, std::vector<OutlineItem>& out) {
|
||||
if (!mod) return;
|
||||
for (auto* child : mod->getChildren("variables")) {
|
||||
if (child->conceptType == "Variable") {
|
||||
auto* var = static_cast<const Variable*>(child);
|
||||
out.push_back(makeOutlineItem(var->name, "Variable", var));
|
||||
}
|
||||
}
|
||||
for (auto* child : mod->getChildren("functions")) {
|
||||
if (child->conceptType == "Function") {
|
||||
auto* fn = static_cast<const Function*>(child);
|
||||
collectOutlineFromFunction(fn, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static std::string toLowerCopy(const std::string& input) {
|
||||
std::string out = input;
|
||||
std::transform(out.begin(), out.end(), out.begin(),
|
||||
[](unsigned char c) { return (char)std::tolower(c); });
|
||||
return out;
|
||||
}
|
||||
|
||||
static bool containsCaseInsensitive(const std::string& text, const std::string& filter) {
|
||||
if (filter.empty()) return true;
|
||||
std::string hay = toLowerCopy(text);
|
||||
return hay.find(filter) != std::string::npos;
|
||||
}
|
||||
|
||||
static bool outlineMatchesFilter(const OutlineItem& item, const std::string& filter) {
|
||||
if (filter.empty()) return true;
|
||||
if (containsCaseInsensitive(item.name, filter)) return true;
|
||||
for (const auto& child : item.children) {
|
||||
if (outlineMatchesFilter(child, filter)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static const char* lspSymbolKindLabel(int kind) {
|
||||
switch (kind) {
|
||||
case 1: return "File";
|
||||
case 2: return "Module";
|
||||
case 5: return "Class";
|
||||
case 6: return "Method";
|
||||
case 12: return "Function";
|
||||
case 13: return "Variable";
|
||||
case 14: return "Constant";
|
||||
case 19: return "String";
|
||||
case 23: return "Struct";
|
||||
default: return "Symbol";
|
||||
}
|
||||
}
|
||||
|
||||
static bool lspSymbolMatchesFilter(const LSPClient::DocumentSymbol& sym, const std::string& filter) {
|
||||
if (filter.empty()) return true;
|
||||
if (containsCaseInsensitive(sym.name, filter)) return true;
|
||||
for (const auto& child : sym.children) {
|
||||
if (lspSymbolMatchesFilter(child, filter)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Theme setup — VSCode Dark-inspired
|
||||
// ---------------------------------------------------------------------------
|
||||
static void SetupVSCodeDarkTheme() {
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
ImVec4* colors = style.Colors;
|
||||
|
||||
// Window
|
||||
colors[ImGuiCol_WindowBg] = ImVec4(0.12f, 0.12f, 0.12f, 1.00f);
|
||||
colors[ImGuiCol_ChildBg] = ImVec4(0.12f, 0.12f, 0.12f, 1.00f);
|
||||
colors[ImGuiCol_PopupBg] = ImVec4(0.15f, 0.15f, 0.15f, 1.00f);
|
||||
|
||||
// Borders
|
||||
colors[ImGuiCol_Border] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
|
||||
colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
||||
|
||||
// Frame (input fields, checkboxes)
|
||||
colors[ImGuiCol_FrameBg] = ImVec4(0.16f, 0.16f, 0.16f, 1.00f);
|
||||
colors[ImGuiCol_FrameBgHovered] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
|
||||
colors[ImGuiCol_FrameBgActive] = ImVec4(0.24f, 0.24f, 0.24f, 1.00f);
|
||||
|
||||
// Title bar
|
||||
colors[ImGuiCol_TitleBg] = ImVec4(0.08f, 0.08f, 0.08f, 1.00f);
|
||||
colors[ImGuiCol_TitleBgActive] = ImVec4(0.08f, 0.08f, 0.08f, 1.00f);
|
||||
colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.08f, 0.08f, 0.08f, 1.00f);
|
||||
|
||||
// Menu bar
|
||||
colors[ImGuiCol_MenuBarBg] = ImVec4(0.14f, 0.14f, 0.14f, 1.00f);
|
||||
|
||||
// Scrollbar
|
||||
colors[ImGuiCol_ScrollbarBg] = ImVec4(0.12f, 0.12f, 0.12f, 1.00f);
|
||||
colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.30f, 0.30f, 0.30f, 1.00f);
|
||||
colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.40f, 0.40f, 1.00f);
|
||||
colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
|
||||
|
||||
// Buttons
|
||||
colors[ImGuiCol_Button] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
|
||||
colors[ImGuiCol_ButtonHovered] = ImVec4(0.28f, 0.28f, 0.28f, 1.00f);
|
||||
colors[ImGuiCol_ButtonActive] = ImVec4(0.15f, 0.15f, 0.15f, 1.00f);
|
||||
|
||||
// Headers (collapsing headers, tree nodes)
|
||||
colors[ImGuiCol_Header] = ImVec4(0.18f, 0.18f, 0.18f, 1.00f);
|
||||
colors[ImGuiCol_HeaderHovered] = ImVec4(0.26f, 0.26f, 0.26f, 1.00f);
|
||||
colors[ImGuiCol_HeaderActive] = ImVec4(0.22f, 0.22f, 0.22f, 1.00f);
|
||||
|
||||
// Separator
|
||||
colors[ImGuiCol_Separator] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
|
||||
colors[ImGuiCol_SeparatorHovered] = ImVec4(0.28f, 0.56f, 0.89f, 1.00f);
|
||||
colors[ImGuiCol_SeparatorActive] = ImVec4(0.28f, 0.56f, 0.89f, 1.00f);
|
||||
|
||||
// Tabs
|
||||
colors[ImGuiCol_Tab] = ImVec4(0.12f, 0.12f, 0.12f, 1.00f);
|
||||
colors[ImGuiCol_TabHovered] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
|
||||
colors[ImGuiCol_TabActive] = ImVec4(0.18f, 0.18f, 0.18f, 1.00f);
|
||||
colors[ImGuiCol_TabUnfocused] = ImVec4(0.12f, 0.12f, 0.12f, 1.00f);
|
||||
colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.16f, 0.16f, 0.16f, 1.00f);
|
||||
|
||||
// Docking
|
||||
colors[ImGuiCol_DockingPreview] = ImVec4(0.28f, 0.56f, 0.89f, 0.70f);
|
||||
colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.12f, 0.12f, 0.12f, 1.00f);
|
||||
|
||||
// Text
|
||||
colors[ImGuiCol_Text] = ImVec4(0.86f, 0.86f, 0.86f, 1.00f);
|
||||
colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
|
||||
|
||||
// Selection / highlight
|
||||
colors[ImGuiCol_TextSelectedBg] = ImVec4(0.17f, 0.40f, 0.64f, 0.60f);
|
||||
|
||||
// Style tweaks
|
||||
style.WindowRounding = 0.0f;
|
||||
style.FrameRounding = 2.0f;
|
||||
style.ScrollbarRounding = 2.0f;
|
||||
style.GrabRounding = 2.0f;
|
||||
style.TabRounding = 0.0f;
|
||||
style.WindowBorderSize = 1.0f;
|
||||
style.FrameBorderSize = 0.0f;
|
||||
style.WindowPadding = ImVec2(8, 8);
|
||||
style.FramePadding = ImVec2(6, 3);
|
||||
style.ItemSpacing = ImVec2(6, 4);
|
||||
}
|
||||
|
||||
static void SetupVSCodeLightTheme() {
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
ImVec4* colors = style.Colors;
|
||||
|
||||
colors[ImGuiCol_WindowBg] = ImVec4(0.95f, 0.95f, 0.95f, 1.00f);
|
||||
colors[ImGuiCol_ChildBg] = ImVec4(0.95f, 0.95f, 0.95f, 1.00f);
|
||||
colors[ImGuiCol_PopupBg] = ImVec4(0.98f, 0.98f, 0.98f, 1.00f);
|
||||
|
||||
colors[ImGuiCol_Border] = ImVec4(0.75f, 0.75f, 0.75f, 1.00f);
|
||||
colors[ImGuiCol_FrameBg] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
|
||||
colors[ImGuiCol_FrameBgHovered] = ImVec4(0.85f, 0.85f, 0.85f, 1.00f);
|
||||
colors[ImGuiCol_FrameBgActive] = ImVec4(0.80f, 0.80f, 0.80f, 1.00f);
|
||||
|
||||
colors[ImGuiCol_TitleBg] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
|
||||
colors[ImGuiCol_TitleBgActive] = ImVec4(0.86f, 0.86f, 0.86f, 1.00f);
|
||||
colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
|
||||
|
||||
colors[ImGuiCol_MenuBarBg] = ImVec4(0.92f, 0.92f, 0.92f, 1.00f);
|
||||
colors[ImGuiCol_Button] = ImVec4(0.85f, 0.85f, 0.85f, 1.00f);
|
||||
colors[ImGuiCol_ButtonHovered] = ImVec4(0.78f, 0.78f, 0.78f, 1.00f);
|
||||
colors[ImGuiCol_ButtonActive] = ImVec4(0.70f, 0.70f, 0.70f, 1.00f);
|
||||
|
||||
colors[ImGuiCol_Header] = ImVec4(0.82f, 0.82f, 0.82f, 1.00f);
|
||||
colors[ImGuiCol_HeaderHovered] = ImVec4(0.75f, 0.75f, 0.75f, 1.00f);
|
||||
colors[ImGuiCol_HeaderActive] = ImVec4(0.70f, 0.70f, 0.70f, 1.00f);
|
||||
|
||||
colors[ImGuiCol_Text] = ImVec4(0.10f, 0.10f, 0.10f, 1.00f);
|
||||
colors[ImGuiCol_TextDisabled] = ImVec4(0.45f, 0.45f, 0.45f, 1.00f);
|
||||
colors[ImGuiCol_TextSelectedBg] = ImVec4(0.40f, 0.60f, 0.90f, 0.45f);
|
||||
|
||||
style.WindowRounding = 0.0f;
|
||||
style.FrameRounding = 2.0f;
|
||||
style.ScrollbarRounding = 2.0f;
|
||||
style.GrabRounding = 2.0f;
|
||||
style.TabRounding = 0.0f;
|
||||
style.WindowBorderSize = 1.0f;
|
||||
style.FrameBorderSize = 0.0f;
|
||||
style.WindowPadding = ImVec2(8, 8);
|
||||
style.FramePadding = ImVec2(6, 3);
|
||||
style.ItemSpacing = ImVec2(6, 4);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Syntax highlight color map
|
||||
// ---------------------------------------------------------------------------
|
||||
static ImVec4 tokenColor(TokenCategory cat) {
|
||||
switch (cat) {
|
||||
case TokenCategory::Keyword: return ImVec4(0.77f, 0.49f, 0.86f, 1.0f); // purple
|
||||
case TokenCategory::String: return ImVec4(0.81f, 0.54f, 0.37f, 1.0f); // orange
|
||||
case TokenCategory::Comment: return ImVec4(0.42f, 0.52f, 0.35f, 1.0f); // green
|
||||
case TokenCategory::Number: return ImVec4(0.71f, 0.80f, 0.55f, 1.0f); // light green
|
||||
case TokenCategory::Function: return ImVec4(0.86f, 0.86f, 0.55f, 1.0f); // yellow
|
||||
case TokenCategory::Parameter: return ImVec4(0.60f, 0.78f, 0.90f, 1.0f); // light blue
|
||||
case TokenCategory::Type: return ImVec4(0.30f, 0.70f, 0.68f, 1.0f); // teal
|
||||
case TokenCategory::Operator: return ImVec4(0.86f, 0.86f, 0.86f, 1.0f); // white
|
||||
case TokenCategory::Punctuation: return ImVec4(0.60f, 0.60f, 0.60f, 1.0f); // gray
|
||||
case TokenCategory::Builtin: return ImVec4(0.30f, 0.70f, 0.90f, 1.0f); // blue
|
||||
case TokenCategory::Identifier: return ImVec4(0.60f, 0.78f, 0.90f, 1.0f); // light blue
|
||||
default: return ImVec4(0.86f, 0.86f, 0.86f, 1.0f); // white
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Render syntax-highlighted text (read-only preview)
|
||||
// ---------------------------------------------------------------------------
|
||||
static void RenderHighlightedText(const std::string& text,
|
||||
const std::vector<HighlightSpan>& spans) {
|
||||
if (text.empty()) return;
|
||||
|
||||
// Build a color for each byte position
|
||||
// Default = plain text color
|
||||
std::vector<TokenCategory> charCats(text.size(), TokenCategory::Plain);
|
||||
for (const auto& span : spans) {
|
||||
for (uint32_t i = span.start; i < span.end && i < charCats.size(); ++i) {
|
||||
charCats[i] = span.category;
|
||||
}
|
||||
}
|
||||
|
||||
// Render line by line, span by span
|
||||
size_t pos = 0;
|
||||
int lineNum = 1;
|
||||
while (pos < text.size()) {
|
||||
// Find end of line
|
||||
size_t eol = text.find('\n', pos);
|
||||
if (eol == std::string::npos) eol = text.size();
|
||||
|
||||
// Line number
|
||||
ImGui::TextColored(ImVec4(0.45f, 0.45f, 0.45f, 1.0f), "%4d ", lineNum);
|
||||
ImGui::SameLine(0.0f, 0.0f);
|
||||
|
||||
// Render spans within this line
|
||||
size_t linePos = pos;
|
||||
while (linePos < eol) {
|
||||
// Find the extent of the current color
|
||||
TokenCategory cat = charCats[linePos];
|
||||
size_t spanEnd = linePos + 1;
|
||||
while (spanEnd < eol && charCats[spanEnd] == cat) ++spanEnd;
|
||||
|
||||
std::string chunk = text.substr(linePos, spanEnd - linePos);
|
||||
ImGui::TextColored(tokenColor(cat), "%s", chunk.c_str());
|
||||
if (spanEnd < eol) ImGui::SameLine(0.0f, 0.0f);
|
||||
|
||||
linePos = spanEnd;
|
||||
}
|
||||
|
||||
if (linePos == pos) {
|
||||
// Empty line
|
||||
ImGui::TextUnformatted("");
|
||||
}
|
||||
|
||||
pos = eol + 1;
|
||||
++lineNum;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// File tree rendering
|
||||
// ---------------------------------------------------------------------------
|
||||
static void RenderFileTree(const FileNode& node, EditorState& state) {
|
||||
if (!node.isDir) {
|
||||
if (ImGui::Selectable(node.name.c_str())) {
|
||||
state.doOpen(node.path);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;
|
||||
if (ImGui::TreeNodeEx(node.name.c_str(), flags)) {
|
||||
for (const auto& child : node.children) {
|
||||
RenderFileTree(child, state);
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Welcome screen rendering
|
||||
// ---------------------------------------------------------------------------
|
||||
static void RenderWelcome(WelcomeScreen& welcome, EditorState& state, std::string& lastDialogPath) {
|
||||
ImGui::Text("%s", welcome.getTitle().c_str());
|
||||
ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "%s", welcome.getSubtitle().c_str());
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::Text("Quick Actions");
|
||||
if (ImGui::Button("New File")) {
|
||||
std::string lang = state.active() ? state.active()->language : "python";
|
||||
state.createBuffer(state.makeUntitledName(), "", lang);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Open File")) {
|
||||
auto path = FileDialog::openFile({"Open File", {"*.py","*.cpp","*.h","*.el","*.js","*.ts","*.java","*.rs","*.go"}, lastDialogPath});
|
||||
if (!path.empty()) {
|
||||
lastDialogPath = path;
|
||||
state.doOpen(path);
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Open Folder")) {
|
||||
auto path = FileDialog::openFolder({"Open Folder", state.workspaceRoot});
|
||||
if (!path.empty()) {
|
||||
state.workspaceRoot = path;
|
||||
state.fileTreeDirty = true;
|
||||
state.projectSearch.setRoot(state.workspaceRoot);
|
||||
lastDialogPath = path;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::Text("Recent Files");
|
||||
for (const auto& rf : welcome.getRecentFiles()) {
|
||||
if (ImGui::Selectable(rf.displayName.c_str())) {
|
||||
state.doOpen(rf.path, bufferModeFromString(rf.mode));
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::Text("Tip");
|
||||
ImGui::TextWrapped("%s", welcome.getTip(0).c_str());
|
||||
}
|
||||
@@ -190,9 +190,7 @@ public:
|
||||
// Find the parent and remove the child
|
||||
ASTNode* parent = node->parent;
|
||||
if (parent) {
|
||||
// This is a simplified implementation - in reality, we'd need to track
|
||||
// which role the node was added to and remove it from that role
|
||||
// For now, we'll just mark this as a TODO in a real implementation
|
||||
// STUB: insertNode undo not implemented — requires role tracking per mutation
|
||||
}
|
||||
}
|
||||
} else if (operation["type"] == "setNodeProperty") {
|
||||
@@ -344,10 +342,20 @@ public:
|
||||
std::cout << "Sending to Emacs: " << command << std::endl;
|
||||
|
||||
// In a real implementation:
|
||||
std::string cmd = "emacsclient -s whetstone -e \"" + command + "\"";
|
||||
// Escape command to prevent shell injection
|
||||
std::string escaped;
|
||||
for (char c : command) {
|
||||
if (c == '"' || c == '\\') escaped += '\\';
|
||||
escaped += c;
|
||||
}
|
||||
std::string cmd = "emacsclient -s whetstone -e \"" + escaped + "\"";
|
||||
#ifdef _WIN32
|
||||
FILE* pipe = _popen(cmd.c_str(), "r");
|
||||
if (!pipe) return "nil"; // Return nil if we can't open the pipe
|
||||
|
||||
#else
|
||||
FILE* pipe = popen(cmd.c_str(), "r");
|
||||
#endif
|
||||
if (!pipe) return "nil";
|
||||
|
||||
char buffer[4096];
|
||||
std::string result = "";
|
||||
while (!feof(pipe)) {
|
||||
@@ -355,17 +363,31 @@ public:
|
||||
result += buffer;
|
||||
}
|
||||
}
|
||||
#ifdef _WIN32
|
||||
_pclose(pipe);
|
||||
#else
|
||||
pclose(pipe);
|
||||
#endif
|
||||
|
||||
// Trim whitespace from the result
|
||||
result.erase(result.find_last_not_of(" \t\n\r\f\v") + 1);
|
||||
return result.empty() ? "nil" : result;
|
||||
}
|
||||
|
||||
// Escape a string for embedding in Elisp double-quoted strings
|
||||
static std::string escapeElispString(const std::string& s) {
|
||||
std::string out;
|
||||
for (char c : s) {
|
||||
if (c == '"' || c == '\\') out += '\\';
|
||||
out += c;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Method to load a file via Emacs and parse to AST using tree-sitter
|
||||
std::unique_ptr<Module> loadFile(const std::string& path) {
|
||||
// First, get the file content from Emacs
|
||||
std::string command = "(with-current-buffer (find-file-noselect \"" + path + "\") (buffer-string))";
|
||||
std::string command = "(with-current-buffer (find-file-noselect \"" + escapeElispString(path) + "\") (buffer-string))";
|
||||
std::string content = sendToEmacs(command);
|
||||
|
||||
// Determine the language based on file extension
|
||||
@@ -424,12 +446,9 @@ public:
|
||||
} else if (targetLanguage == "elisp") {
|
||||
ElispGenerator elispGen;
|
||||
content = elispGen.generate(ast);
|
||||
} else if (targetLanguage == "cpp") {
|
||||
// For C++ generation, we would use a CppGenerator when implemented
|
||||
// For now, we'll use the Python generator as a placeholder
|
||||
PythonGenerator gen;
|
||||
} else if (targetLanguage == "cpp" || targetLanguage == "c++") {
|
||||
CppGenerator gen;
|
||||
content = gen.generate(ast);
|
||||
// TODO: Implement CppGenerator when ready
|
||||
} else {
|
||||
// Default to Python generator for unknown languages
|
||||
PythonGenerator gen;
|
||||
@@ -437,21 +456,24 @@ public:
|
||||
}
|
||||
|
||||
// Send the content to Emacs to save to file
|
||||
std::string command = "(with-current-buffer (find-file-noselect \"" + path + "\")" +
|
||||
std::string ePath = escapeElispString(path);
|
||||
std::string eContent = escapeElispString(content);
|
||||
std::string command = "(with-current-buffer (find-file-noselect \"" + ePath + "\")" +
|
||||
"(erase-buffer)" +
|
||||
"(insert \"" + content + "\")" +
|
||||
"(write-file \"" + path + "\"))";
|
||||
"(insert \"" + eContent + "\")" +
|
||||
"(write-file \"" + ePath + "\"))";
|
||||
std::string result = sendToEmacs(command);
|
||||
// If the result is not an error, assume success
|
||||
return result.find("Error") == std::string::npos;
|
||||
}
|
||||
|
||||
// Overload: save raw content string to a file via Emacs
|
||||
bool saveContent(const std::string& path, const std::string& content) {
|
||||
std::string command = "(with-current-buffer (find-file-noselect \"" + path + "\")" +
|
||||
std::string ePath = escapeElispString(path);
|
||||
std::string eContent = escapeElispString(content);
|
||||
std::string command = "(with-current-buffer (find-file-noselect \"" + ePath + "\")" +
|
||||
"(erase-buffer)" +
|
||||
"(insert \"" + content + "\")" +
|
||||
"(write-file \"" + path + "\"))";
|
||||
"(insert \"" + eContent + "\")" +
|
||||
"(write-file \"" + ePath + "\"))";
|
||||
std::string result = sendToEmacs(command);
|
||||
return result.find("Error") == std::string::npos;
|
||||
}
|
||||
|
||||
702
editor/src/ast/CppGenerator.h
Normal file
702
editor/src/ast/CppGenerator.h
Normal file
@@ -0,0 +1,702 @@
|
||||
#pragma once
|
||||
#include "ProjectionGenerator.h"
|
||||
|
||||
class CppGenerator : public ProjectionGenerator {
|
||||
public:
|
||||
std::string generate(const ASTNode* node) override {
|
||||
return dispatchGenerate(this, node, "// Unknown concept: ");
|
||||
}
|
||||
|
||||
std::string visitModule(const Module* module) override {
|
||||
std::ostringstream oss;
|
||||
|
||||
// Generate namespace wrapper
|
||||
oss << "namespace " << 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]));
|
||||
}
|
||||
|
||||
oss << "\n} // namespace " << module->name << "\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitFunction(const Function* function) override {
|
||||
std::ostringstream oss;
|
||||
|
||||
// Process annotations first (these are in the "annotations" role)
|
||||
auto annotations = function->getChildren("annotations");
|
||||
for (const auto* annotation : annotations) {
|
||||
std::string annotationCode = generate(annotation);
|
||||
if (!annotationCode.empty() && annotationCode != "// Unknown concept: Annotation") {
|
||||
oss << annotationCode << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Generate function return type
|
||||
std::string returnTypeStr = "void"; // Default
|
||||
auto returnType = function->getChild("returnType");
|
||||
if (returnType) {
|
||||
returnTypeStr = generate(returnType);
|
||||
}
|
||||
|
||||
// Generate function signature
|
||||
oss << returnTypeStr << " " << 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 << " // Function body is empty\n";
|
||||
oss << " return;";
|
||||
if (returnTypeStr != "void") {
|
||||
oss << " // TODO: return appropriate value";
|
||||
}
|
||||
oss << "\n";
|
||||
} 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";
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitVariable(const Variable* variable) override {
|
||||
std::ostringstream oss;
|
||||
|
||||
auto type = variable->getChild("type");
|
||||
std::string typeStr = "auto"; // Default
|
||||
if (type) {
|
||||
typeStr = generate(type);
|
||||
}
|
||||
|
||||
// Check enclosing function for memory annotations that affect variable types
|
||||
std::string wrapper = getMemoryTypeWrapper(variable);
|
||||
if (!wrapper.empty()) {
|
||||
oss << wrapper << "<" << typeStr << "> " << variable->name;
|
||||
} else {
|
||||
oss << typeStr << " " << variable->name;
|
||||
}
|
||||
|
||||
auto initializer = variable->getChild("initializer");
|
||||
if (initializer) {
|
||||
oss << " = " << generate(initializer);
|
||||
}
|
||||
|
||||
oss << ";";
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitParameter(const Parameter* parameter) override {
|
||||
std::ostringstream oss;
|
||||
|
||||
auto type = parameter->getChild("type");
|
||||
std::string typeStr = "auto"; // Default
|
||||
if (type) {
|
||||
typeStr = generate(type);
|
||||
}
|
||||
|
||||
oss << typeStr << " " << parameter->name;
|
||||
|
||||
// Add default value if present
|
||||
auto defaultValue = parameter->getChild("defaultValue");
|
||||
if (defaultValue) {
|
||||
oss << " = " << generate(defaultValue);
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitAssignment(const Assignment* assignment) override {
|
||||
std::ostringstream oss;
|
||||
|
||||
auto target = assignment->getChild("target");
|
||||
auto value = assignment->getChild("value");
|
||||
|
||||
if (target) {
|
||||
oss << generate(target) << " = ";
|
||||
} else {
|
||||
oss << "/* missing target */ ";
|
||||
}
|
||||
|
||||
if (value) {
|
||||
oss << generate(value);
|
||||
} else {
|
||||
oss << "/* missing value */";
|
||||
}
|
||||
|
||||
oss << ";";
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitReturn(const Return* ret) override {
|
||||
std::ostringstream oss;
|
||||
oss << "return ";
|
||||
|
||||
auto value = ret->getChild("value");
|
||||
if (value) {
|
||||
oss << generate(value);
|
||||
} else {
|
||||
// For void returns
|
||||
oss << ";";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
oss << ";";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitBinaryOperation(const BinaryOperation* binOp) override {
|
||||
std::ostringstream oss;
|
||||
|
||||
auto left = binOp->getChild("left");
|
||||
auto right = binOp->getChild("right");
|
||||
|
||||
if (left) {
|
||||
oss << generate(left);
|
||||
} else {
|
||||
oss << "/* missing left */";
|
||||
}
|
||||
|
||||
oss << " " << binOp->op << " ";
|
||||
|
||||
if (right) {
|
||||
oss << generate(right);
|
||||
} else {
|
||||
oss << "/* missing right */";
|
||||
}
|
||||
|
||||
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 C++, strings need to be enclosed in double quotes
|
||||
return "\"" + lit->value + "\"";
|
||||
}
|
||||
|
||||
std::string visitBooleanLiteral(const BooleanLiteral* lit) override {
|
||||
return lit->value ? "true" : "false";
|
||||
}
|
||||
|
||||
std::string visitNullLiteral(const NullLiteral* lit) override {
|
||||
return "nullptr";
|
||||
}
|
||||
|
||||
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 << "true"; // fallback
|
||||
}
|
||||
oss << ") {\n";
|
||||
|
||||
// Then branch
|
||||
for (const auto* thenStmt : thenBranch) {
|
||||
std::string stmtCode = generate(thenStmt);
|
||||
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 << "}";
|
||||
|
||||
// Else branch
|
||||
if (!elseBranch.empty()) {
|
||||
oss << " else {\n";
|
||||
for (const auto* elseStmt : elseBranch) {
|
||||
std::string stmtCode = generate(elseStmt);
|
||||
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 << "}";
|
||||
}
|
||||
|
||||
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 << "true"; // fallback to infinite loop
|
||||
}
|
||||
oss << ") {\n";
|
||||
|
||||
for (const auto* stmt : body) {
|
||||
std::string stmtCode = generate(stmt);
|
||||
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 << "}";
|
||||
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 << "for (auto& " << iterator << " : ";
|
||||
if (iterable) {
|
||||
oss << generate(iterable);
|
||||
} else {
|
||||
oss << "/* missing iterable */"; // fallback
|
||||
}
|
||||
oss << ") {\n";
|
||||
|
||||
for (const auto* stmt : body) {
|
||||
std::string stmtCode = generate(stmt);
|
||||
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 << "}";
|
||||
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 << ";"; // Empty statement
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitUnaryOperation(const UnaryOperation* unOp) override {
|
||||
std::ostringstream oss;
|
||||
|
||||
auto operand = unOp->getChild("operand");
|
||||
std::string op = unOp->op;
|
||||
|
||||
oss << op << " ";
|
||||
if (operand) {
|
||||
oss << generate(operand);
|
||||
} else {
|
||||
oss << "/* missing operand */";
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitFunctionCall(const FunctionCall* call) override {
|
||||
std::ostringstream oss;
|
||||
oss << call->functionName << "(";
|
||||
|
||||
auto arguments = call->getChildren("arguments");
|
||||
for (size_t i = 0; i < arguments.size(); ++i) {
|
||||
if (i > 0) oss << ", ";
|
||||
oss << generate(arguments[i]);
|
||||
}
|
||||
|
||||
oss << ")";
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitBlock(const Block* block) override {
|
||||
std::ostringstream oss;
|
||||
|
||||
auto statements = block->getChildren("statements");
|
||||
if (statements.empty()) {
|
||||
oss << "{}";
|
||||
} else {
|
||||
oss << "{\n";
|
||||
for (size_t i = 0; i < statements.size(); ++i) {
|
||||
std::string stmtCode = generate(statements[i]);
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (i < statements.size() - 1) oss << "\n";
|
||||
}
|
||||
oss << "}";
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitListLiteral(const ListLiteral* lit) override {
|
||||
std::ostringstream oss;
|
||||
oss << "{";
|
||||
|
||||
auto elements = lit->getChildren("elements");
|
||||
for (size_t i = 0; i < elements.size(); ++i) {
|
||||
if (i > 0) oss << ", ";
|
||||
oss << generate(elements[i]);
|
||||
}
|
||||
|
||||
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) {
|
||||
oss << generate(target);
|
||||
} else {
|
||||
oss << "/* missing target */";
|
||||
}
|
||||
|
||||
oss << "[";
|
||||
if (index) {
|
||||
oss << generate(index);
|
||||
} else {
|
||||
oss << "/* missing index */";
|
||||
}
|
||||
oss << "]";
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitMemberAccess(const MemberAccess* access) override {
|
||||
std::ostringstream oss;
|
||||
|
||||
auto target = access->getChild("target");
|
||||
if (target) {
|
||||
oss << generate(target);
|
||||
} else {
|
||||
oss << "/* missing target */";
|
||||
}
|
||||
|
||||
oss << "." << access->memberName;
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitPrimitiveType(const PrimitiveType* type) override {
|
||||
std::string kind = type->kind;
|
||||
// Map common types to C++ equivalents
|
||||
if (kind == "int") return "int";
|
||||
if (kind == "float") return "float";
|
||||
if (kind == "string") return "std::string";
|
||||
if (kind == "bool") return "bool";
|
||||
if (kind == "char") return "char";
|
||||
if (kind == "double") return "double";
|
||||
if (kind == "long") return "long";
|
||||
if (kind == "short") return "short";
|
||||
if (kind == "byte") return "char"; // C++ doesn't have byte, use char
|
||||
if (kind == "void") return "void";
|
||||
|
||||
return kind; // Return as-is if not a common type
|
||||
}
|
||||
|
||||
std::string visitListType(const ListType* type) override {
|
||||
std::ostringstream oss;
|
||||
oss << "std::vector<";
|
||||
|
||||
auto elementType = type->getChild("elementType");
|
||||
if (elementType) {
|
||||
oss << generate(elementType);
|
||||
} else {
|
||||
oss << "auto"; // Default if no element type specified
|
||||
}
|
||||
|
||||
oss << ">";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitSetType(const SetType* type) override {
|
||||
std::ostringstream oss;
|
||||
oss << "std::set<";
|
||||
|
||||
auto elementType = type->getChild("elementType");
|
||||
if (elementType) {
|
||||
oss << generate(elementType);
|
||||
} else {
|
||||
oss << "auto"; // Default if no element type specified
|
||||
}
|
||||
|
||||
oss << ">";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitMapType(const MapType* type) override {
|
||||
std::ostringstream oss;
|
||||
oss << "std::map<";
|
||||
|
||||
auto keyType = type->getChild("keyType");
|
||||
auto valueType = type->getChild("valueType");
|
||||
|
||||
if (keyType) {
|
||||
oss << generate(keyType);
|
||||
} else {
|
||||
oss << "auto"; // Default if no key type specified
|
||||
}
|
||||
|
||||
oss << ", ";
|
||||
|
||||
if (valueType) {
|
||||
oss << generate(valueType);
|
||||
} else {
|
||||
oss << "auto"; // Default if no value type specified
|
||||
}
|
||||
|
||||
oss << ">";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitTupleType(const TupleType* type) override {
|
||||
std::ostringstream oss;
|
||||
oss << "std::tuple<";
|
||||
|
||||
auto elementTypes = type->getChildren("elementTypes");
|
||||
for (size_t i = 0; i < elementTypes.size(); ++i) {
|
||||
if (i > 0) oss << ", ";
|
||||
oss << generate(elementTypes[i]);
|
||||
}
|
||||
|
||||
oss << ">";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitArrayType(const ArrayType* type) override {
|
||||
std::ostringstream oss;
|
||||
oss << "std::array<";
|
||||
|
||||
auto elementType = type->getChild("elementType");
|
||||
if (elementType) {
|
||||
oss << generate(elementType);
|
||||
} else {
|
||||
oss << "auto"; // Default if no element type specified
|
||||
}
|
||||
|
||||
oss << ", /* size unknown */>";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitOptionalType(const OptionalType* type) override {
|
||||
std::ostringstream oss;
|
||||
oss << "std::optional<";
|
||||
|
||||
auto innerType = type->getChild("innerType");
|
||||
if (innerType) {
|
||||
oss << generate(innerType);
|
||||
} else {
|
||||
oss << "auto"; // Default if no inner type specified
|
||||
}
|
||||
|
||||
oss << ">";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitCustomType(const CustomType* type) override {
|
||||
return type->typeName;
|
||||
}
|
||||
|
||||
std::string visitDerefStrategy(const DerefStrategy* annotation) override {
|
||||
// Generate C++-style comment for deref strategy
|
||||
if (annotation->strategy == "batched") {
|
||||
return "// @deref(batched) - Use batched memory management (smart pointers)";
|
||||
} else if (annotation->strategy == "streamed") {
|
||||
return "// @deref(streamed) - Use streamed memory management (RAII)";
|
||||
} else if (annotation->strategy == "manual") {
|
||||
return "// @deref(manual) - Use manual memory management (new/delete)";
|
||||
} else {
|
||||
return "// @deref(" + annotation->strategy + ") - Memory management strategy";
|
||||
}
|
||||
}
|
||||
|
||||
std::string visitOptimizationLock(const OptimizationLock* annotation) override {
|
||||
return "// @lock(" + annotation->lockedBy + ") - Optimization locked: " + annotation->lockReason;
|
||||
}
|
||||
|
||||
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 + ") - Memory deallocation strategy";
|
||||
}
|
||||
|
||||
std::string visitLifetimeAnnotation(const LifetimeAnnotation* annotation) override {
|
||||
return "// @lifetime(" + annotation->strategy + ") - Object lifetime management";
|
||||
}
|
||||
|
||||
std::string visitReclaimAnnotation(const ReclaimAnnotation* annotation) override {
|
||||
return "// @reclaim(" + annotation->strategy + ") - Memory reclamation strategy";
|
||||
}
|
||||
|
||||
std::string visitOwnerAnnotation(const OwnerAnnotation* annotation) override {
|
||||
return "// @owner(" + annotation->strategy + ") - Ownership management strategy";
|
||||
}
|
||||
|
||||
std::string visitAllocateAnnotation(const AllocateAnnotation* annotation) override {
|
||||
return "// @allocate(" + annotation->strategy + ") - Memory allocation strategy";
|
||||
}
|
||||
|
||||
std::string visitHotColdAnnotation(const HotColdAnnotation* annotation) override {
|
||||
if (annotation->hint == "Hot")
|
||||
return "__attribute__((hot))";
|
||||
if (annotation->hint == "Cold")
|
||||
return "__attribute__((cold))";
|
||||
return "// @hotcold(" + annotation->hint + ")";
|
||||
}
|
||||
|
||||
std::string visitInlineAnnotation(const InlineAnnotation* annotation) override {
|
||||
if (annotation->mode == "Always")
|
||||
return "[[gnu::always_inline]] inline";
|
||||
if (annotation->mode == "Never")
|
||||
return "__attribute__((noinline))";
|
||||
return "inline";
|
||||
}
|
||||
|
||||
std::string visitPureAnnotation(const PureAnnotation*) override {
|
||||
return "[[nodiscard]]";
|
||||
}
|
||||
|
||||
std::string visitConstExprAnnotation(const ConstExprAnnotation*) override {
|
||||
return "constexpr";
|
||||
}
|
||||
|
||||
private:
|
||||
// Check enclosing function's memory annotations to determine smart-pointer wrapper
|
||||
std::string getMemoryTypeWrapper(const Variable* variable) const {
|
||||
const ASTNode* cur = variable->parent;
|
||||
while (cur && cur->conceptType != "Function") {
|
||||
cur = cur->parent;
|
||||
}
|
||||
if (!cur) return "";
|
||||
|
||||
for (auto* anno : cur->getChildren("annotations")) {
|
||||
if (anno->conceptType == "ReclaimAnnotation") {
|
||||
auto* ra = static_cast<const ReclaimAnnotation*>(anno);
|
||||
if (ra->strategy == "Tracing" || ra->strategy == "Cycle")
|
||||
return "std::shared_ptr";
|
||||
}
|
||||
if (anno->conceptType == "LifetimeAnnotation") {
|
||||
auto* la = static_cast<const LifetimeAnnotation*>(anno);
|
||||
if (la->strategy == "RAII")
|
||||
return "std::unique_ptr";
|
||||
}
|
||||
if (anno->conceptType == "OwnerAnnotation") {
|
||||
auto* oa = static_cast<const OwnerAnnotation*>(anno);
|
||||
if (oa->strategy == "Shared_ARC") return "std::shared_ptr";
|
||||
if (oa->strategy == "Single") return "std::unique_ptr";
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
};
|
||||
545
editor/src/ast/ElispGenerator.h
Normal file
545
editor/src/ast/ElispGenerator.h
Normal file
@@ -0,0 +1,545 @@
|
||||
#pragma once
|
||||
#include "ProjectionGenerator.h"
|
||||
|
||||
class ElispGenerator : public ProjectionGenerator {
|
||||
public:
|
||||
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;
|
||||
}
|
||||
|
||||
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";
|
||||
}
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
161
editor/src/ast/ProjectionGenerator.h
Normal file
161
editor/src/ast/ProjectionGenerator.h
Normal file
@@ -0,0 +1,161 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "ASTNode.h"
|
||||
#include "Module.h"
|
||||
#include "Function.h"
|
||||
#include "Variable.h"
|
||||
#include "Parameter.h"
|
||||
#include "Statement.h"
|
||||
#include "Expression.h"
|
||||
#include "Type.h"
|
||||
#include "Annotation.h"
|
||||
|
||||
class ProjectionGenerator {
|
||||
public:
|
||||
virtual ~ProjectionGenerator() = default;
|
||||
|
||||
virtual std::string generate(const ASTNode* node) = 0;
|
||||
virtual std::string visitModule(const Module* module) = 0;
|
||||
virtual std::string visitFunction(const Function* function) = 0;
|
||||
virtual std::string visitVariable(const Variable* variable) = 0;
|
||||
virtual std::string visitParameter(const Parameter* parameter) = 0;
|
||||
virtual std::string visitAssignment(const Assignment* assignment) = 0;
|
||||
virtual std::string visitReturn(const Return* ret) = 0;
|
||||
virtual std::string visitBinaryOperation(const BinaryOperation* binOp) = 0;
|
||||
virtual std::string visitVariableReference(const VariableReference* varRef) = 0;
|
||||
virtual std::string visitIntegerLiteral(const IntegerLiteral* lit) = 0;
|
||||
virtual std::string visitFloatLiteral(const FloatLiteral* lit) = 0;
|
||||
virtual std::string visitStringLiteral(const StringLiteral* lit) = 0;
|
||||
virtual std::string visitBooleanLiteral(const BooleanLiteral* lit) = 0;
|
||||
virtual std::string visitNullLiteral(const NullLiteral* lit) = 0;
|
||||
virtual std::string visitIfStatement(const IfStatement* stmt) = 0;
|
||||
virtual std::string visitWhileLoop(const WhileLoop* loop) = 0;
|
||||
virtual std::string visitForLoop(const ForLoop* loop) = 0;
|
||||
virtual std::string visitExpressionStatement(const ExpressionStatement* stmt) = 0;
|
||||
virtual std::string visitUnaryOperation(const UnaryOperation* unOp) = 0;
|
||||
virtual std::string visitFunctionCall(const FunctionCall* call) = 0;
|
||||
virtual std::string visitBlock(const Block* block) = 0;
|
||||
virtual std::string visitListLiteral(const ListLiteral* lit) = 0;
|
||||
virtual std::string visitIndexAccess(const IndexAccess* access) = 0;
|
||||
virtual std::string visitMemberAccess(const MemberAccess* access) = 0;
|
||||
virtual std::string visitPrimitiveType(const PrimitiveType* type) = 0;
|
||||
virtual std::string visitListType(const ListType* type) = 0;
|
||||
virtual std::string visitSetType(const SetType* type) = 0;
|
||||
virtual std::string visitMapType(const MapType* type) = 0;
|
||||
virtual std::string visitTupleType(const TupleType* type) = 0;
|
||||
virtual std::string visitArrayType(const ArrayType* type) = 0;
|
||||
virtual std::string visitOptionalType(const OptionalType* type) = 0;
|
||||
virtual std::string visitCustomType(const CustomType* type) = 0;
|
||||
virtual std::string visitDerefStrategy(const DerefStrategy* annotation) = 0;
|
||||
virtual std::string visitOptimizationLock(const OptimizationLock* annotation) = 0;
|
||||
virtual std::string visitLangSpecific(const LangSpecific* annotation) = 0;
|
||||
virtual std::string visitDeallocateAnnotation(const DeallocateAnnotation* annotation) = 0;
|
||||
virtual std::string visitLifetimeAnnotation(const LifetimeAnnotation* annotation) = 0;
|
||||
virtual std::string visitReclaimAnnotation(const ReclaimAnnotation* annotation) = 0;
|
||||
virtual std::string visitOwnerAnnotation(const OwnerAnnotation* annotation) = 0;
|
||||
virtual std::string visitAllocateAnnotation(const AllocateAnnotation* annotation) = 0;
|
||||
virtual std::string visitHotColdAnnotation(const HotColdAnnotation* annotation) = 0;
|
||||
virtual std::string visitInlineAnnotation(const InlineAnnotation* annotation) = 0;
|
||||
virtual std::string visitPureAnnotation(const PureAnnotation* annotation) = 0;
|
||||
virtual std::string visitConstExprAnnotation(const ConstExprAnnotation* annotation) = 0;
|
||||
};
|
||||
|
||||
// Shared dispatch: maps conceptType string to the appropriate visit call.
|
||||
// Each generator's generate() calls this instead of duplicating the dispatch chain.
|
||||
template<typename Gen>
|
||||
std::string dispatchGenerate(Gen* gen, const ASTNode* node, const std::string& unknownPrefix) {
|
||||
if (!node) return "";
|
||||
|
||||
if (node->conceptType == "Module") {
|
||||
return gen->visitModule(static_cast<const Module*>(node));
|
||||
} else if (node->conceptType == "Function") {
|
||||
return gen->visitFunction(static_cast<const Function*>(node));
|
||||
} else if (node->conceptType == "Variable") {
|
||||
return gen->visitVariable(static_cast<const Variable*>(node));
|
||||
} else if (node->conceptType == "Parameter") {
|
||||
return gen->visitParameter(static_cast<const Parameter*>(node));
|
||||
} else if (node->conceptType == "Assignment") {
|
||||
return gen->visitAssignment(static_cast<const Assignment*>(node));
|
||||
} else if (node->conceptType == "Return") {
|
||||
return gen->visitReturn(static_cast<const Return*>(node));
|
||||
} else if (node->conceptType == "BinaryOperation") {
|
||||
return gen->visitBinaryOperation(static_cast<const BinaryOperation*>(node));
|
||||
} else if (node->conceptType == "VariableReference") {
|
||||
return gen->visitVariableReference(static_cast<const VariableReference*>(node));
|
||||
} else if (node->conceptType == "IntegerLiteral") {
|
||||
return gen->visitIntegerLiteral(static_cast<const IntegerLiteral*>(node));
|
||||
} else if (node->conceptType == "FloatLiteral") {
|
||||
return gen->visitFloatLiteral(static_cast<const FloatLiteral*>(node));
|
||||
} else if (node->conceptType == "StringLiteral") {
|
||||
return gen->visitStringLiteral(static_cast<const StringLiteral*>(node));
|
||||
} else if (node->conceptType == "BooleanLiteral") {
|
||||
return gen->visitBooleanLiteral(static_cast<const BooleanLiteral*>(node));
|
||||
} else if (node->conceptType == "NullLiteral") {
|
||||
return gen->visitNullLiteral(static_cast<const NullLiteral*>(node));
|
||||
} else if (node->conceptType == "IfStatement") {
|
||||
return gen->visitIfStatement(static_cast<const IfStatement*>(node));
|
||||
} else if (node->conceptType == "WhileLoop") {
|
||||
return gen->visitWhileLoop(static_cast<const WhileLoop*>(node));
|
||||
} else if (node->conceptType == "ForLoop") {
|
||||
return gen->visitForLoop(static_cast<const ForLoop*>(node));
|
||||
} else if (node->conceptType == "ExpressionStatement") {
|
||||
return gen->visitExpressionStatement(static_cast<const ExpressionStatement*>(node));
|
||||
} else if (node->conceptType == "UnaryOperation") {
|
||||
return gen->visitUnaryOperation(static_cast<const UnaryOperation*>(node));
|
||||
} else if (node->conceptType == "FunctionCall") {
|
||||
return gen->visitFunctionCall(static_cast<const FunctionCall*>(node));
|
||||
} else if (node->conceptType == "Block") {
|
||||
return gen->visitBlock(static_cast<const Block*>(node));
|
||||
} else if (node->conceptType == "ListLiteral") {
|
||||
return gen->visitListLiteral(static_cast<const ListLiteral*>(node));
|
||||
} else if (node->conceptType == "IndexAccess") {
|
||||
return gen->visitIndexAccess(static_cast<const IndexAccess*>(node));
|
||||
} else if (node->conceptType == "MemberAccess") {
|
||||
return gen->visitMemberAccess(static_cast<const MemberAccess*>(node));
|
||||
} else if (node->conceptType == "PrimitiveType") {
|
||||
return gen->visitPrimitiveType(static_cast<const PrimitiveType*>(node));
|
||||
} else if (node->conceptType == "ListType") {
|
||||
return gen->visitListType(static_cast<const ListType*>(node));
|
||||
} else if (node->conceptType == "SetType") {
|
||||
return gen->visitSetType(static_cast<const SetType*>(node));
|
||||
} else if (node->conceptType == "MapType") {
|
||||
return gen->visitMapType(static_cast<const MapType*>(node));
|
||||
} else if (node->conceptType == "TupleType") {
|
||||
return gen->visitTupleType(static_cast<const TupleType*>(node));
|
||||
} else if (node->conceptType == "ArrayType") {
|
||||
return gen->visitArrayType(static_cast<const ArrayType*>(node));
|
||||
} else if (node->conceptType == "OptionalType") {
|
||||
return gen->visitOptionalType(static_cast<const OptionalType*>(node));
|
||||
} else if (node->conceptType == "CustomType") {
|
||||
return gen->visitCustomType(static_cast<const CustomType*>(node));
|
||||
} else if (node->conceptType == "DerefStrategy") {
|
||||
return gen->visitDerefStrategy(static_cast<const DerefStrategy*>(node));
|
||||
} else if (node->conceptType == "OptimizationLock") {
|
||||
return gen->visitOptimizationLock(static_cast<const OptimizationLock*>(node));
|
||||
} else if (node->conceptType == "LangSpecific") {
|
||||
return gen->visitLangSpecific(static_cast<const LangSpecific*>(node));
|
||||
} else if (node->conceptType == "DeallocateAnnotation") {
|
||||
return gen->visitDeallocateAnnotation(static_cast<const DeallocateAnnotation*>(node));
|
||||
} else if (node->conceptType == "LifetimeAnnotation") {
|
||||
return gen->visitLifetimeAnnotation(static_cast<const LifetimeAnnotation*>(node));
|
||||
} else if (node->conceptType == "ReclaimAnnotation") {
|
||||
return gen->visitReclaimAnnotation(static_cast<const ReclaimAnnotation*>(node));
|
||||
} else if (node->conceptType == "OwnerAnnotation") {
|
||||
return gen->visitOwnerAnnotation(static_cast<const OwnerAnnotation*>(node));
|
||||
} else if (node->conceptType == "AllocateAnnotation") {
|
||||
return gen->visitAllocateAnnotation(static_cast<const AllocateAnnotation*>(node));
|
||||
} else if (node->conceptType == "HotColdAnnotation") {
|
||||
return gen->visitHotColdAnnotation(static_cast<const HotColdAnnotation*>(node));
|
||||
} else if (node->conceptType == "InlineAnnotation") {
|
||||
return gen->visitInlineAnnotation(static_cast<const InlineAnnotation*>(node));
|
||||
} else if (node->conceptType == "PureAnnotation") {
|
||||
return gen->visitPureAnnotation(static_cast<const PureAnnotation*>(node));
|
||||
} else if (node->conceptType == "ConstExprAnnotation") {
|
||||
return gen->visitConstExprAnnotation(static_cast<const ConstExprAnnotation*>(node));
|
||||
}
|
||||
|
||||
return unknownPrefix + node->conceptType;
|
||||
}
|
||||
577
editor/src/ast/PythonGenerator.h
Normal file
577
editor/src/ast/PythonGenerator.h
Normal file
@@ -0,0 +1,577 @@
|
||||
#pragma once
|
||||
|
||||
#include "ProjectionGenerator.h"
|
||||
|
||||
class PythonGenerator : public ProjectionGenerator {
|
||||
public:
|
||||
std::string generate(const ASTNode* node) override {
|
||||
return dispatchGenerate(this, node, "# Unknown concept: ");
|
||||
}
|
||||
|
||||
std::string visitModule(const Module* module) override {
|
||||
std::ostringstream oss;
|
||||
|
||||
// Add module docstring and basic info
|
||||
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 (these are in the "annotations" role)
|
||||
auto annotations = function->getChildren("annotations");
|
||||
for (const auto* annotation : annotations) {
|
||||
oss << generate(annotation) << "\n";
|
||||
}
|
||||
|
||||
// Generate function signature
|
||||
oss << "def " << 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 << " pass\n";
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitVariable(const Variable* variable) override {
|
||||
std::ostringstream oss;
|
||||
oss << variable->name << " = ";
|
||||
|
||||
auto initializer = variable->getChild("initializer");
|
||||
if (initializer) {
|
||||
oss << generate(initializer);
|
||||
} else {
|
||||
oss << "None";
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitParameter(const Parameter* parameter) override {
|
||||
std::ostringstream oss;
|
||||
oss << parameter->name;
|
||||
|
||||
// Add type annotation if present
|
||||
auto type = parameter->getChild("type");
|
||||
if (type) {
|
||||
oss << ": " << generate(type);
|
||||
}
|
||||
|
||||
// Add default value if present
|
||||
auto defaultValue = parameter->getChild("defaultValue");
|
||||
if (defaultValue) {
|
||||
oss << " = " << generate(defaultValue);
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitAssignment(const Assignment* assignment) override {
|
||||
std::ostringstream oss;
|
||||
|
||||
auto target = assignment->getChild("target");
|
||||
auto value = assignment->getChild("value");
|
||||
|
||||
if (target) {
|
||||
oss << generate(target) << " = ";
|
||||
}
|
||||
|
||||
if (value) {
|
||||
oss << generate(value);
|
||||
} else {
|
||||
oss << "None";
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitReturn(const Return* ret) override {
|
||||
std::ostringstream oss;
|
||||
oss << "return ";
|
||||
|
||||
auto value = ret->getChild("value");
|
||||
if (value) {
|
||||
oss << generate(value);
|
||||
} else {
|
||||
oss << "None";
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitBinaryOperation(const BinaryOperation* binOp) override {
|
||||
std::ostringstream oss;
|
||||
|
||||
auto left = binOp->getChild("left");
|
||||
auto right = binOp->getChild("right");
|
||||
|
||||
if (left) {
|
||||
oss << generate(left);
|
||||
}
|
||||
|
||||
oss << " " << binOp->op << " ";
|
||||
|
||||
if (right) {
|
||||
oss << generate(right);
|
||||
}
|
||||
|
||||
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 {
|
||||
return "\"" + lit->value + "\"";
|
||||
}
|
||||
|
||||
std::string visitBooleanLiteral(const BooleanLiteral* lit) override {
|
||||
return lit->value ? "True" : "False";
|
||||
}
|
||||
|
||||
std::string visitNullLiteral(const NullLiteral* lit) override {
|
||||
return "None";
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
if (condition) {
|
||||
oss << "if " << generate(condition) << ":\n";
|
||||
} else {
|
||||
oss << "if True:\n"; // fallback
|
||||
}
|
||||
|
||||
// Then branch
|
||||
for (const auto* thenStmt : thenBranch) {
|
||||
std::string stmtCode = generate(thenStmt);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Else branch
|
||||
if (!elseBranch.empty()) {
|
||||
oss << "else:\n";
|
||||
for (const auto* elseStmt : elseBranch) {
|
||||
std::string stmtCode = generate(elseStmt);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitWhileLoop(const WhileLoop* loop) override {
|
||||
std::ostringstream oss;
|
||||
|
||||
auto condition = loop->getChild("condition");
|
||||
auto body = loop->getChildren("body");
|
||||
|
||||
if (condition) {
|
||||
oss << "while " << generate(condition) << ":\n";
|
||||
} else {
|
||||
oss << "while True:\n"; // fallback
|
||||
}
|
||||
|
||||
for (const auto* stmt : body) {
|
||||
std::string stmtCode = generate(stmt);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitForLoop(const ForLoop* loop) override {
|
||||
std::ostringstream oss;
|
||||
|
||||
auto iterable = loop->getChild("iterable");
|
||||
auto body = loop->getChildren("body");
|
||||
|
||||
if (loop->iteratorName.empty()) {
|
||||
oss << "for item";
|
||||
} else {
|
||||
oss << "for " << loop->iteratorName;
|
||||
}
|
||||
|
||||
if (iterable) {
|
||||
oss << " in " << generate(iterable) << ":\n";
|
||||
} else {
|
||||
oss << " in []:\n"; // fallback
|
||||
}
|
||||
|
||||
for (const auto* stmt : body) {
|
||||
std::string stmtCode = generate(stmt);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitExpressionStatement(const ExpressionStatement* stmt) override {
|
||||
std::ostringstream oss;
|
||||
|
||||
auto expr = stmt->getChild("expression");
|
||||
if (expr) {
|
||||
oss << generate(expr);
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitUnaryOperation(const UnaryOperation* unOp) override {
|
||||
std::ostringstream oss;
|
||||
oss << unOp->op << " ";
|
||||
|
||||
auto operand = unOp->getChild("operand");
|
||||
if (operand) {
|
||||
oss << generate(operand);
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitFunctionCall(const FunctionCall* call) override {
|
||||
std::ostringstream oss;
|
||||
oss << call->functionName << "(";
|
||||
|
||||
auto arguments = call->getChildren("arguments");
|
||||
for (size_t i = 0; i < arguments.size(); ++i) {
|
||||
if (i > 0) oss << ", ";
|
||||
oss << generate(arguments[i]);
|
||||
}
|
||||
|
||||
oss << ")";
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitBlock(const Block* block) override {
|
||||
std::ostringstream oss;
|
||||
|
||||
auto statements = block->getChildren("statements");
|
||||
for (size_t i = 0; i < statements.size(); ++i) {
|
||||
if (i > 0) oss << "\n";
|
||||
oss << generate(statements[i]);
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitListLiteral(const ListLiteral* lit) override {
|
||||
std::ostringstream oss;
|
||||
oss << "[";
|
||||
|
||||
auto elements = lit->getChildren("elements");
|
||||
for (size_t i = 0; i < elements.size(); ++i) {
|
||||
if (i > 0) oss << ", ";
|
||||
oss << generate(elements[i]);
|
||||
}
|
||||
|
||||
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) {
|
||||
oss << generate(target);
|
||||
}
|
||||
|
||||
oss << "[";
|
||||
if (index) {
|
||||
oss << generate(index);
|
||||
}
|
||||
oss << "]";
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitMemberAccess(const MemberAccess* access) override {
|
||||
std::ostringstream oss;
|
||||
|
||||
auto target = access->getChild("target");
|
||||
if (target) {
|
||||
oss << generate(target);
|
||||
}
|
||||
|
||||
oss << "." << access->memberName;
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitPrimitiveType(const PrimitiveType* type) override {
|
||||
std::string kind = type->kind;
|
||||
// Map common types to Python equivalents
|
||||
if (kind == "int") return "int";
|
||||
if (kind == "float") return "float";
|
||||
if (kind == "string") return "str";
|
||||
if (kind == "bool") return "bool";
|
||||
if (kind == "char") return "str"; // Python doesn't have char, use str
|
||||
if (kind == "double") return "float";
|
||||
if (kind == "long") return "int";
|
||||
if (kind == "short") return "int";
|
||||
if (kind == "byte") return "int";
|
||||
if (kind == "void") return "None";
|
||||
|
||||
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 << "Any";
|
||||
}
|
||||
|
||||
oss << "]";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitSetType(const SetType* type) override {
|
||||
std::ostringstream oss;
|
||||
oss << "Set[";
|
||||
|
||||
auto elementType = type->getChild("elementType");
|
||||
if (elementType) {
|
||||
oss << generate(elementType);
|
||||
} else {
|
||||
oss << "Any";
|
||||
}
|
||||
|
||||
oss << "]";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitMapType(const MapType* type) override {
|
||||
std::ostringstream oss;
|
||||
oss << "Dict[";
|
||||
|
||||
auto keyType = type->getChild("keyType");
|
||||
auto valueType = type->getChild("valueType");
|
||||
|
||||
if (keyType) {
|
||||
oss << generate(keyType);
|
||||
} else {
|
||||
oss << "Any";
|
||||
}
|
||||
|
||||
oss << ", ";
|
||||
|
||||
if (valueType) {
|
||||
oss << generate(valueType);
|
||||
} else {
|
||||
oss << "Any";
|
||||
}
|
||||
|
||||
oss << "]";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitTupleType(const TupleType* type) override {
|
||||
std::ostringstream oss;
|
||||
oss << "Tuple[";
|
||||
|
||||
auto elementTypes = type->getChildren("elementTypes");
|
||||
for (size_t i = 0; i < elementTypes.size(); ++i) {
|
||||
if (i > 0) oss << ", ";
|
||||
oss << generate(elementTypes[i]);
|
||||
}
|
||||
|
||||
oss << "]";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitArrayType(const ArrayType* type) override {
|
||||
std::ostringstream oss;
|
||||
oss << "List[";
|
||||
|
||||
auto elementType = type->getChild("elementType");
|
||||
if (elementType) {
|
||||
oss << generate(elementType);
|
||||
} else {
|
||||
oss << "Any";
|
||||
}
|
||||
|
||||
oss << "]";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitOptionalType(const OptionalType* type) override {
|
||||
std::ostringstream oss;
|
||||
oss << "Optional[";
|
||||
|
||||
auto innerType = type->getChild("innerType");
|
||||
if (innerType) {
|
||||
oss << generate(innerType);
|
||||
} else {
|
||||
oss << "Any";
|
||||
}
|
||||
|
||||
oss << "]";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string visitCustomType(const CustomType* type) override {
|
||||
return type->typeName;
|
||||
}
|
||||
|
||||
std::string visitDerefStrategy(const DerefStrategy* annotation) override {
|
||||
return "# @deref(" + annotation->strategy + ")";
|
||||
}
|
||||
|
||||
std::string visitOptimizationLock(const OptimizationLock* annotation) override {
|
||||
return "# @lock(" + 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 + ") - Memory deallocation strategy";
|
||||
}
|
||||
|
||||
std::string visitLifetimeAnnotation(const LifetimeAnnotation* annotation) override {
|
||||
return "# @lifetime(" + annotation->strategy + ") - Object lifetime management";
|
||||
}
|
||||
|
||||
std::string visitReclaimAnnotation(const ReclaimAnnotation* annotation) override {
|
||||
return "# @reclaim(" + annotation->strategy + ") - Memory reclamation strategy";
|
||||
}
|
||||
|
||||
std::string visitOwnerAnnotation(const OwnerAnnotation* annotation) override {
|
||||
return "# @owner(" + annotation->strategy + ") - Ownership management strategy";
|
||||
}
|
||||
|
||||
std::string visitAllocateAnnotation(const AllocateAnnotation* annotation) override {
|
||||
return "# @allocate(" + annotation->strategy + ") - Memory allocation 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";
|
||||
}
|
||||
};
|
||||
1855
editor/src/main.cpp
1855
editor/src/main.cpp
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user