Skip to content

Commit

Permalink
Fix callbacks not modifying Luerl state
Browse files Browse the repository at this point in the history
Callbacks passed to functions implemented in Erlang as `erl_func` in the
likes were not updating state correctly.

For example, imagine the following Lua program

```lua
globalVar = { a = 1 }

function modify_global()
  globalVar['b'] = 2
end

external_call(modify_global)

return globalVar
```

`external_call` is a function implemented in Erlang as

```erlang
ExternalFun = fun([Fun], S) ->
    {FunRef, NewState1} = luerl_new:encode(Fun, S),
    io:format("Function ref: ~p~n", [FunRef]),

    {ok, Res, NewState2} = luerl_new:call(FunRef, [], NewState1),
    {Res, NewState2}
end,

State = luerl_new:init(),
{ok, [], State1} = luerl_new:set_table_keys_dec([<<"external_call">>], ExternalFun, State),
```

This program returns

```erlang
% Expected
[[{<<"a">>, 1}, {<<"b">>, 2}]]

% Actual
[[{<<"a">>, 1}}]]
```

- [X] Write a test case that reproduces the problem
- [ ] Fix the root cause
  • Loading branch information
davydog187 committed Oct 22, 2024
1 parent 37991d1 commit 95d3f67
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 3 deletions.
1 change: 1 addition & 0 deletions src/luerl_comp.erl
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ do_passes([], St) -> {ok,St}.
%% The actual compiler passes.

do_scan_file(#luacomp{lfile=Name,opts=Opts}=St) ->
io:fwrite("opening file ~p", [Name]),
%% Read the bytes in a file skipping an initial # line or Windows BOM.
case file:open(Name, [read,{encoding,unicode}]) of
{ok,F} ->
Expand Down
6 changes: 3 additions & 3 deletions src/luerl_new.erl
Original file line number Diff line number Diff line change
Expand Up @@ -423,11 +423,11 @@ decode(#tref{}=T, St, In) ->
decode_table(T, St, In);
decode(#usdref{}=U, St, _) ->
decode_userdata(U, St);
decode(#funref{}=Fun, State, _) ->
F = fun(Args) ->
decode(#funref{}=Fun, _, _) ->
F = fun(Args, State) ->
{Args1, State1} = encode_list(Args, State),
{Ret, State2} = luerl_emul:functioncall(Fun, Args1, State1),
decode_list(Ret, State2)
{decode_list(Ret, State2), State2}
end,
F; %Just a bare fun
decode(#erl_func{code=Fun}, _, _) -> Fun;
Expand Down
26 changes: 26 additions & 0 deletions test/luerl_new_tests.erl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,32 @@

-include_lib("eunit/include/eunit.hrl").


external_modify_global_test() ->
% put(luerl_itrace, true),
State = luerl_new:init(),

ExternalFun = fun([Fun], S) ->
{FunRef, NewState1} = luerl_new:encode(Fun, S),

{ok, Res, NewState2} = luerl_new:call(FunRef, [], NewState1),
{Res, NewState2}
end,

{ok, [], State1} = luerl_new:set_table_keys_dec([<<"external_call">>], ExternalFun, State),

% Define a Lua function that modifies a global variable 'globalVar'
LuaChunk = <<"globalVar = 'before'\n"
"function modify_global(args)\n"
" globalVar = 'after'\n"
"end\n"
"external_call(modify_global)\n" % Pass the function reference
"return globalVar\n">>,

{ok, Res, _State2} = luerl_new:do_dec(LuaChunk, State1),

?assertEqual([<<"after">>], Res).

encode_test() ->
State = luerl_new:init(),
?assertMatch({nil, _State}, luerl_new:encode(nil, State)),
Expand Down

0 comments on commit 95d3f67

Please sign in to comment.