Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "LuaNova"
uuid = "faa88067-b4cd-4998-97ac-8175b58d6ef9"
version = "0.1.6"
version = "0.1.7"

[deps]
EnumX = "4e289a0a-7415-4d19-859d-a7e5c4648b56"
Expand Down
26 changes: 26 additions & 0 deletions src/intermediate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,32 @@ function raw_len(L::LuaState, idx::Integer)
return C.lua_rawlen(L, idx)
end

function is_array_like(L::LuaState, idx::Integer)
if !is_table(L, idx)
return false
end

# Get the length of the array part
array_len = Int(raw_len(L, idx))

# Empty tables default to Dict (more general)
if array_len == 0
return false
end

# Count total number of keys
key_count = 0
C.lua_pushnil(L)
while C.lua_next(L, idx > 0 ? idx : idx - 1) != 0
key_count += 1
lua_pop!(L, 1) # Pop value, keep key for next iteration
end

# It's array-like if all keys are in the array part
# (i.e., total keys == array length)
return key_count == array_len
end

function lua_table_to_vector(L::LuaState, idx::Integer)
if !is_table(L, idx)
error("Value at index $idx is not a table")
Expand Down
7 changes: 6 additions & 1 deletion src/state.jl
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,12 @@ function from_lua(L::LuaState)
elseif type_code == C.LUA_TNIL
args[i] = nothing
elseif type_code == C.LUA_TTABLE
args[i] = lua_table_to_dict(L, i)
# Check if table is array-like or dict-like
if is_array_like(L, i)
args[i] = lua_table_to_vector(L, i)
else
args[i] = lua_table_to_dict(L, i)
end
elseif type_code == C.LUA_TUSERDATA
if C.lua_getmetatable(L, i) != 0 # Check if metatable exists
C.lua_pushstring(L, Base.unsafe_convert(Ptr{Cchar}, pointer("__name")))
Expand Down
21 changes: 17 additions & 4 deletions test/test_table_as_parameter.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,28 @@ end
@define_lua_function is_dict_type

function get_table_value(table, key)
return table[key]
# Handle both Dict and Vector indexing
if table isa Vector
return table[Int(key)]
else
return table[key]
end
end
@define_lua_function get_table_value

function sum_table_values(table)
total = 0.0
for (k, v) in table
if v isa Number
total += v
if table isa Vector
for v in table
if v isa Number
total += v
end
end
else
for (k, v) in table
if v isa Number
total += v
end
end
end
return total
Expand Down
163 changes: 163 additions & 0 deletions test/test_vector_as_parameter.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
module TestVectorAsParameter

using LuaNova
using Test

function is_vector_type(vec)
return vec isa Vector
end
@define_lua_function is_vector_type

function get_vector_element(vec, index)
return vec[Int(index)]
end
@define_lua_function get_vector_element

function sum_vector(vec)
return sum(vec)
end
@define_lua_function sum_vector

function vector_length(vec)
return length(vec)
end
@define_lua_function vector_length

function double_vector(vec)
return vec .* 2
end
@define_lua_function double_vector

function accept_vector_and_scalar(scalar, vec, multiplier)
return scalar + sum(vec) * multiplier
end
@define_lua_function accept_vector_and_scalar

function filter_positive(vec)
return filter(x -> x > 0, vec)
end
@define_lua_function filter_positive

function vector_min_max(vec)
return minimum(vec), maximum(vec)
end
@define_lua_function vector_min_max

function concatenate_vectors(v1, v2)
return vcat(v1, v2)
end
@define_lua_function concatenate_vectors

function reverse_vector(vec)
return reverse(vec)
end
@define_lua_function reverse_vector

@testset "Vector as parameter" begin
L = LuaNova.new_state()
LuaNova.open_libs(L)

@push_lua_function(L, "is_vector_type", is_vector_type)
@push_lua_function(L, "get_vector_element", get_vector_element)
@push_lua_function(L, "sum_vector", sum_vector)
@push_lua_function(L, "vector_length", vector_length)
@push_lua_function(L, "double_vector", double_vector)
@push_lua_function(L, "accept_vector_and_scalar", accept_vector_and_scalar)
@push_lua_function(L, "filter_positive", filter_positive)
@push_lua_function(L, "vector_min_max", vector_min_max)
@push_lua_function(L, "concatenate_vectors", concatenate_vectors)
@push_lua_function(L, "reverse_vector", reverse_vector)

# Test empty table (defaults to Dict, not Vector)
LuaNova.safe_script(L, "result = is_vector_type({})")
LuaNova.get_global(L, "result")
@test LuaNova.to_boolean(L, -1) == false
LuaNova.lua_pop!(L, 1)

# Test vector element access
LuaNova.safe_script(L, "result = get_vector_element({10, 20, 30}, 1)")
LuaNova.get_global(L, "result")
@test LuaNova.to_number(L, -1) == 10.0
LuaNova.lua_pop!(L, 1)

LuaNova.safe_script(L, "result = get_vector_element({10, 20, 30}, 3)")
LuaNova.get_global(L, "result")
@test LuaNova.to_number(L, -1) == 30.0
LuaNova.lua_pop!(L, 1)

# Test sum of vector
LuaNova.safe_script(L, "result = sum_vector({1, 2, 3, 4, 5})")
LuaNova.get_global(L, "result")
@test LuaNova.to_number(L, -1) == 15.0
LuaNova.lua_pop!(L, 1)

# Test vector length
LuaNova.safe_script(L, "result = vector_length({1, 2, 3})")
LuaNova.get_global(L, "result")
@test LuaNova.to_number(L, -1) == 3.0
LuaNova.lua_pop!(L, 1)

LuaNova.safe_script(L, "result = vector_length({})")
LuaNova.get_global(L, "result")
@test LuaNova.to_number(L, -1) == 0.0
LuaNova.lua_pop!(L, 1)

# Test vector transformation
LuaNova.safe_script(L, "result = double_vector({1, 2, 3})")
LuaNova.get_global(L, "result")
@test LuaNova.is_table(L, -1) == true
doubled = LuaNova.lua_table_to_vector(L, -1)
@test doubled == [2.0, 4.0, 6.0]
LuaNova.lua_pop!(L, 1)

# Test vector as one of multiple parameters
LuaNova.safe_script(L, "result = accept_vector_and_scalar(10, {1, 2, 3}, 2)")
LuaNova.get_global(L, "result")
@test LuaNova.to_number(L, -1) == 22.0 # 10 + (1+2+3)*2
LuaNova.lua_pop!(L, 1)

# Test filtering vector
LuaNova.safe_script(L, "result = filter_positive({-2, -1, 0, 1, 2, 3})")
LuaNova.get_global(L, "result")
@test LuaNova.is_table(L, -1) == true
filtered = LuaNova.lua_table_to_vector(L, -1)
@test filtered == [1.0, 2.0, 3.0]
LuaNova.lua_pop!(L, 1)

# Test multiple return values from vector operation
LuaNova.safe_script(L, "min_val, max_val = vector_min_max({5, 2, 8, 1, 9, 3})")
LuaNova.get_global(L, "min_val")
@test LuaNova.to_number(L, -1) == 1.0
LuaNova.lua_pop!(L, 1)
LuaNova.get_global(L, "max_val")
@test LuaNova.to_number(L, -1) == 9.0
LuaNova.lua_pop!(L, 1)

# Test concatenating vectors
LuaNova.safe_script(L, "result = concatenate_vectors({1, 2, 3}, {4, 5, 6})")
LuaNova.get_global(L, "result")
@test LuaNova.is_table(L, -1) == true
concatenated = LuaNova.lua_table_to_vector(L, -1)
@test concatenated == [1.0, 2.0, 3.0, 4.0, 5.0, 6.0]
LuaNova.lua_pop!(L, 1)

# Test reversing a vector
LuaNova.safe_script(L, "result = reverse_vector({1, 2, 3, 4, 5})")
LuaNova.get_global(L, "result")
@test LuaNova.is_table(L, -1) == true
reversed = LuaNova.lua_table_to_vector(L, -1)
@test reversed == [5.0, 4.0, 3.0, 2.0, 1.0]
LuaNova.lua_pop!(L, 1)

# Test that vector type is correctly identified
LuaNova.safe_script(L, "result = is_vector_type({1, 2, 3})")
LuaNova.get_global(L, "result")
@test LuaNova.to_boolean(L, -1) == true
LuaNova.lua_pop!(L, 1)

LuaNova.close(L)

return nothing
end

end
Loading