replace go json with pure lua, much speed
This commit is contained in:
parent
12ba756b95
commit
74faa76dbd
2
.gitignore
vendored
2
.gitignore
vendored
@ -23,6 +23,6 @@ luajit/.git
|
||||
go.work
|
||||
|
||||
# Test directories and files
|
||||
test.lua
|
||||
/*.lua
|
||||
test_fs_dir
|
||||
public
|
@ -1,45 +0,0 @@
|
||||
package json
|
||||
|
||||
import (
|
||||
luajit "git.sharkk.net/Sky/LuaJIT-to-Go"
|
||||
"github.com/goccy/go-json"
|
||||
)
|
||||
|
||||
func GetFunctionList() map[string]luajit.GoFunction {
|
||||
return map[string]luajit.GoFunction{
|
||||
"json_encode": json_encode,
|
||||
"json_decode": json_decode,
|
||||
}
|
||||
}
|
||||
|
||||
func json_encode(s *luajit.State) int {
|
||||
value, err := s.ToValue(1)
|
||||
if err != nil {
|
||||
s.PushNil()
|
||||
s.PushString("failed to read value")
|
||||
return 2
|
||||
}
|
||||
|
||||
data, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
s.PushNil()
|
||||
s.PushString("encoding failed")
|
||||
return 2
|
||||
}
|
||||
|
||||
s.PushString(string(data))
|
||||
return 1
|
||||
}
|
||||
|
||||
func json_decode(s *luajit.State) int {
|
||||
jsonStr := s.ToString(1)
|
||||
var result any
|
||||
if err := json.Unmarshal([]byte(jsonStr), &result); err != nil {
|
||||
s.PushNil()
|
||||
s.PushString("invalid JSON")
|
||||
return 2
|
||||
}
|
||||
|
||||
s.PushValue(result)
|
||||
return 1
|
||||
}
|
@ -1,105 +1,380 @@
|
||||
-- modules/json.lua - High-performance JSON module using Go functions
|
||||
-- modules/json.lua - High-performance JSON module
|
||||
|
||||
local json = {}
|
||||
|
||||
-- Use the fast Go JSON encoder/decoder
|
||||
function json.encode(value)
|
||||
return moonshark.json_encode(value)
|
||||
local buffer = {}
|
||||
local pos = 1
|
||||
|
||||
local function encode_string(s)
|
||||
buffer[pos] = '"'
|
||||
pos = pos + 1
|
||||
|
||||
local start = 1
|
||||
for i = 1, #s do
|
||||
local c = s:byte(i)
|
||||
if c == 34 then -- "
|
||||
if i > start then
|
||||
buffer[pos] = s:sub(start, i - 1)
|
||||
pos = pos + 1
|
||||
end
|
||||
buffer[pos] = '\\"'
|
||||
pos = pos + 1
|
||||
start = i + 1
|
||||
elseif c == 92 then -- \
|
||||
if i > start then
|
||||
buffer[pos] = s:sub(start, i - 1)
|
||||
pos = pos + 1
|
||||
end
|
||||
buffer[pos] = '\\\\'
|
||||
pos = pos + 1
|
||||
start = i + 1
|
||||
elseif c < 32 then
|
||||
if i > start then
|
||||
buffer[pos] = s:sub(start, i - 1)
|
||||
pos = pos + 1
|
||||
end
|
||||
if c == 8 then
|
||||
buffer[pos] = '\\b'
|
||||
elseif c == 9 then
|
||||
buffer[pos] = '\\t'
|
||||
elseif c == 10 then
|
||||
buffer[pos] = '\\n'
|
||||
elseif c == 12 then
|
||||
buffer[pos] = '\\f'
|
||||
elseif c == 13 then
|
||||
buffer[pos] = '\\r'
|
||||
else
|
||||
buffer[pos] = ('\\u%04x'):format(c)
|
||||
end
|
||||
pos = pos + 1
|
||||
start = i + 1
|
||||
end
|
||||
end
|
||||
|
||||
if start <= #s then
|
||||
buffer[pos] = s:sub(start)
|
||||
pos = pos + 1
|
||||
end
|
||||
|
||||
buffer[pos] = '"'
|
||||
pos = pos + 1
|
||||
end
|
||||
|
||||
local function encode_value(v, depth)
|
||||
local t = type(v)
|
||||
|
||||
if t == 'string' then
|
||||
encode_string(v)
|
||||
elseif t == 'number' then
|
||||
if v ~= v then -- NaN
|
||||
buffer[pos] = 'null'
|
||||
elseif v == 1/0 or v == -1/0 then -- Infinity
|
||||
buffer[pos] = 'null'
|
||||
else
|
||||
buffer[pos] = tostring(v)
|
||||
end
|
||||
pos = pos + 1
|
||||
elseif t == 'boolean' then
|
||||
buffer[pos] = v and 'true' or 'false'
|
||||
pos = pos + 1
|
||||
elseif t == 'table' then
|
||||
if depth > 100 then error('circular reference') end
|
||||
|
||||
local is_array = true
|
||||
local max_index = 0
|
||||
local count = 0
|
||||
|
||||
for k, _ in pairs(v) do
|
||||
count = count + 1
|
||||
if type(k) ~= 'number' or k <= 0 or k % 1 ~= 0 then
|
||||
is_array = false
|
||||
break
|
||||
end
|
||||
if k > max_index then max_index = k end
|
||||
end
|
||||
|
||||
if is_array and count == max_index then
|
||||
buffer[pos] = '['
|
||||
pos = pos + 1
|
||||
|
||||
for i = 1, max_index do
|
||||
if i > 1 then
|
||||
buffer[pos] = ','
|
||||
pos = pos + 1
|
||||
end
|
||||
encode_value(v[i], depth + 1)
|
||||
end
|
||||
|
||||
buffer[pos] = ']'
|
||||
pos = pos + 1
|
||||
else
|
||||
buffer[pos] = '{'
|
||||
pos = pos + 1
|
||||
|
||||
local first = true
|
||||
for k, val in pairs(v) do
|
||||
if not first then
|
||||
buffer[pos] = ','
|
||||
pos = pos + 1
|
||||
end
|
||||
first = false
|
||||
|
||||
encode_string(tostring(k))
|
||||
buffer[pos] = ':'
|
||||
pos = pos + 1
|
||||
encode_value(val, depth + 1)
|
||||
end
|
||||
|
||||
buffer[pos] = '}'
|
||||
pos = pos + 1
|
||||
end
|
||||
else
|
||||
buffer[pos] = 'null'
|
||||
pos = pos + 1
|
||||
end
|
||||
end
|
||||
|
||||
encode_value(value, 0)
|
||||
return table.concat(buffer)
|
||||
end
|
||||
|
||||
function json.decode(str)
|
||||
local result, err = moonshark.json_decode(str)
|
||||
if result == nil and err then
|
||||
error("json_decode: " .. err)
|
||||
local pos = 1
|
||||
local len = #str
|
||||
|
||||
local function skip_whitespace()
|
||||
while pos <= len do
|
||||
local c = str:byte(pos)
|
||||
if c ~= 32 and c ~= 9 and c ~= 10 and c ~= 13 then break end
|
||||
pos = pos + 1
|
||||
end
|
||||
end
|
||||
|
||||
local function decode_string()
|
||||
local start = pos + 1
|
||||
pos = pos + 1
|
||||
|
||||
while pos <= len do
|
||||
local c = str:byte(pos)
|
||||
if c == 34 then -- "
|
||||
local result = str:sub(start, pos - 1)
|
||||
pos = pos + 1
|
||||
|
||||
if result:find('\\') then
|
||||
result = result:gsub('\\(.)', {
|
||||
['"'] = '"',
|
||||
['\\'] = '\\',
|
||||
['/'] = '/',
|
||||
['b'] = '\b',
|
||||
['f'] = '\f',
|
||||
['n'] = '\n',
|
||||
['r'] = '\r',
|
||||
['t'] = '\t'
|
||||
})
|
||||
result = result:gsub('\\u(%x%x%x%x)', function(hex)
|
||||
return string.char(tonumber(hex, 16))
|
||||
end)
|
||||
end
|
||||
|
||||
return result
|
||||
elseif c == 92 then -- \
|
||||
pos = pos + 2
|
||||
else
|
||||
pos = pos + 1
|
||||
end
|
||||
end
|
||||
|
||||
error('unterminated string')
|
||||
end
|
||||
|
||||
local function decode_number()
|
||||
local start = pos
|
||||
local c = str:byte(pos)
|
||||
|
||||
if c == 45 then pos = pos + 1 end -- -
|
||||
|
||||
c = str:byte(pos)
|
||||
if not c or c < 48 or c > 57 then error('invalid number') end
|
||||
|
||||
if c == 48 then
|
||||
pos = pos + 1
|
||||
else
|
||||
while pos <= len do
|
||||
c = str:byte(pos)
|
||||
if c < 48 or c > 57 then break end
|
||||
pos = pos + 1
|
||||
end
|
||||
end
|
||||
|
||||
if pos <= len and str:byte(pos) == 46 then -- .
|
||||
pos = pos + 1
|
||||
local found_digit = false
|
||||
while pos <= len do
|
||||
c = str:byte(pos)
|
||||
if c < 48 or c > 57 then break end
|
||||
found_digit = true
|
||||
pos = pos + 1
|
||||
end
|
||||
if not found_digit then error('invalid number') end
|
||||
end
|
||||
|
||||
if pos <= len then
|
||||
c = str:byte(pos)
|
||||
if c == 101 or c == 69 then -- e or E
|
||||
pos = pos + 1
|
||||
if pos <= len then
|
||||
c = str:byte(pos)
|
||||
if c == 43 or c == 45 then pos = pos + 1 end -- + or -
|
||||
end
|
||||
local found_digit = false
|
||||
while pos <= len do
|
||||
c = str:byte(pos)
|
||||
if c < 48 or c > 57 then break end
|
||||
found_digit = true
|
||||
pos = pos + 1
|
||||
end
|
||||
if not found_digit then error('invalid number') end
|
||||
end
|
||||
end
|
||||
|
||||
return tonumber(str:sub(start, pos - 1))
|
||||
end
|
||||
|
||||
local function decode_value()
|
||||
skip_whitespace()
|
||||
if pos > len then error('unexpected end') end
|
||||
|
||||
local c = str:byte(pos)
|
||||
|
||||
if c == 34 then -- "
|
||||
return decode_string()
|
||||
elseif c == 123 then -- {
|
||||
local result = {}
|
||||
pos = pos + 1
|
||||
skip_whitespace()
|
||||
|
||||
if pos <= len and str:byte(pos) == 125 then -- }
|
||||
pos = pos + 1
|
||||
return result
|
||||
end
|
||||
|
||||
while true do
|
||||
skip_whitespace()
|
||||
if pos > len or str:byte(pos) ~= 34 then error('expected string key') end
|
||||
|
||||
local key = decode_string()
|
||||
skip_whitespace()
|
||||
|
||||
if pos > len or str:byte(pos) ~= 58 then error('expected :') end
|
||||
pos = pos + 1
|
||||
|
||||
result[key] = decode_value()
|
||||
skip_whitespace()
|
||||
|
||||
if pos > len then error('unexpected end') end
|
||||
c = str:byte(pos)
|
||||
|
||||
if c == 125 then -- }
|
||||
pos = pos + 1
|
||||
return result
|
||||
elseif c == 44 then -- ,
|
||||
pos = pos + 1
|
||||
else
|
||||
error('expected , or }')
|
||||
end
|
||||
end
|
||||
|
||||
elseif c == 91 then -- [
|
||||
local result = {}
|
||||
local index = 1
|
||||
pos = pos + 1
|
||||
skip_whitespace()
|
||||
|
||||
if pos <= len and str:byte(pos) == 93 then -- ]
|
||||
pos = pos + 1
|
||||
return result
|
||||
end
|
||||
|
||||
while true do
|
||||
result[index] = decode_value()
|
||||
index = index + 1
|
||||
skip_whitespace()
|
||||
|
||||
if pos > len then error('unexpected end') end
|
||||
c = str:byte(pos)
|
||||
|
||||
if c == 93 then -- ]
|
||||
pos = pos + 1
|
||||
return result
|
||||
elseif c == 44 then -- ,
|
||||
pos = pos + 1
|
||||
else
|
||||
error('expected , or ]')
|
||||
end
|
||||
end
|
||||
|
||||
elseif c == 116 then -- true
|
||||
if str:sub(pos, pos + 3) == 'true' then
|
||||
pos = pos + 4
|
||||
return true
|
||||
end
|
||||
error('invalid literal')
|
||||
|
||||
elseif c == 102 then -- false
|
||||
if str:sub(pos, pos + 4) == 'false' then
|
||||
pos = pos + 5
|
||||
return false
|
||||
end
|
||||
error('invalid literal')
|
||||
|
||||
elseif c == 110 then -- null
|
||||
if str:sub(pos, pos + 3) == 'null' then
|
||||
pos = pos + 4
|
||||
return nil
|
||||
end
|
||||
error('invalid literal')
|
||||
|
||||
elseif (c >= 48 and c <= 57) or c == 45 then -- 0-9 or -
|
||||
return decode_number()
|
||||
|
||||
else
|
||||
error('unexpected character')
|
||||
end
|
||||
end
|
||||
|
||||
local result = decode_value()
|
||||
skip_whitespace()
|
||||
if pos <= len then error('unexpected content after JSON') end
|
||||
return result
|
||||
end
|
||||
|
||||
-- Pretty print JSON with indentation
|
||||
function json.pretty(value, indent)
|
||||
indent = indent or 2
|
||||
local encoded = json.encode(value)
|
||||
local result = {}
|
||||
local depth = 0
|
||||
local in_string = false
|
||||
local escape_next = false
|
||||
|
||||
for i = 1, #encoded do
|
||||
local char = encoded:sub(i, i)
|
||||
|
||||
if escape_next then
|
||||
table.insert(result, char)
|
||||
escape_next = false
|
||||
elseif char == "\\" and in_string then
|
||||
table.insert(result, char)
|
||||
escape_next = true
|
||||
elseif char == '"' then
|
||||
table.insert(result, char)
|
||||
in_string = not in_string
|
||||
elseif not in_string then
|
||||
if char == "{" or char == "[" then
|
||||
table.insert(result, char)
|
||||
depth = depth + 1
|
||||
table.insert(result, "\n" .. string.rep(" ", depth * indent))
|
||||
elseif char == "}" or char == "]" then
|
||||
depth = depth - 1
|
||||
table.insert(result, "\n" .. string.rep(" ", depth * indent))
|
||||
table.insert(result, char)
|
||||
elseif char == "," then
|
||||
table.insert(result, char)
|
||||
table.insert(result, "\n" .. string.rep(" ", depth * indent))
|
||||
elseif char == ":" then
|
||||
table.insert(result, char .. " ")
|
||||
else
|
||||
table.insert(result, char)
|
||||
end
|
||||
else
|
||||
table.insert(result, char)
|
||||
end
|
||||
end
|
||||
|
||||
return table.concat(result)
|
||||
end
|
||||
|
||||
-- Load JSON from file
|
||||
function json.load_file(filename)
|
||||
if not moonshark.file_exists(filename) then
|
||||
error("File not found: " .. filename)
|
||||
end
|
||||
|
||||
local file = io.open(filename, "r")
|
||||
if not file then
|
||||
error("Cannot open file: " .. filename)
|
||||
end
|
||||
|
||||
|
||||
local content = file:read("*all")
|
||||
file:close()
|
||||
|
||||
|
||||
return json.decode(content)
|
||||
end
|
||||
|
||||
-- Save data to JSON file
|
||||
function json.save_file(filename, data, pretty)
|
||||
local content
|
||||
if pretty then
|
||||
content = json.pretty(data)
|
||||
else
|
||||
content = json.encode(data)
|
||||
end
|
||||
|
||||
function json.save_file(filename, data)
|
||||
local file = io.open(filename, "w")
|
||||
if not file then
|
||||
error("Cannot write to file: " .. filename)
|
||||
end
|
||||
|
||||
file:write(content)
|
||||
|
||||
file:write(json.encode(data))
|
||||
file:close()
|
||||
end
|
||||
|
||||
-- Merge JSON objects
|
||||
function json.merge(...)
|
||||
local result = {}
|
||||
for i = 1, select("#", ...) do
|
||||
local n = select("#", ...)
|
||||
for i = 1, n do
|
||||
local obj = select(i, ...)
|
||||
if type(obj) == "table" then
|
||||
for k, v in pairs(obj) do
|
||||
@ -110,61 +385,217 @@ function json.merge(...)
|
||||
return result
|
||||
end
|
||||
|
||||
-- Extract values by JSONPath-like syntax (simplified)
|
||||
function json.extract(data, path)
|
||||
local parts = moonshark.string_split(path, ".")
|
||||
local current = data
|
||||
|
||||
for _, part in ipairs(parts) do
|
||||
local start = 1
|
||||
local len = #path
|
||||
|
||||
while start <= len do
|
||||
local dot_pos = path:find(".", start, true)
|
||||
local part = dot_pos and path:sub(start, dot_pos - 1) or path:sub(start)
|
||||
|
||||
if type(current) ~= "table" then
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Handle array indices [0], [1], etc.
|
||||
local array_match = part:match("^%[(%d+)%]$")
|
||||
if array_match then
|
||||
local index = tonumber(array_match) + 1 -- Lua is 1-indexed
|
||||
|
||||
local bracket_start, bracket_end = part:find("^%[(%d+)%]$")
|
||||
if bracket_start then
|
||||
local index = tonumber(part:sub(2, -2)) + 1
|
||||
current = current[index]
|
||||
else
|
||||
current = current[part]
|
||||
end
|
||||
|
||||
|
||||
if current == nil then
|
||||
return nil
|
||||
end
|
||||
|
||||
start = dot_pos and dot_pos + 1 or len + 1
|
||||
end
|
||||
|
||||
|
||||
return current
|
||||
end
|
||||
|
||||
-- Validate JSON structure against schema (basic)
|
||||
function json.pretty(value, indent)
|
||||
local buffer = {}
|
||||
local pos = 1
|
||||
indent = indent or " "
|
||||
|
||||
local function encode_string(s)
|
||||
buffer[pos] = '"'
|
||||
pos = pos + 1
|
||||
|
||||
local start = 1
|
||||
for i = 1, #s do
|
||||
local c = s:byte(i)
|
||||
if c == 34 then -- "
|
||||
if i > start then
|
||||
buffer[pos] = s:sub(start, i - 1)
|
||||
pos = pos + 1
|
||||
end
|
||||
buffer[pos] = '\\"'
|
||||
pos = pos + 1
|
||||
start = i + 1
|
||||
elseif c == 92 then -- \
|
||||
if i > start then
|
||||
buffer[pos] = s:sub(start, i - 1)
|
||||
pos = pos + 1
|
||||
end
|
||||
buffer[pos] = '\\\\'
|
||||
pos = pos + 1
|
||||
start = i + 1
|
||||
elseif c < 32 then
|
||||
if i > start then
|
||||
buffer[pos] = s:sub(start, i - 1)
|
||||
pos = pos + 1
|
||||
end
|
||||
if c == 8 then
|
||||
buffer[pos] = '\\b'
|
||||
elseif c == 9 then
|
||||
buffer[pos] = '\\t'
|
||||
elseif c == 10 then
|
||||
buffer[pos] = '\\n'
|
||||
elseif c == 12 then
|
||||
buffer[pos] = '\\f'
|
||||
elseif c == 13 then
|
||||
buffer[pos] = '\\r'
|
||||
else
|
||||
buffer[pos] = ('\\u%04x'):format(c)
|
||||
end
|
||||
pos = pos + 1
|
||||
start = i + 1
|
||||
end
|
||||
end
|
||||
|
||||
if start <= #s then
|
||||
buffer[pos] = s:sub(start)
|
||||
pos = pos + 1
|
||||
end
|
||||
|
||||
buffer[pos] = '"'
|
||||
pos = pos + 1
|
||||
end
|
||||
|
||||
local function encode_value(v, depth)
|
||||
local t = type(v)
|
||||
local current_indent = string.rep(indent, depth)
|
||||
local next_indent = string.rep(indent, depth + 1)
|
||||
|
||||
if t == 'string' then
|
||||
encode_string(v)
|
||||
elseif t == 'number' then
|
||||
if v ~= v then -- NaN
|
||||
buffer[pos] = 'null'
|
||||
elseif v == 1/0 or v == -1/0 then -- Infinity
|
||||
buffer[pos] = 'null'
|
||||
else
|
||||
buffer[pos] = tostring(v)
|
||||
end
|
||||
pos = pos + 1
|
||||
elseif t == 'boolean' then
|
||||
buffer[pos] = v and 'true' or 'false'
|
||||
pos = pos + 1
|
||||
elseif t == 'table' then
|
||||
if depth > 100 then error('circular reference') end
|
||||
|
||||
local is_array = true
|
||||
local max_index = 0
|
||||
local count = 0
|
||||
|
||||
for k, _ in pairs(v) do
|
||||
count = count + 1
|
||||
if type(k) ~= 'number' or k <= 0 or k % 1 ~= 0 then
|
||||
is_array = false
|
||||
break
|
||||
end
|
||||
if k > max_index then max_index = k end
|
||||
end
|
||||
|
||||
if is_array and count == max_index then
|
||||
buffer[pos] = '[\n'
|
||||
pos = pos + 1
|
||||
|
||||
for i = 1, max_index do
|
||||
buffer[pos] = next_indent
|
||||
pos = pos + 1
|
||||
encode_value(v[i], depth + 1)
|
||||
if i < max_index then
|
||||
buffer[pos] = ','
|
||||
pos = pos + 1
|
||||
end
|
||||
buffer[pos] = '\n'
|
||||
pos = pos + 1
|
||||
end
|
||||
|
||||
buffer[pos] = current_indent .. ']'
|
||||
pos = pos + 1
|
||||
else
|
||||
buffer[pos] = '{\n'
|
||||
pos = pos + 1
|
||||
|
||||
local keys = {}
|
||||
for k in pairs(v) do
|
||||
keys[#keys + 1] = k
|
||||
end
|
||||
|
||||
for i, k in ipairs(keys) do
|
||||
buffer[pos] = next_indent
|
||||
pos = pos + 1
|
||||
encode_string(tostring(k))
|
||||
buffer[pos] = ': '
|
||||
pos = pos + 1
|
||||
encode_value(v[k], depth + 1)
|
||||
if i < #keys then
|
||||
buffer[pos] = ','
|
||||
pos = pos + 1
|
||||
end
|
||||
buffer[pos] = '\n'
|
||||
pos = pos + 1
|
||||
end
|
||||
|
||||
buffer[pos] = current_indent .. '}'
|
||||
pos = pos + 1
|
||||
end
|
||||
else
|
||||
buffer[pos] = 'null'
|
||||
pos = pos + 1
|
||||
end
|
||||
end
|
||||
|
||||
encode_value(value, 0)
|
||||
return table.concat(buffer)
|
||||
end
|
||||
|
||||
function json.validate(data, schema)
|
||||
local function validate_value(value, schema_value)
|
||||
local value_type = type(value)
|
||||
local schema_type = schema_value.type
|
||||
|
||||
|
||||
if schema_type and value_type ~= schema_type then
|
||||
return false, "Expected " .. schema_type .. ", got " .. value_type
|
||||
end
|
||||
|
||||
|
||||
if schema_type == "table" and schema_value.properties then
|
||||
local required = schema_value.required
|
||||
for prop, prop_schema in pairs(schema_value.properties) do
|
||||
if schema_value.required and schema_value.required[prop] and value[prop] == nil then
|
||||
local prop_value = value[prop]
|
||||
|
||||
if required and required[prop] and prop_value == nil then
|
||||
return false, "Missing required property: " .. prop
|
||||
end
|
||||
|
||||
if value[prop] ~= nil then
|
||||
local valid, err = validate_value(value[prop], prop_schema)
|
||||
|
||||
if prop_value ~= nil then
|
||||
local valid, err = validate_value(prop_value, prop_schema)
|
||||
if not valid then
|
||||
return false, "Property " .. prop .. ": " .. err
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
return validate_value(data, schema)
|
||||
end
|
||||
|
||||
|
@ -8,7 +8,6 @@ import (
|
||||
"Moonshark/modules/crypto"
|
||||
"Moonshark/modules/fs"
|
||||
"Moonshark/modules/http"
|
||||
"Moonshark/modules/json"
|
||||
"Moonshark/modules/math"
|
||||
lua_string "Moonshark/modules/string"
|
||||
|
||||
@ -35,7 +34,6 @@ func New() *Registry {
|
||||
}
|
||||
|
||||
// Load all Go functions
|
||||
maps.Copy(r.goFuncs, json.GetFunctionList())
|
||||
maps.Copy(r.goFuncs, lua_string.GetFunctionList())
|
||||
maps.Copy(r.goFuncs, math.GetFunctionList())
|
||||
maps.Copy(r.goFuncs, fs.GetFunctionList())
|
||||
|
@ -13,9 +13,16 @@ function assert(condition, message, level)
|
||||
|
||||
level = level or 2
|
||||
local info = debug.getinfo(level, "Sl")
|
||||
local file = info.source:match("@?(.+)") or "unknown"
|
||||
local line = info.currentline or "unknown"
|
||||
local file = info.source
|
||||
|
||||
-- Extract filename from source or use generic name
|
||||
if file:sub(1,1) == "@" then
|
||||
file = file:sub(2) -- Remove @ prefix for files
|
||||
else
|
||||
file = "<script>" -- Generic name for inline scripts
|
||||
end
|
||||
|
||||
local line = info.currentline or "unknown"
|
||||
local error_msg = message or "assertion failed"
|
||||
local full_msg = string.format("%s:%s: %s", file, line, error_msg)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user