AeThex-Engine-Core/engine/modules/aethex_lang/aethex_compiler.cpp
2026-02-24 01:55:30 -07:00

896 lines
24 KiB
C++

/**************************************************************************/
/* aethex_compiler.cpp */
/**************************************************************************/
/* This file is part of: */
/* AETHEX ENGINE */
/* https://aethex.foundation */
/**************************************************************************/
/* Copyright (c) 2026-present AeThex Labs. */
/**************************************************************************/
#include "aethex_compiler.h"
#include "core/io/file_access.h"
void AeThexCompiler::Chunk::write_int(int32_t value) {
code.push_back((value >> 0) & 0xFF);
code.push_back((value >> 8) & 0xFF);
code.push_back((value >> 16) & 0xFF);
code.push_back((value >> 24) & 0xFF);
}
void AeThexCompiler::Chunk::write_float(float value) {
union { float f; int32_t i; } u;
u.f = value;
write_int(u.i);
}
int AeThexCompiler::Chunk::add_constant(const Variant &value) {
constants.push_back(value);
return constants.size() - 1;
}
int AeThexCompiler::Chunk::add_string(const String &str) {
strings.push_back(str);
return strings.size() - 1;
}
AeThexCompiler::AeThexCompiler() {
}
AeThexCompiler::~AeThexCompiler() {
}
void AeThexCompiler::_bind_methods() {
BIND_ENUM_CONSTANT(TARGET_BYTECODE);
BIND_ENUM_CONSTANT(TARGET_LUAU);
BIND_ENUM_CONSTANT(TARGET_VERSE);
BIND_ENUM_CONSTANT(TARGET_CSHARP);
BIND_ENUM_CONSTANT(TARGET_JAVASCRIPT);
}
Error AeThexCompiler::compile(const AeThexParser::ASTNode *root, Target p_target) {
had_error = false;
current_target = p_target;
result = CompiledScript();
result.target = p_target;
if (!root) {
had_error = true;
return ERR_INVALID_PARAMETER;
}
if (p_target == TARGET_BYTECODE) {
current_chunk = &result.main_chunk;
compile_node(root);
emit_return();
} else {
switch (p_target) {
case TARGET_LUAU:
result.output_code = generate_luau(root);
break;
case TARGET_VERSE:
result.output_code = generate_verse(root);
break;
case TARGET_CSHARP:
result.output_code = generate_csharp(root);
break;
case TARGET_JAVASCRIPT:
result.output_code = generate_javascript(root);
break;
default:
break;
}
}
return had_error ? ERR_COMPILATION_FAILED : OK;
}
void AeThexCompiler::compile_node(const AeThexParser::ASTNode *node) {
if (!node) return;
switch (node->type) {
case AeThexParser::ASTNode::NODE_REALITY:
compile_reality(node);
break;
case AeThexParser::ASTNode::NODE_JOURNEY:
compile_journey(node);
break;
case AeThexParser::ASTNode::NODE_BEACON:
compile_beacon(node);
break;
case AeThexParser::ASTNode::NODE_IF:
compile_if(node);
break;
case AeThexParser::ASTNode::NODE_SYNC:
compile_sync(node);
break;
case AeThexParser::ASTNode::NODE_BINARY_OP:
compile_binary(node);
break;
case AeThexParser::ASTNode::NODE_UNARY_OP:
compile_unary(node);
break;
case AeThexParser::ASTNode::NODE_CALL:
compile_call(node);
break;
case AeThexParser::ASTNode::NODE_LITERAL:
compile_literal(node);
break;
case AeThexParser::ASTNode::NODE_IDENTIFIER:
compile_identifier(node);
break;
default:
compile_statement(node);
break;
}
}
void AeThexCompiler::compile_reality(const AeThexParser::ASTNode *node) {
result.reality_name = node->value;
// Extract platforms from attributes
if (node->attributes.has("platforms")) {
String platforms = node->attributes["platforms"];
Vector<String> parts = platforms.split(",");
for (const String &p : parts) {
result.supported_platforms.push_back(p.strip_edges());
}
}
// Compile children
for (const AeThexParser::ASTNode *child : node->children) {
compile_node(child);
}
}
void AeThexCompiler::compile_journey(const AeThexParser::ASTNode *node) {
// Create function chunk
String func_name = node->value;
result.functions[func_name] = Chunk();
Chunk *prev_chunk = current_chunk;
current_chunk = &result.functions[func_name];
begin_scope();
// Parameters are first children until we hit a non-identifier
int param_count = 0;
for (const AeThexParser::ASTNode *child : node->children) {
if (child->type == AeThexParser::ASTNode::NODE_IDENTIFIER && param_count < 10) {
declare_local(child->value, false);
param_count++;
} else {
compile_node(child);
}
}
emit_return();
end_scope();
current_chunk = prev_chunk;
}
void AeThexCompiler::compile_beacon(const AeThexParser::ASTNode *node) {
result.beacons.push_back(node->value);
}
void AeThexCompiler::compile_statement(const AeThexParser::ASTNode *node) {
switch (node->type) {
case AeThexParser::ASTNode::NODE_VARIABLE: {
bool is_const = node->attributes.has("const") && node->attributes["const"] == "true";
declare_local(node->value, is_const);
if (!node->children.is_empty()) {
compile_node(node->children[0]);
} else {
emit_byte(OP_PUSH_NULL);
}
emit_bytes(OP_STORE_LOCAL, resolve_local(node->value));
break;
}
case AeThexParser::ASTNode::NODE_NOTIFY: {
if (!node->children.is_empty()) {
compile_node(node->children[0]);
}
emit_byte(OP_NOTIFY);
break;
}
case AeThexParser::ASTNode::NODE_REVEAL: {
if (!node->children.is_empty()) {
compile_node(node->children[0]);
} else {
emit_byte(OP_PUSH_NULL);
}
emit_byte(OP_RETURN);
break;
}
case AeThexParser::ASTNode::NODE_ASSIGNMENT: {
if (node->children.size() >= 2) {
compile_node(node->children[1]); // Value
if (node->children[0]->type == AeThexParser::ASTNode::NODE_IDENTIFIER) {
int local = resolve_local(node->children[0]->value);
if (local >= 0) {
emit_bytes(OP_STORE_LOCAL, local);
} else {
int idx = current_chunk->add_string(node->children[0]->value);
emit_bytes(OP_STORE_GLOBAL, idx);
}
}
}
break;
}
default:
compile_expression(node);
emit_byte(OP_POP);
break;
}
}
void AeThexCompiler::compile_expression(const AeThexParser::ASTNode *node) {
compile_node(node);
}
void AeThexCompiler::compile_binary(const AeThexParser::ASTNode *node) {
if (node->children.size() < 2) return;
compile_node(node->children[0]);
compile_node(node->children[1]);
String op = node->value;
if (op == "+") emit_byte(OP_ADD);
else if (op == "-") emit_byte(OP_SUB);
else if (op == "*") emit_byte(OP_MUL);
else if (op == "/") emit_byte(OP_DIV);
else if (op == "%") emit_byte(OP_MOD);
else if (op == "==") emit_byte(OP_EQ);
else if (op == "!=") emit_byte(OP_NE);
else if (op == "<") emit_byte(OP_LT);
else if (op == "<=") emit_byte(OP_LE);
else if (op == ">") emit_byte(OP_GT);
else if (op == ">=") emit_byte(OP_GE);
else if (op == "and") emit_byte(OP_AND);
else if (op == "or") emit_byte(OP_OR);
}
void AeThexCompiler::compile_unary(const AeThexParser::ASTNode *node) {
if (node->children.is_empty()) return;
compile_node(node->children[0]);
if (node->value == "-") emit_byte(OP_NEG);
else if (node->value == "not") emit_byte(OP_NOT);
}
void AeThexCompiler::compile_call(const AeThexParser::ASTNode *node) {
if (node->children.is_empty()) return;
// First child is callee, rest are arguments
for (int i = 1; i < node->children.size(); i++) {
compile_node(node->children[i]);
}
compile_node(node->children[0]);
emit_bytes(OP_CALL, node->children.size() - 1);
}
void AeThexCompiler::compile_literal(const AeThexParser::ASTNode *node) {
String val = node->value;
if (val == "null") {
emit_byte(OP_PUSH_NULL);
} else if (val == "true") {
emit_bytes(OP_PUSH_BOOL, 1);
} else if (val == "false") {
emit_bytes(OP_PUSH_BOOL, 0);
} else if (node->attributes.has("type") && node->attributes["type"] == "number") {
if (val.contains(".")) {
emit_byte(OP_PUSH_FLOAT);
current_chunk->write_float(val.to_float());
} else {
emit_byte(OP_PUSH_INT);
current_chunk->write_int(val.to_int());
}
} else {
int idx = current_chunk->add_string(val);
emit_bytes(OP_PUSH_STRING, idx);
}
}
void AeThexCompiler::compile_identifier(const AeThexParser::ASTNode *node) {
int local = resolve_local(node->value);
if (local >= 0) {
emit_bytes(OP_LOAD_LOCAL, local);
} else {
int idx = current_chunk->add_string(node->value);
emit_bytes(OP_LOAD_GLOBAL, idx);
}
}
void AeThexCompiler::compile_if(const AeThexParser::ASTNode *node) {
if (node->children.size() < 2) return;
// Condition
compile_node(node->children[0]);
int then_jump = emit_jump(OP_JUMP_IF_NOT);
emit_byte(OP_POP);
// Then block
if (node->children[1]) {
for (const AeThexParser::ASTNode *stmt : node->children[1]->children) {
compile_node(stmt);
}
}
int else_jump = emit_jump(OP_JUMP);
patch_jump(then_jump);
emit_byte(OP_POP);
// Else block
if (node->children.size() > 2 && node->children[2]) {
for (const AeThexParser::ASTNode *stmt : node->children[2]->children) {
compile_node(stmt);
}
}
patch_jump(else_jump);
}
void AeThexCompiler::compile_sync(const AeThexParser::ASTNode *node) {
if (!node->children.is_empty()) {
compile_node(node->children[0]);
}
emit_byte(OP_SYNC);
}
void AeThexCompiler::emit_byte(uint8_t byte) {
current_chunk->write(byte);
}
void AeThexCompiler::emit_bytes(uint8_t b1, uint8_t b2) {
emit_byte(b1);
emit_byte(b2);
}
void AeThexCompiler::emit_return() {
emit_byte(OP_PUSH_NULL);
emit_byte(OP_RETURN);
}
int AeThexCompiler::emit_jump(Opcode op) {
emit_byte(op);
emit_byte(0xFF);
emit_byte(0xFF);
return current_chunk->code.size() - 2;
}
void AeThexCompiler::patch_jump(int offset) {
int jump = current_chunk->code.size() - offset - 2;
current_chunk->code.write[offset] = (jump >> 0) & 0xFF;
current_chunk->code.write[offset + 1] = (jump >> 8) & 0xFF;
}
void AeThexCompiler::emit_loop(int loop_start) {
emit_byte(OP_LOOP);
int offset = current_chunk->code.size() - loop_start + 2;
emit_byte((offset >> 0) & 0xFF);
emit_byte((offset >> 8) & 0xFF);
}
void AeThexCompiler::begin_scope() {
scope_depth++;
}
void AeThexCompiler::end_scope() {
scope_depth--;
while (!locals.is_empty() && locals[locals.size() - 1].depth > scope_depth) {
emit_byte(OP_POP);
locals.resize(locals.size() - 1);
}
}
void AeThexCompiler::declare_local(const String &name, bool is_const) {
Local local;
local.name = name;
local.depth = scope_depth;
local.is_const = is_const;
locals.push_back(local);
}
int AeThexCompiler::resolve_local(const String &name) {
for (int i = locals.size() - 1; i >= 0; i--) {
if (locals[i].name == name) {
return i;
}
}
return -1;
}
String AeThexCompiler::indent_str(int level) const {
String s;
for (int i = 0; i < level; i++) {
s += " ";
}
return s;
}
// ==========================================
// Luau (Roblox) Code Generation
// ==========================================
String AeThexCompiler::export_to_luau(const AeThexParser::ASTNode *root) {
return generate_luau(root);
}
String AeThexCompiler::generate_luau(const AeThexParser::ASTNode *root) {
String code = "-- Generated by AeThex Compiler\n";
code += "-- Target: Roblox Luau\n\n";
if (root && root->type == AeThexParser::ASTNode::NODE_REALITY) {
code += "local " + root->value + " = {}\n\n";
for (const AeThexParser::ASTNode *child : root->children) {
code += luau_node(child, 0);
}
code += "\nreturn " + root->value + "\n";
}
return code;
}
String AeThexCompiler::luau_node(const AeThexParser::ASTNode *node, int indent) {
if (!node) return "";
String ind = indent_str(indent);
switch (node->type) {
case AeThexParser::ASTNode::NODE_JOURNEY: {
String code = ind + "function " + result.reality_name + "." + node->value + "(";
// Parameters
bool first = true;
for (const AeThexParser::ASTNode *child : node->children) {
if (child->type == AeThexParser::ASTNode::NODE_IDENTIFIER) {
if (!first) code += ", ";
code += child->value;
first = false;
}
}
code += ")\n";
// Body
for (const AeThexParser::ASTNode *child : node->children) {
if (child->type != AeThexParser::ASTNode::NODE_IDENTIFIER) {
code += luau_node(child, indent + 1);
}
}
code += ind + "end\n\n";
return code;
}
case AeThexParser::ASTNode::NODE_BEACON: {
return ind + "-- Beacon (Signal): " + node->value + "\n";
}
case AeThexParser::ASTNode::NODE_VARIABLE: {
String code = ind + "local " + node->value;
if (!node->children.is_empty()) {
code += " = " + luau_node(node->children[0], 0);
}
return code + "\n";
}
case AeThexParser::ASTNode::NODE_NOTIFY: {
String arg = node->children.is_empty() ? "\"\"" : luau_node(node->children[0], 0);
return ind + "print(" + arg + ")\n";
}
case AeThexParser::ASTNode::NODE_REVEAL: {
String val = node->children.is_empty() ? "nil" : luau_node(node->children[0], 0);
return ind + "return " + val + "\n";
}
case AeThexParser::ASTNode::NODE_IF: {
String code = ind + "if " + luau_node(node->children[0], 0) + " then\n";
if (node->children.size() > 1 && node->children[1]) {
for (const AeThexParser::ASTNode *stmt : node->children[1]->children) {
code += luau_node(stmt, indent + 1);
}
}
if (node->children.size() > 2 && node->children[2]) {
code += ind + "else\n";
for (const AeThexParser::ASTNode *stmt : node->children[2]->children) {
code += luau_node(stmt, indent + 1);
}
}
code += ind + "end\n";
return code;
}
case AeThexParser::ASTNode::NODE_SYNC: {
String arg = node->children.is_empty() ? "nil" : luau_node(node->children[0], 0);
return ind + "-- sync: " + arg + "\n" + ind + "task.wait()\n";
}
case AeThexParser::ASTNode::NODE_BINARY_OP: {
String left = node->children.size() > 0 ? luau_node(node->children[0], 0) : "";
String right = node->children.size() > 1 ? luau_node(node->children[1], 0) : "";
return "(" + left + " " + node->value + " " + right + ")";
}
case AeThexParser::ASTNode::NODE_UNARY_OP: {
String operand = node->children.is_empty() ? "" : luau_node(node->children[0], 0);
return node->value + operand;
}
case AeThexParser::ASTNode::NODE_CALL: {
String callee = node->children.is_empty() ? "" : luau_node(node->children[0], 0);
String args;
for (int i = 1; i < node->children.size(); i++) {
if (i > 1) args += ", ";
args += luau_node(node->children[i], 0);
}
return callee + "(" + args + ")";
}
case AeThexParser::ASTNode::NODE_LITERAL: {
if (node->value == "null") return "nil";
if (node->attributes.has("type") && node->attributes["type"] == "string") {
return "\"" + node->value + "\"";
}
return node->value;
}
case AeThexParser::ASTNode::NODE_IDENTIFIER:
return node->value;
default:
return "";
}
}
// ==========================================
// Verse (UEFN) Code Generation
// ==========================================
String AeThexCompiler::export_to_verse(const AeThexParser::ASTNode *root) {
return generate_verse(root);
}
String AeThexCompiler::generate_verse(const AeThexParser::ASTNode *root) {
String code = "# Generated by AeThex Compiler\n";
code += "# Target: UEFN Verse\n\n";
code += "using { /Fortnite.com/Devices }\n";
code += "using { /Verse.org/Simulation }\n\n";
if (root && root->type == AeThexParser::ASTNode::NODE_REALITY) {
code += root->value + " := class(creative_device):\n\n";
for (const AeThexParser::ASTNode *child : root->children) {
code += verse_node(child, 1);
}
}
return code;
}
String AeThexCompiler::verse_node(const AeThexParser::ASTNode *node, int indent) {
if (!node) return "";
String ind = indent_str(indent);
switch (node->type) {
case AeThexParser::ASTNode::NODE_JOURNEY: {
String code = ind + node->value + "(";
// Parameters
bool first = true;
for (const AeThexParser::ASTNode *child : node->children) {
if (child->type == AeThexParser::ASTNode::NODE_IDENTIFIER) {
if (!first) code += ", ";
code += child->value + " : any";
first = false;
}
}
code += ")<suspends> : void =\n";
// Body
for (const AeThexParser::ASTNode *child : node->children) {
if (child->type != AeThexParser::ASTNode::NODE_IDENTIFIER) {
code += verse_node(child, indent + 1);
}
}
return code + "\n";
}
case AeThexParser::ASTNode::NODE_VARIABLE: {
String is_var = (node->attributes.has("const") && node->attributes["const"] == "true") ? "" : "var ";
String code = ind + is_var + node->value + " : any";
if (!node->children.is_empty()) {
code += " = " + verse_node(node->children[0], 0);
}
return code + "\n";
}
case AeThexParser::ASTNode::NODE_NOTIFY: {
String arg = node->children.is_empty() ? "\"\"" : verse_node(node->children[0], 0);
return ind + "Print(" + arg + ")\n";
}
case AeThexParser::ASTNode::NODE_REVEAL: {
return ind + "# return\n";
}
case AeThexParser::ASTNode::NODE_LITERAL: {
if (node->value == "null") return "false";
if (node->value == "true") return "true";
if (node->value == "false") return "false";
if (node->attributes.has("type") && node->attributes["type"] == "string") {
return "\"" + node->value + "\"";
}
return node->value;
}
case AeThexParser::ASTNode::NODE_IDENTIFIER:
return node->value;
default:
return "";
}
}
// ==========================================
// C# (Unity) Code Generation
// ==========================================
String AeThexCompiler::export_to_csharp(const AeThexParser::ASTNode *root) {
return generate_csharp(root);
}
String AeThexCompiler::generate_csharp(const AeThexParser::ASTNode *root) {
String code = "// Generated by AeThex Compiler\n";
code += "// Target: Unity C#\n\n";
code += "using UnityEngine;\n";
code += "using System;\n\n";
if (root && root->type == AeThexParser::ASTNode::NODE_REALITY) {
code += "public class " + root->value + " : MonoBehaviour\n{\n";
for (const AeThexParser::ASTNode *child : root->children) {
code += csharp_node(child, 1);
}
code += "}\n";
}
return code;
}
String AeThexCompiler::csharp_node(const AeThexParser::ASTNode *node, int indent) {
if (!node) return "";
String ind = indent_str(indent);
switch (node->type) {
case AeThexParser::ASTNode::NODE_JOURNEY: {
String code = ind + "public void " + node->value + "(";
// Parameters
bool first = true;
for (const AeThexParser::ASTNode *child : node->children) {
if (child->type == AeThexParser::ASTNode::NODE_IDENTIFIER) {
if (!first) code += ", ";
code += "object " + child->value;
first = false;
}
}
code += ")\n" + ind + "{\n";
// Body
for (const AeThexParser::ASTNode *child : node->children) {
if (child->type != AeThexParser::ASTNode::NODE_IDENTIFIER) {
code += csharp_node(child, indent + 1);
}
}
code += ind + "}\n\n";
return code;
}
case AeThexParser::ASTNode::NODE_BEACON: {
return ind + "public event Action " + node->value + ";\n";
}
case AeThexParser::ASTNode::NODE_VARIABLE: {
String decl = (node->attributes.has("const") && node->attributes["const"] == "true") ? "const " : "";
String code = ind + decl + "var " + node->value;
if (!node->children.is_empty()) {
code += " = " + csharp_node(node->children[0], 0);
}
return code + ";\n";
}
case AeThexParser::ASTNode::NODE_NOTIFY: {
String arg = node->children.is_empty() ? "\"\"" : csharp_node(node->children[0], 0);
return ind + "Debug.Log(" + arg + ");\n";
}
case AeThexParser::ASTNode::NODE_REVEAL: {
String val = node->children.is_empty() ? "" : csharp_node(node->children[0], 0);
return ind + "return" + (val.is_empty() ? "" : " " + val) + ";\n";
}
case AeThexParser::ASTNode::NODE_IF: {
String code = ind + "if (" + csharp_node(node->children[0], 0) + ")\n";
code += ind + "{\n";
if (node->children.size() > 1 && node->children[1]) {
for (const AeThexParser::ASTNode *stmt : node->children[1]->children) {
code += csharp_node(stmt, indent + 1);
}
}
code += ind + "}\n";
if (node->children.size() > 2 && node->children[2]) {
code += ind + "else\n" + ind + "{\n";
for (const AeThexParser::ASTNode *stmt : node->children[2]->children) {
code += csharp_node(stmt, indent + 1);
}
code += ind + "}\n";
}
return code;
}
case AeThexParser::ASTNode::NODE_LITERAL: {
if (node->value == "null") return "null";
if (node->attributes.has("type") && node->attributes["type"] == "string") {
return "\"" + node->value + "\"";
}
return node->value;
}
case AeThexParser::ASTNode::NODE_IDENTIFIER:
return node->value;
default:
return "";
}
}
// ==========================================
// JavaScript (Web) Code Generation
// ==========================================
String AeThexCompiler::export_to_javascript(const AeThexParser::ASTNode *root) {
return generate_javascript(root);
}
String AeThexCompiler::generate_javascript(const AeThexParser::ASTNode *root) {
String code = "// Generated by AeThex Compiler\n";
code += "// Target: JavaScript (Web)\n\n";
if (root && root->type == AeThexParser::ASTNode::NODE_REALITY) {
code += "const " + root->value + " = {\n";
bool first = true;
for (const AeThexParser::ASTNode *child : root->children) {
if (child->type == AeThexParser::ASTNode::NODE_JOURNEY) {
if (!first) code += ",\n";
first = false;
code += js_node(child, 1);
}
}
code += "\n};\n\nexport default " + root->value + ";\n";
}
return code;
}
String AeThexCompiler::js_node(const AeThexParser::ASTNode *node, int indent) {
if (!node) return "";
String ind = indent_str(indent);
switch (node->type) {
case AeThexParser::ASTNode::NODE_JOURNEY: {
String code = ind + node->value + "(";
// Parameters
bool first = true;
for (const AeThexParser::ASTNode *child : node->children) {
if (child->type == AeThexParser::ASTNode::NODE_IDENTIFIER) {
if (!first) code += ", ";
code += child->value;
first = false;
}
}
code += ") {\n";
// Body
for (const AeThexParser::ASTNode *child : node->children) {
if (child->type != AeThexParser::ASTNode::NODE_IDENTIFIER) {
code += js_node(child, indent + 1);
}
}
code += ind + "}";
return code;
}
case AeThexParser::ASTNode::NODE_VARIABLE: {
String decl = (node->attributes.has("const") && node->attributes["const"] == "true") ? "const" : "let";
String code = ind + decl + " " + node->value;
if (!node->children.is_empty()) {
code += " = " + js_node(node->children[0], 0);
}
return code + ";\n";
}
case AeThexParser::ASTNode::NODE_NOTIFY: {
String arg = node->children.is_empty() ? "\"\"" : js_node(node->children[0], 0);
return ind + "console.log(" + arg + ");\n";
}
case AeThexParser::ASTNode::NODE_REVEAL: {
String val = node->children.is_empty() ? "" : js_node(node->children[0], 0);
return ind + "return" + (val.is_empty() ? "" : " " + val) + ";\n";
}
case AeThexParser::ASTNode::NODE_LITERAL: {
if (node->value == "null") return "null";
if (node->attributes.has("type") && node->attributes["type"] == "string") {
return "\"" + node->value + "\"";
}
return node->value;
}
case AeThexParser::ASTNode::NODE_IDENTIFIER:
return node->value;
default:
return "";
}
}
String AeThexCompiler::target_name(Target t) {
switch (t) {
case TARGET_BYTECODE: return "Bytecode";
case TARGET_LUAU: return "Roblox Luau";
case TARGET_VERSE: return "UEFN Verse";
case TARGET_CSHARP: return "Unity C#";
case TARGET_JAVASCRIPT: return "JavaScript";
default: return "Unknown";
}
}
String AeThexCompiler::opcode_name(Opcode op) {
switch (op) {
case OP_PUSH_NULL: return "PUSH_NULL";
case OP_PUSH_BOOL: return "PUSH_BOOL";
case OP_PUSH_INT: return "PUSH_INT";
case OP_PUSH_FLOAT: return "PUSH_FLOAT";
case OP_PUSH_STRING: return "PUSH_STRING";
case OP_POP: return "POP";
case OP_DUP: return "DUP";
case OP_LOAD_LOCAL: return "LOAD_LOCAL";
case OP_STORE_LOCAL: return "STORE_LOCAL";
case OP_LOAD_GLOBAL: return "LOAD_GLOBAL";
case OP_STORE_GLOBAL: return "STORE_GLOBAL";
case OP_ADD: return "ADD";
case OP_SUB: return "SUB";
case OP_MUL: return "MUL";
case OP_DIV: return "DIV";
case OP_CALL: return "CALL";
case OP_RETURN: return "RETURN";
case OP_SYNC: return "SYNC";
case OP_BEACON_EMIT: return "BEACON_EMIT";
case OP_NOTIFY: return "NOTIFY";
default: return "UNKNOWN";
}
}