mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-25 06:14:59 +00:00
373 lines
9.9 KiB
Lua
373 lines
9.9 KiB
Lua
-- JSON Script Runtime Executor
|
|
-- Executes script.json definitions at runtime without code generation
|
|
|
|
local M = {}
|
|
|
|
-- Reference resolver - resolves $ref:path.to.value
|
|
local function resolve_ref(ref, context)
|
|
if type(ref) ~= "string" or not ref:match("^%$ref:") then
|
|
return ref
|
|
end
|
|
|
|
local path = ref:sub(6) -- Remove "$ref:"
|
|
local parts = {}
|
|
for part in path:gmatch("[^.]+") do
|
|
table.insert(parts, part)
|
|
end
|
|
|
|
local value = context
|
|
for _, part in ipairs(parts) do
|
|
if type(value) ~= "table" then
|
|
return nil
|
|
end
|
|
value = value[part]
|
|
end
|
|
|
|
return value
|
|
end
|
|
|
|
-- Expression evaluator
|
|
local function eval_expression(expr, context)
|
|
if type(expr) ~= "table" then
|
|
return resolve_ref(expr, context)
|
|
end
|
|
|
|
local expr_type = expr.type
|
|
|
|
-- Literal values
|
|
if expr_type == "string_literal" then
|
|
return expr.value
|
|
elseif expr_type == "number_literal" then
|
|
return expr.value
|
|
elseif expr_type == "boolean_literal" then
|
|
return expr.value
|
|
elseif expr_type == "null_literal" then
|
|
return nil
|
|
end
|
|
|
|
-- Template literals
|
|
if expr_type == "template_literal" then
|
|
local template = expr.template
|
|
-- Simple interpolation ${variable}
|
|
return template:gsub("%${([^}]+)}", function(varPath)
|
|
local ref = "$ref:" .. varPath
|
|
local value = resolve_ref(ref, context)
|
|
return tostring(value or "")
|
|
end)
|
|
end
|
|
|
|
-- Binary expressions
|
|
if expr_type == "binary_expression" then
|
|
local left = eval_expression(expr.left, context)
|
|
local right = eval_expression(expr.right, context)
|
|
local op = expr.operator
|
|
|
|
if op == "+" then return left + right
|
|
elseif op == "-" then return left - right
|
|
elseif op == "*" then return left * right
|
|
elseif op == "/" then return left / right
|
|
elseif op == "%" then return left % right
|
|
elseif op == "==" or op == "===" then return left == right
|
|
elseif op == "!=" or op == "~=" or op == "!==" then return left ~= right
|
|
elseif op == "<" then return left < right
|
|
elseif op == ">" then return left > right
|
|
elseif op == "<=" then return left <= right
|
|
elseif op == ">=" then return left >= right
|
|
end
|
|
end
|
|
|
|
-- Logical expressions (short-circuit evaluation)
|
|
if expr_type == "logical_expression" then
|
|
local op = expr.operator
|
|
|
|
if op == "&&" or op == "and" then
|
|
local left = eval_expression(expr.left, context)
|
|
if not left then return left end -- Short-circuit
|
|
return eval_expression(expr.right, context)
|
|
elseif op == "||" or op == "or" then
|
|
local left = eval_expression(expr.left, context)
|
|
if left then return left end -- Short-circuit
|
|
return eval_expression(expr.right, context)
|
|
elseif op == "??" then
|
|
local left = eval_expression(expr.left, context)
|
|
if left ~= nil then return left end -- Null coalescing
|
|
return eval_expression(expr.right, context)
|
|
end
|
|
end
|
|
|
|
-- Unary expressions
|
|
if expr_type == "unary_expression" then
|
|
local arg = eval_expression(expr.argument, context)
|
|
local op = expr.operator
|
|
|
|
if op == "!" or op == "not" then return not arg
|
|
elseif op == "-" then return -arg
|
|
elseif op == "+" then return arg
|
|
elseif op == "~" then return ~arg -- Bitwise NOT (Lua 5.3+)
|
|
end
|
|
end
|
|
|
|
-- Conditional expression (ternary)
|
|
if expr_type == "conditional_expression" then
|
|
local test = eval_expression(expr.test, context)
|
|
if test then
|
|
return eval_expression(expr.consequent, context)
|
|
else
|
|
return eval_expression(expr.alternate, context)
|
|
end
|
|
end
|
|
|
|
-- Member access
|
|
if expr_type == "member_access" then
|
|
local obj = eval_expression(expr.object, context)
|
|
if type(obj) == "table" then
|
|
-- Computed property access
|
|
if expr.computed then
|
|
local prop = eval_expression(expr.property, context)
|
|
return obj[prop]
|
|
else
|
|
return obj[expr.property]
|
|
end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
-- Call expression
|
|
if expr_type == "call_expression" then
|
|
local callee = resolve_ref(expr.callee, context)
|
|
local args = {}
|
|
if expr.args then
|
|
for _, arg in ipairs(expr.args) do
|
|
table.insert(args, eval_expression(arg, context))
|
|
end
|
|
end
|
|
|
|
if type(callee) == "function" then
|
|
return callee(table.unpack(args))
|
|
end
|
|
end
|
|
|
|
-- Object literal
|
|
if expr_type == "object_literal" then
|
|
local obj = {}
|
|
if expr.properties then
|
|
for key, value in pairs(expr.properties) do
|
|
obj[key] = eval_expression(value, context)
|
|
end
|
|
end
|
|
return obj
|
|
end
|
|
|
|
-- Array literal
|
|
if expr_type == "array_literal" then
|
|
local arr = {}
|
|
if expr.elements then
|
|
for _, elem in ipairs(expr.elements) do
|
|
table.insert(arr, eval_expression(elem, context))
|
|
end
|
|
end
|
|
return arr
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
-- Statement executor
|
|
local function execute_statement(stmt, context)
|
|
local stmt_type = stmt.type
|
|
|
|
-- Variable declarations
|
|
if stmt_type == "const_declaration" or stmt_type == "let_declaration" then
|
|
local name = stmt.name
|
|
local value = eval_expression(stmt.value, context)
|
|
context.local_vars = context.local_vars or {}
|
|
context.local_vars[name] = value
|
|
return nil
|
|
end
|
|
|
|
-- Assignment
|
|
if stmt_type == "assignment" then
|
|
local target = stmt.target
|
|
local value = eval_expression(stmt.value, context)
|
|
-- Simple variable assignment
|
|
if type(target) == "string" then
|
|
context.local_vars = context.local_vars or {}
|
|
context.local_vars[target] = value
|
|
end
|
|
return nil
|
|
end
|
|
|
|
-- If statement
|
|
if stmt_type == "if_statement" then
|
|
local condition = eval_expression(stmt.condition, context)
|
|
if condition then
|
|
if stmt.then then
|
|
for _, s in ipairs(stmt.then) do
|
|
local result = execute_statement(s, context)
|
|
if result and result.type == "return" then
|
|
return result
|
|
end
|
|
end
|
|
end
|
|
elseif stmt.else then
|
|
for _, s in ipairs(stmt.else) do
|
|
local result = execute_statement(s, context)
|
|
if result and result.type == "return" then
|
|
return result
|
|
end
|
|
end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
-- Return statement
|
|
if stmt_type == "return" then
|
|
return {
|
|
type = "return",
|
|
value = eval_expression(stmt.value, context)
|
|
}
|
|
end
|
|
|
|
-- Try-catch
|
|
if stmt_type == "try_catch" then
|
|
local success, err = pcall(function()
|
|
if stmt.try then
|
|
for _, s in ipairs(stmt.try) do
|
|
local result = execute_statement(s, context)
|
|
if result and result.type == "return" then
|
|
return result
|
|
end
|
|
end
|
|
end
|
|
end)
|
|
|
|
if not success and stmt.catch then
|
|
context.catch = context.catch or {}
|
|
context.catch.error = err
|
|
for _, s in ipairs(stmt.catch.body) do
|
|
local result = execute_statement(s, context)
|
|
if result and result.type == "return" then
|
|
return result
|
|
end
|
|
end
|
|
end
|
|
|
|
if stmt.finally then
|
|
for _, s in ipairs(stmt.finally) do
|
|
execute_statement(s, context)
|
|
end
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
-- Call expression statement
|
|
if stmt_type == "call_expression" then
|
|
eval_expression(stmt, context)
|
|
return nil
|
|
end
|
|
|
|
-- For-each loop (ipairs/for...of)
|
|
if stmt_type == "for_each_loop" then
|
|
local iterable = eval_expression(stmt.iterable, context)
|
|
if type(iterable) == "table" then
|
|
context.local_vars = context.local_vars or {}
|
|
for _, item in ipairs(iterable) do
|
|
context.local_vars[stmt.iterator] = item
|
|
for _, s in ipairs(stmt.body or {}) do
|
|
local result = execute_statement(s, context)
|
|
if result and result.type == "return" then
|
|
return result
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
-- Comment (ignored at runtime)
|
|
if stmt_type == "comment" then
|
|
return nil
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
-- Execute function from script.json
|
|
function M.execute_function(script_json, function_name, args)
|
|
-- Find function definition
|
|
local func_def = nil
|
|
for _, fn in ipairs(script_json.functions or {}) do
|
|
if fn.name == function_name then
|
|
func_def = fn
|
|
break
|
|
end
|
|
end
|
|
|
|
if not func_def then
|
|
error("Function not found: " .. function_name)
|
|
end
|
|
|
|
-- Build context
|
|
local context = {
|
|
params = {},
|
|
local_vars = {},
|
|
constants = {},
|
|
imports = {},
|
|
functions = {}
|
|
}
|
|
|
|
-- Load constants
|
|
for _, const in ipairs(script_json.constants or {}) do
|
|
context.constants[const.name] = const.value
|
|
end
|
|
|
|
-- Set parameters with defaults
|
|
args = args or {}
|
|
for i, param in ipairs(func_def.params or {}) do
|
|
local value = args[i]
|
|
|
|
-- Handle default values
|
|
if value == nil and param.default ~= nil then
|
|
if type(param.default) == "string" and param.default:match("^%$ref:") then
|
|
value = resolve_ref(param.default, context)
|
|
elseif type(param.default) == "table" then
|
|
value = eval_expression(param.default, context)
|
|
else
|
|
value = param.default
|
|
end
|
|
end
|
|
|
|
context.params[param.name] = value
|
|
end
|
|
|
|
-- Execute function body
|
|
for _, stmt in ipairs(func_def.body or {}) do
|
|
local result = execute_statement(stmt, context)
|
|
if result and result.type == "return" then
|
|
return result.value
|
|
end
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
-- Load and execute script.json file
|
|
function M.load_and_execute(json_path, function_name, args)
|
|
local file = io.open(json_path, "r")
|
|
if not file then
|
|
error("Cannot open file: " .. json_path)
|
|
end
|
|
|
|
local content = file:read("*all")
|
|
file:close()
|
|
|
|
-- Parse JSON (assuming json module available)
|
|
local json = require("json")
|
|
local script_json = json.decode(content)
|
|
|
|
return M.execute_function(script_json, function_name, args)
|
|
end
|
|
|
|
return M
|