Skip to content
Open
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
19 changes: 16 additions & 3 deletions src/glua.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,16 @@ pub fn float(v: Float) -> Value
@external(erlang, "glua_ffi", "coerce")
pub fn table(values: List(#(Value, Value))) -> Value

pub fn alloc_table(lua: Lua, values: List(#(Value, Value))) -> #(Lua, Value) {
let #(val, lua) = do_alloc_table(values, lua)
#(lua, val)
}

pub fn alloc_userdata(lua: Lua, a: anything) -> #(Lua, Value) {
let #(val, lua) = do_alloc_userdata(a, lua)
#(lua, val)
}

pub fn table_decoder(
keys_decoder: decode.Decoder(a),
values_decoder: decode.Decoder(b),
Expand Down Expand Up @@ -333,7 +343,7 @@ pub fn set(
Ok(_) -> Ok(#(keys, lua))

Error(KeyNotFound) -> {
let #(tbl, lua) = alloc_table([], lua)
let #(tbl, lua) = do_alloc_table([], lua)
do_set(lua, keys, tbl)
|> result.map(fn(lua) { #(keys, lua) })
}
Expand Down Expand Up @@ -400,8 +410,11 @@ pub fn set_lua_paths(
set(lua, ["package", "path"], paths)
}

@external(erlang, "luerl_emul", "alloc_table")
fn alloc_table(content: List(a), lua: Lua) -> #(a, Lua)
@external(erlang, "luerl_heap", "alloc_table")
fn do_alloc_table(content: List(a), lua: Lua) -> #(Value, Lua)

@external(erlang, "luerl_heap", "alloc_userdata")
fn do_alloc_userdata(a: anything, lua: Lua) -> #(Value, Lua)

@external(erlang, "glua_ffi", "get_table_keys_dec")
fn do_get(lua: Lua, keys: List(String)) -> Result(dynamic.Dynamic, LuaError)
Expand Down
31 changes: 28 additions & 3 deletions src/glua_ffi.erl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

-export([coerce/1, coerce_nil/0, coerce_userdata/1, wrap_fun/1, sandbox_fun/1, get_table_keys/2, get_table_keys_dec/2,
get_private/2, set_table_keys/3, load/2, load_file/2, eval/2, eval_dec/2, eval_file/2,
eval_file_dec/2, eval_chunk/2, eval_chunk_dec/2, call_function/3, call_function_dec/3]).
eval_file_dec/2, eval_chunk/2, eval_chunk_dec/2, call_function/3, call_function_dec/3,
alloc/2]).

%% turn `{userdata, Data}` into `Data` to make it more easy to decode it in Gleam
maybe_process_userdata(Lst) when is_list(Lst) ->
Expand Down Expand Up @@ -58,6 +59,21 @@ is_encoded({erl_mfa,_,_,_}) ->
is_encoded(_) ->
false.

encode(X, St0) ->
case is_encoded(X) of
true -> {X, St0};
false -> luerl:encode(X, St0)
end.

encode_list(L, St0) when is_list(L) ->
Enc = fun(X, {L1, St}) ->
{Enc, St1} = encode(X, St),
{[Enc | L1], St1}
end,
{L1, St1} = lists:foldl(Enc, {[], St0}, L),
{lists:reverse(L1), St1}.


%% TODO: Improve compiler errors handling and try to detect more errors
map_error({error, [{_, luerl_parse, Errors} | _], _}) ->
FormattedErrors = lists:map(fun(E) -> list_to_binary(E) end, Errors),
Expand Down Expand Up @@ -97,6 +113,15 @@ coerce_nil() ->
coerce_userdata(X) ->
{userdata, X}.

alloc(St0, Value) when is_list(Value) ->
{Enc, St1} = luerl_heap:alloc_table(Value, St0),
{St1, Enc};
alloc(St0, {usrdef,_}=Value) ->
{Enc, St1} = luerl_heap:alloc_userdata(Value, St0),
{St1, Enc};
alloc(St0, Other) ->
{St0, Other}.

wrap_fun(Fun) ->
fun(Args, State) ->
Decoded = luerl:decode_list(Args, State),
Expand Down Expand Up @@ -165,11 +190,11 @@ eval_file_dec(Lua, Path) ->
unicode:characters_to_list(Path), Lua)).

call_function(Lua, Fun, Args) ->
{EncodedArgs, State} = luerl:encode_list(Args, Lua),
{EncodedArgs, State} = encode_list(Args, Lua),
to_gleam(luerl:call(Fun, EncodedArgs, State)).

call_function_dec(Lua, Fun, Args) ->
{EncodedArgs, St1} = luerl:encode_list(Args, Lua),
{EncodedArgs, St1} = encode_list(Args, Lua),
case luerl:call(Fun, EncodedArgs, St1) of
{ok, Ret, St2} ->
Values = luerl:decode_list(Ret, St2),
Expand Down
19 changes: 19 additions & 0 deletions test/glua_test.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -551,3 +551,22 @@ pub fn nested_function_references_test() {
glua.call_function(state: lua, ref:, args: [arg], using: decode.float)
assert result == 20.0
}

pub fn alloc_test() {
let #(lua, table) = glua.alloc_table(glua.new(), [])
let proxy =
glua.function(fn(lua, _args) { #(lua, [glua.string("constant")]) })
let metatable = glua.table([#(glua.string("__index"), proxy)])
let assert Ok(#(lua, _)) =
glua.ref_call_function_by_name(lua, ["setmetatable"], [table, metatable])
let assert Ok(lua) = glua.set(lua, ["test_table"], table)

let assert Ok(#(_lua, [ret1])) =
glua.eval(lua, "return test_table.any_key", decode.string)

let assert Ok(#(_lua, [ret2])) =
glua.eval(lua, "return test_table.other_key", decode.string)

assert ret1 == "constant"
assert ret2 == "constant"
}