-module(glua). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/glua.gleam"). -export([exec/2, run/2, then/2, success/1, failure/1, 'try'/2, map/2, fold/2, nil/0, string/1, bool/1, guard/3, int/1, format_error/1, float/1, table/1, table_list/1, table_list_decoder/1, function_decoder/0, userdata/1, function/1, dereference/2, returning/2, returning_multi/2, new/0, gc/1, get/1, get_private/3, set/2, sandbox/2, set_api/2, set_lua_paths/1, set_private/3, delete_private/2, load/1, load_file/1, eval/1, eval_chunk/1, eval_file/1, call_function/2, call_function_by_name/2, index/2, new_index/3, error/1, error_with_level/2, new_sandboxed/1]). -export_type([lua/0, error/1, lua_compile_error/0, lua_compile_error_kind/0, lua_runtime_exception_kind/0, action/2, chunk/0, value/0, never/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. ?MODULEDOC( " A library to embed Lua in Gleam programs.\n" "\n" " Gleam wrapper around [Luerl](https://github.com/rvirding/luerl).\n" ). -type lua() :: any(). -type error(DQP) :: {lua_compile_failure, list(lua_compile_error())} | {lua_runtime_exception, lua_runtime_exception_kind(), lua()} | {key_not_found, list(binary())} | {file_not_found, binary()} | {unexpected_result_type, list(gleam@dynamic@decode:decode_error())} | {custom_error, DQP} | {unknown_error, gleam@dynamic:dynamic_()}. -type lua_compile_error() :: {lua_compile_error, integer(), lua_compile_error_kind(), binary()}. -type lua_compile_error_kind() :: parse | tokenize. -type lua_runtime_exception_kind() :: {illegal_index, binary(), binary()} | {error_call, binary(), gleam@option:option(integer())} | {undefined_function, binary()} | {undefined_method, binary(), binary()} | {bad_arith, binary(), list(binary())} | {badarg, binary(), list(gleam@dynamic:dynamic_())} | {assert_error, binary()} | unknown_exception. -opaque action(DQQ, DQR) :: {action, fun((lua()) -> {ok, {lua(), DQQ}} | {error, error(DQR)})}. -type chunk() :: any(). -type value() :: any(). -type never() :: any(). -file("src/glua.gleam", 325). ?DOC( " Runs an `Action` within a Lua environment and returns both the result\n" " and the updated Lua state in case of no errors.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " let state = glua.new()\n" " let assert Ok(#(new_state, Nil)) =\n" " glua.exec(state, glua.set([\"my_value\"], glua.string(\"Hello!\")))\n" "\n" " glua.exec(\n" " state:,\n" " action: glua.eval(code: \"return my_value\") |> glua.returning_multi(decode.string)\n" " )\n" "\n" " // -> Ok(#(_state, [\"Hello!\"]))\n" " ```\n" ). -spec exec(lua(), action(DRC, DRD)) -> {ok, {lua(), DRC}} | {error, error(DRD)}. exec(Lua, Action) -> (erlang:element(2, Action))(Lua). -file("src/glua.gleam", 301). ?DOC( " Runs an `Action` within a Lua environment.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " let state = glua.new()\n" "\n" " glua.eval(code: \"return 'Hello from Lua!'\")\n" " |> glua.returning_multi(using: decode.string)\n" " |> glua.run(state, _)\n" " // -> Ok(\"Hello from Lua!\")\n" " ```\n" ). -spec run(lua(), action(DQV, DQW)) -> {ok, DQV} | {error, error(DQW)}. run(Lua, Action) -> _pipe = exec(Lua, Action), gleam@result:map(_pipe, fun gleam@pair:second/1). -file("src/glua.gleam", 359). ?DOC( " Composes two `Action`s into a single one, by executing the first one and passing its return value\n" " to a function that returns another `Action`.\n" "\n" " If the first `Action` returns an `Error` when executed, then the function is not called\n" " and the error is returned.\n" "\n" " This function is the most common way to chain together multiple `Action`s.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " let my_value = 1\n" " let assert Ok(#(_state, ret)) = glua.run(glua.new(), {\n" " use _ <- glua.then(glua.set(keys: [\"my_value\"], value: glua.int(my_value)))\n" " glua.get(keys: [\"my_value\"]) |> glua.returning(decode.int)\n" " })\n" "\n" " assert ret == my_value\n" " ```\n" "\n" " ```gleam\n" " glua.run(glua.new(), {\n" " use ret <- glua.then(glua.eval_file(path: \"./my_file.lua\"))\n" " glua.call_function_by_name(path: [\"table\", \"pack\"], args: ret)\n" " })\n" " // -> Error(glua.FileNotFound(\"./my_file.lua\"))\n" " ```\n" ). -spec then(action(DRJ, DRK), fun((DRJ) -> action(DRN, DRK))) -> action(DRN, DRK). then(Action, Next) -> {action, fun(State) -> gleam@result:'try'( (erlang:element(2, Action))(State), fun(_use0) -> {New, Ret} = _use0, (erlang:element(2, Next(Ret)))(New) end ) end}. -file("src/glua.gleam", 429). ?DOC( " Creates an `Action` that always succeeds and returns `value`.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " glua.run(glua.new(), glua.success(\"my value\"))\n" " // -> Ok(\"my_value\")\n" " ```\n" ). -spec success(DSH) -> action(DSH, any()). success(Value) -> {action, fun(State) -> {ok, {State, Value}} end}. -file("src/glua.gleam", 445). ?DOC( " Creates an `Action` that always fails with `glua.CustomError(error)`.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " glua.run(\n" " glua.new(),\n" " glua.failure(\"incorrect number of return values\")\n" " )\n" " // -> Error(glua.CustomError(\"incorrect number of return values\"))\n" " ```\n" ). -spec failure(DSL) -> action(any(), DSL). failure(Error) -> {action, fun(_) -> {error, {custom_error, Error}} end}. -file("src/glua.gleam", 388). ?DOC( " Tries to update the return value of an `Action` by passing it to a function\n" " that yields a result.\n" "\n" " This is a shorthand for writing a case with `glua.then`:\n" "\n" " ```gleam\n" " use fun <- glua.then(glua.get([\"string\", \"reverse\"]))\n" " glua.call_function(fun:, args: [glua.string(\"Hello\")])\n" " |> glua.try(list.first)\n" " |> glua.returning(decode.string)\n" " ```\n" "\n" " as opposed to this:\n" "\n" " ```gleam\n" " use fun <- glua.then(glua.get([\"string\", \"reverse\"]))\n" " use return <- glua.then(glua.call_function(fun, [glua.string(\"Hello\")]))\n" " case return {\n" " [first] -> glua.dereference(ref: first, using: decode.string)\n" " _ -> glua.failure(Nil)\n" " }\n" " ```\n" ). -spec 'try'(action(DRS, DRT), fun((DRS) -> {ok, DRW} | {error, DRT})) -> action(DRW, DRT). 'try'(Action, Fun) -> then(Action, fun(Ret) -> case Fun(Ret) of {ok, X} -> success(X); {error, E} -> failure(E) end end). -file("src/glua.gleam", 500). ?DOC( " Transforms the return value of an `Action` with the provided function.\n" "\n" " If the `Action` returns an `Error` when executed then the function is not called and the\n" " error is returned.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " glua.get(keys: [\"_VERSION\"])\n" " |> glua.returning(using: decode.string)\n" " |> glua.map(fn(version) {\n" " \"glua supports \" <> version\n" " })\n" " |> glua.run(glua.new(), _)\n" " // -> Ok(\"glua supports Lua 5.3\")\n" " ```\n" "\n" " ```gleam\n" " glua.run(glua.new(), {\n" " use n <- glua.map(glua.get(keys: [\"my_number\"]))\n" " n * 2\n" " })\n" " // -> Error(glua.KeyNotFound([\"my_number\"]))\n" " ```\n" ). -spec map(action(DSX, DSY), fun((DSX) -> DTB)) -> action(DTB, DSY). map(Action, Fun) -> {action, fun(State) -> _pipe = (erlang:element(2, Action))(State), gleam@result:map( _pipe, fun(_capture) -> gleam@pair:map_second(_capture, Fun) end ) end}. -file("src/glua.gleam", 521). ?DOC( " Maps a list of elements into a list of `Action`s by calling a function in each element and then flattens\n" " all the `Action`s into a single one.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " let numbers = [9, 16, 25]\n" " let keys = [\"math\", \"sqrt\"]\n" " glua.run(glua.new(), glua.fold(numbers, fn(n) {\n" " glua.call_function_by_name(keys:, args: [glua.int(n)])\n" " |> glua.try(list.first)\n" " |> glua.returning(using: decode.float)\n" " }))\n" " // -> Ok([3.0, 4.0, 5.0])\n" " ```\n" ). -spec fold(list(DTE), fun((DTE) -> action(DTG, DTH))) -> action(list(DTG), DTH). fold(List, Fun) -> {action, fun(State) -> _pipe@1 = gleam@list:try_fold( List, {State, []}, fun(Acc, E) -> {State@1, Results} = Acc, _pipe = (erlang:element(2, Fun(E)))(State@1), gleam@result:map( _pipe, fun(_capture) -> gleam@pair:map_second( _capture, fun(Ret) -> [Ret | Results] end ) end ) end ), gleam@result:map( _pipe@1, fun(_capture@1) -> gleam@pair:map_second(_capture@1, fun lists:reverse/1) end ) end}. -file("src/glua.gleam", 541). -spec nil() -> value(). nil() -> glua_ffi:coerce_nil(). -file("src/glua.gleam", 544). -spec string(binary()) -> value(). string(V) -> glua_ffi:coerce(V). -file("src/glua.gleam", 208). -spec format_decode_error(gleam@dynamic@decode:decode_error()) -> binary(). format_decode_error(Error) -> Base = <<<<<<"Expected "/utf8, (erlang:element(2, Error))/binary>>/binary, ", but found "/utf8>>/binary, (erlang:element(3, Error))/binary>>, case erlang:element(4, Error) of [] -> Base; Path -> <<<>/binary, (gleam@string:join(Path, <<"."/utf8>>))/binary>> end. -file("src/glua.gleam", 547). -spec bool(boolean()) -> value(). bool(V) -> glua_ffi:coerce(V). -file("src/glua.gleam", 413). ?DOC( " Runs a callback function if the given bool is `False`, otherwise return a failing `Action`\n" " using the provided value.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " glua.run(glua.new(), {\n" " use ret <- glua.then(glua.eval(code: \"local a = 1\"))\n" " use <- glua.guard(when: ret == [], return: \"expected at least one value from Lua\")\n" "\n" " glua.fold(ret, glua.dereference(_, using: decode.int))\n" " })\n" " // -> Error(glua.CustomError(\"expected at least one value from Lua\"))\n" " ```\n" ). -spec guard(boolean(), DSB, fun(() -> action(DSC, DSB))) -> action(DSC, DSB). guard(Requirement, Consequence, Alternative) -> gleam@bool:guard(Requirement, failure(Consequence), Alternative). -file("src/glua.gleam", 550). -spec int(integer()) -> value(). int(V) -> glua_ffi:coerce(V). -file("src/glua.gleam", 147). -spec format_compile_error(lua_compile_error()) -> binary(). format_compile_error(Error) -> Kind = case erlang:element(3, Error) of parse -> <<"parse"/utf8>>; tokenize -> <<"tokenize"/utf8>> end, <<<<<<<<<<"Failed to "/utf8, Kind/binary>>/binary, ": error on line "/utf8>>/binary, (erlang:integer_to_binary(erlang:element(2, Error)))/binary>>/binary, ": "/utf8>>/binary, (erlang:element(4, Error))/binary>>. -file("src/glua.gleam", 161). -spec format_exception(lua_runtime_exception_kind()) -> binary(). format_exception(Exception) -> case Exception of {illegal_index, Index, Value} -> <<<<<<<<<<<<<<"Invalid index "/utf8, "\""/utf8>>/binary, Index/binary>>/binary, "\""/utf8>>/binary, " at object "/utf8>>/binary, "\""/utf8>>/binary, Value/binary>>/binary, "\""/utf8>>; {error_call, Msg, Level} -> Base = <<"Error call: "/utf8, Msg/binary>>, case Level of {some, Level@1} -> <<<>/binary, (erlang:integer_to_binary(Level@1))/binary>>; none -> Base end; {undefined_function, Fun} -> <<"Undefined function: "/utf8, Fun/binary>>; {undefined_method, Obj, Method} -> <<<<<<<<<<<<<<"Undefined method "/utf8, "\""/utf8>>/binary, Method/binary>>/binary, "\""/utf8>>/binary, " for object: "/utf8>>/binary, "\""/utf8>>/binary, Obj/binary>>/binary, "\""/utf8>>; {bad_arith, Operator, Args} -> <<"Bad arithmetic expression: "/utf8, (gleam@string:join( Args, <<<<" "/utf8, Operator/binary>>/binary, " "/utf8>> ))/binary>>; {badarg, Function, Args@1} -> <<<<<<"Bad argument "/utf8, (gleam@string:join( gleam@list:map(Args@1, fun luerl_lib:format_value/1), <<", "/utf8>> ))/binary>>/binary, " for function "/utf8>>/binary, Function/binary>>; {assert_error, Msg@1} -> <<"Assertion failed with message: "/utf8, Msg@1/binary>>; unknown_exception -> <<"Unknown exception"/utf8>> end. -file("src/glua.gleam", 121). ?DOC( " Turns a `glua.Error` value into a human-readable string\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " let assert Error(e) = glua.run(glua.new(), glua.eval(\n" " code: \"if true end\",\n" " ))\n" "\n" " glua.format_error(e)\n" " // -> \"Lua compile error: \\n\\nFailed to parse: error on line 1: syntax error before: 'end'\"\n" " ```\n" "\n" " ```gleam\n" " let assert Error(e) = glua.run(glua.new(), glua.eval(\n" " code: \"local a = 1; local b = true; return a + b\",\n" " ))\n" "\n" " glua.format_error(e)\n" " // -> \"Lua runtime exception: Bad arithmetic expression: 1 + true\"\n" " ```\n" "\n" " ```gleam\n" " let assert Error(e) = glua.run(glua.new(), glua.get(\n" " keys: [\"a_value\"],\n" " ))\n" " \n" " glua.format_error(e)\n" " // -> \"Key \\\"a_value\\\" not found\"\n" " ```\n" "\n" " ```gleam\n" " let assert Error(e) = glua.run(glua.new(), glua.eval_file(\n" " path: \"my_lua_file.lua\",\n" " ))\n" "\n" " glua.format_error(e)\n" " // -> \"Lua source file \\\"my_lua_file.lua\\\" not found\"\n" " ```\n" "\n" " ```gleam\n" " let assert Error(e) = glua.run(glua.new(), {\n" " use ret <- glua.then(glua.eval(\n" " code: \"return 1 + 1\",\n" " ))\n" " use ref <- glua.try(list.first(ret))\n" " \n" " glua.dereference(ref:, using: decode.string)\n" " })\n" "\n" " glua.format_error(e)\n" " // -> \"Expected String, but found Int\"\n" " ```\n" ). -spec format_error(error(any())) -> binary(). format_error(Error) -> case Error of {lua_compile_failure, Errors} -> <<<<"Lua compile error: "/utf8, "\n\n"/utf8>>/binary, (gleam@string:join( gleam@list:map(Errors, fun format_compile_error/1), <<"\n"/utf8>> ))/binary>>; {lua_runtime_exception, Exception, State} -> Base = <<"Lua runtime exception: "/utf8, (format_exception(Exception))/binary>>, Stacktrace = glua_ffi:get_stacktrace(State), case Stacktrace of <<""/utf8>> -> Base; Stacktrace@1 -> <<<>/binary, Stacktrace@1/binary>> end; {key_not_found, Path} -> <<<<<<<<"Key "/utf8, "\""/utf8>>/binary, (gleam@string:join(Path, <<"."/utf8>>))/binary>>/binary, "\""/utf8>>/binary, " not found"/utf8>>; {file_not_found, Path@1} -> <<<<<<<<"Lua source file "/utf8, "\""/utf8>>/binary, Path@1/binary>>/binary, "\""/utf8>>/binary, " not found"/utf8>>; {unexpected_result_type, Decode_errors} -> _pipe = gleam@list:map(Decode_errors, fun format_decode_error/1), gleam@string:join(_pipe, <<"\n"/utf8>>); {custom_error, Error@1} -> gleam@string:inspect(Error@1); {unknown_error, Error@2} -> <<"Unknown error: "/utf8, (luerl_lib:format_error(Error@2))/binary>> end. -file("src/glua.gleam", 553). -spec float(float()) -> value(). float(V) -> glua_ffi:coerce(V). -file("src/glua.gleam", 555). -spec table(list({value(), value()})) -> action(value(), any()). table(Values) -> {action, fun(State) -> {ok, begin _pipe = luerl_heap:alloc_table(Values, State), gleam@pair:swap(_pipe) end} end}. -file("src/glua.gleam", 560). -spec table_list(list(value())) -> action(value(), any()). table_list(Values) -> {_, Values@1} = gleam@list:map_fold( Values, 1, fun(Acc, Val) -> {Acc + 1, {glua_ffi:coerce(Acc), Val}} end ), table(Values@1). -file("src/glua.gleam", 597). -spec list_loop(gleam@dict:dict(integer(), DUA), list(DUA), integer()) -> list(DUA). list_loop(Dict, Acc, Idx) -> case gleam_stdlib:map_get(Dict, Idx) of {ok, It} -> list_loop(Dict, [It | Acc], Idx + 1); {error, nil} -> lists:reverse(Acc) end. -file("src/glua.gleam", 591). ?DOC( " A decoder for list-style Lua tables.\n" " This decoder works similarly to ipairs in the sense that it stops\n" " when there is a gap in the table list.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " glua.eval(\"return { 1, 2, 3 }\")\n" " |> glua.try(list.first)\n" " |> glua.returning(glua.table_list_decoder(decode.int))\n" " |> glua.run(glua.new(), _)\n" " // -> Ok([1, 2, 3])\n" " ```\n" "\n" " ```gleam\n" " glua.eval(\"return { [1] = 'a', [2] = 'b', [4] = 'd'}\")\n" " |> glua.try(list.first)\n" " |> glua.returning(glua.table_list_decoder(decode.string))\n" " |> glua.run(glua.new(), _)\n" " // -> Ok([\"a\", \"b\"])\n" " ```\n" ). -spec table_list_decoder(gleam@dynamic@decode:decoder(DTW)) -> gleam@dynamic@decode:decoder(list(DTW)). table_list_decoder(Decoder) -> _pipe = gleam@dynamic@decode:dict( {decoder, fun gleam@dynamic@decode:decode_int/1}, Decoder ), gleam@dynamic@decode:map( _pipe, fun(_capture) -> list_loop(_capture, [], 1) end ). -file("src/glua.gleam", 626). -spec function_decoder() -> gleam@dynamic@decode:decoder(fun((list(value())) -> action(list(value()), any()))). function_decoder() -> gleam@dynamic@decode:new_primitive_decoder( <<"LuaFunction"/utf8>>, fun glua_ffi:decode_fun/1 ). -file("src/glua.gleam", 689). ?DOC( " Encodes any Gleam value as a reference that can be passed to a Lua program.\n" "\n" " Deferencing a userdata value inside Lua code will cause a Lua exception.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " pub type User {\n" " User(name: String, is_admin: Bool)\n" " }\n" "\n" " let user_decoder = {\n" " use name <- decode.field(1, decode.string)\n" " use is_admin <- decode.field(2, decode.bool)\n" " decode.success(User(name:, is_admin:))\n" " }\n" "\n" " glua.run(glua.new(), {\n" " use userdata <- glua.then(userdata(User(\"Jhon Doe\", False)))\n" " use _ <- glua.then(glua.set(\n" " keys: [\"a_user\"],\n" " value: userdata\n" " ))\n" " \n" " glua.eval(code: \"return a_user\")\n" " |> glua.try(list.first)\n" " |> glua.returning(using: user_decoder)\n" " })\n" " // -> Ok(User(\"Jhon Doe\", False))\n" " ```\n" "\n" " ```gleam\n" " pub type Person {\n" " Person(name: String, email: String)\n" " }\n" "\n" " let assert Error(glua.LuaRuntimeException(glua.IllegalIndex(_), _)) =\n" " glua.run(glua.new(), {\n" " use userdata <- glua.then(glua.userdata(\n" " Person(name: \"Lucy\", email: \"lucy@example.com\")\n" " ))\n" " use _ <- glua.then(glua.set(\n" " keys: [\"lucy\"],\n" " value: userdata\n" " ))\n" "\n" " glua.eval(code: \"return lucy.email\")\n" " })\n" " ```\n" ). -spec userdata(any()) -> action(value(), any()). userdata(V) -> {action, fun(State) -> {ok, begin _pipe = luerl_heap:alloc_userdata(V, State), gleam@pair:swap(_pipe) end} end}. -file("src/glua.gleam", 610). ?DOC( " Encodes a Gleam function into a Lua function.\n" "\n" " > **Note**: The function to be encoded has to return an `Action` with a `Never` type\n" " > as the `error` parameter, meaning that the function cannot invoke `glua.failure` in its body.\n" " > If you want to return an error inside that function, you should use `glua.error` or `glua.error_with_code`,\n" " > both of which will call the Lua `error` function.\n" ). -spec function(fun((list(value())) -> action(list(value()), never()))) -> value(). function(F) -> glua_ffi:wrap_fun(F). -file("src/glua.gleam", 727). ?DOC( " Converts a reference to a Lua value into type-safe Gleam data using the provided decoder.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " glua.run(glua.new(), {\n" " use ref <- glua.then(\n" " glua.eval(code: \"return 'Hello from Lua!'\")\n" " |> glua.try(list.first)\n" " )\n" "\n" " glua.dereference(ref:, using: decode.string)\n" " })\n" " // -> Ok(\"Hello from Lua!\")\n" " ```\n" "\n" " ```gleam\n" " let assert Ok(#(state, [ref1, ref2])) = glua.exec(\n" " glua.new(),\n" " glua.eval(code: \"return 1, true\")\n" " )\n" "\n" " let assert Ok(1) =\n" " glua.run(state, glua.dereference(ref: ref1, using: decode.int))\n" " let assert Ok(True) =\n" " glua.run(state, glua.dereference(ref: ref2, using: decode.bool))\n" " ```\n" ). -spec dereference(value(), gleam@dynamic@decode:decoder(DVK)) -> action(DVK, any()). dereference(Ref, Decoder) -> {action, fun(State) -> gleam@result:map( begin _pipe = glua_ffi:dereference(State, Ref), _pipe@1 = gleam@dynamic@decode:run(_pipe, Decoder), gleam@result:map_error( _pipe@1, fun(Field@0) -> {unexpected_result_type, Field@0} end ) end, fun(Ret) -> {State, Ret} end ) end}. -file("src/glua.gleam", 761). ?DOC( " Transforms an `Action` that returns a reference to a Lua value into an `Action` that returns\n" " a typed Gleam value.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " let decoder =\n" " decode.dict(decode.string, decode.int)\n" " |> decode.map(dict.to_list)\n" "\n" " glua.eval(code: \"return { a = 1, b = 2 }\")\n" " |> glua.try(apply: list.first)\n" " |> glua.returning(using: decoder)\n" " |> glua.run(glua.new(), _)\n" "\n" " // -> Ok([#(\"a\", 1), #(\"b\", 2)])\n" " ```\n" ). -spec returning(action(value(), DVP), gleam@dynamic@decode:decoder(DVS)) -> action(DVS, DVP). returning(Act, Decoder) -> then(Act, fun(Ref) -> dereference(Ref, Decoder) end). -file("src/glua.gleam", 771). ?DOC( " Same as `glua.returning`, but works on an `Action` that returns multiple references to Lua values\n" " instead of a single one.\n" ). -spec returning_multi( action(list(value()), DVX), gleam@dynamic@decode:decoder(DWA) ) -> action(list(DWA), DVX). returning_multi(Act, Decoder) -> then( Act, fun(Refs) -> fold(Refs, fun(_capture) -> dereference(_capture, Decoder) end) end ). -file("src/glua.gleam", 781). ?DOC(" Creates a new Lua VM instance\n"). -spec new() -> lua(). new() -> luerl:init(). -file("src/glua.gleam", 844). ?DOC(" Runs the garbage collector on the given Lua state.\n"). -spec gc(lua()) -> lua(). gc(Lua) -> luerl:gc(Lua). -file("src/glua.gleam", 874). ?DOC( " Gets a value in the Lua environment.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " glua.get(keys: [\"_VERSION\"])\n" " |> glua.returning(using: decode.string)\n" " |> glua.run(glua.new(), _)\n" " // -> Ok(\"Lua 5.3\")\n" " ```\n" "\n" " ```gleam\n" " glua.run(glua.new(), {\n" " use _ <- glua.then(glua.set(\n" " keys: [\"my_table\", \"my_value\"],\n" " value: glua.bool(True)\n" " ))\n" "\n" " glua.get(keys: [\"my_table\", \"my_value\"]))\n" " |> glua.returning(using: decode.bool)\n" " })\n" " // -> Ok(True)\n" " ```\n" "\n" " ```gleam\n" " glua.run(glua.new(), glua.get(keys: [\"non_existent\"]))\n" " // -> Error(glua.KeyNotFound([\"non_existent\"]))\n" " ```\n" ). -spec get(list(binary())) -> action(value(), any()). get(Keys) -> {action, fun(State) -> gleam@result:map( glua_ffi:get_table_keys(State, Keys), fun(Ret) -> {State, Ret} end ) end}. -file("src/glua.gleam", 893). ?DOC( " Gets a private value that is not exposed to the Lua runtime.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " assert glua.new()\n" " |> glua.set_private(\"private_value\", \"secret_value\")\n" " |> glua.get_private(\"private_value\", decode.string)\n" " == Ok(\"secret_value\")\n" " ```\n" ). -spec get_private(lua(), binary(), gleam@dynamic@decode:decoder(DXD)) -> {ok, DXD} | {error, error(any())}. get_private(Lua, Key, Decoder) -> gleam@result:'try'( glua_ffi:get_private(Lua, Key), fun(Value) -> _pipe = gleam@dynamic@decode:run(Value, Decoder), gleam@result:map_error( _pipe, fun(Field@0) -> {unexpected_result_type, Field@0} end ) end ). -file("src/glua.gleam", 942). ?DOC( " Sets a value in the Lua environment.\n" "\n" " All nested keys will be created as intermediate tables.\n" "\n" " If successfull, this function will return the updated Lua state\n" " and the setted value will be available in Lua scripts.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " glua.run(glua.new(), {\n" " use _ <- glua.then(glua.set(\n" " keys: [\"my_number\"],\n" " value: glua.int(10)\n" " ))\n" "\n" " glua.get(keys: [\"my_number\"])\n" " |> glua.returning(using: decode.int)\n" " })\n" " // -> Ok(10)\n" " ```\n" "\n" " ```gleam\n" " let emails = [\"jhondoe@example.com\", \"lucy@example.com\"]\n" " let assert Ok(results) = glua.run(glua.new(), {\n" " use encoded <- glua.then(glua.table(\n" " list.index_map(emails, fn(email, i) { #(glua.int(i + 1), glua.string(email)) })\n" " ))\n" " use _ <- glua.then(glua.set([\"info\", \"emails\"], encoded))\n" "\n" " glua.eval(code: \"return info.emails\"))\n" " |> glua.try(list.first)\n" " |> glua.returning(using: glua.table_list_decoder(decode.string))\n" " })\n" "\n" " assert results == emails\n" " ```\n" ). -spec set(list(binary()), value()) -> action(nil, any()). set(Keys, Val) -> {action, fun(State) -> gleam@result:'try'( gleam@list:try_fold( Keys, {State, []}, fun(Acc, Key) -> {State@1, Keys@1} = Acc, Keys@2 = lists:append(Keys@1, [Key]), case glua_ffi:get_table_keys(State@1, Keys@2) of {ok, _} -> {ok, {State@1, Keys@2}}; {error, {key_not_found, _}} -> {Tbl, New} = luerl_heap:alloc_table([], State@1), gleam@result:map( glua_ffi:set_table_keys(New, Keys@2, Tbl), fun(New@1) -> {New@1, Keys@2} end ); {error, E} -> {error, E} end end ), fun(_use0) -> {New@2, Keys@3} = _use0, _pipe = glua_ffi:set_table_keys(New@2, Keys@3, Val), gleam@result:map(_pipe, fun(State@2) -> {State@2, nil} end) end ) end}. -file("src/glua.gleam", 832). ?DOC( " Swaps out the value at `keys` with a function that causes a Lua error when called.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " let assert Ok(state) = glua.new() |> glua.sandbox([\"os\"], [\"execute\"])\n" " let assert Error(glua.LuaRuntimeException(exception, _)) =\n" " glua.run(state, glua.eval(\n" " code: \"os.execute(\\\"rm -f important_file\\\"); return 0\",\n" " ))\n" "\n" " // 'important_file' was not deleted\n" " assert exception == glua.ErrorCall([\"os.execute is sandboxed\"])\n" " ```\n" ). -spec sandbox(lua(), list(binary())) -> {ok, lua()} | {error, error(any())}. sandbox(Lua, Keys) -> Msg = <<(gleam@string:join(Keys, <<"."/utf8>>))/binary, " is sandboxed"/utf8>>, _pipe = (erlang:element( 2, set([<<"_G"/utf8>> | Keys], glua_ffi:sandbox_fun(Msg)) ))(Lua), gleam@result:map(_pipe, fun gleam@pair:first/1). -file("src/glua.gleam", 980). ?DOC(" Sets a group of values under a particular table in the Lua environment.\n"). -spec set_api(list(binary()), list({binary(), value()})) -> action(nil, any()). set_api(Keys, Values) -> then( fold( Values, fun(Pair) -> set( lists:append(Keys, [erlang:element(1, Pair)]), erlang:element(2, Pair) ) end ), fun(_) -> success(nil) end ). -file("src/glua.gleam", 1012). ?DOC( " Sets the paths where the Lua runtime will look when requiring other Lua files.\n" "\n" " > **Warning**: This function will not work properly if `[\"package\"]` or `[\"require\"]` are sandboxed\n" " > in the provided Lua state. If you constructed the Lua state using `glua.new_sandboxed`,\n" " > remember to allow the required values by passing `[[\"package\"], [\"require\"]]` to `glua.new_sandboxed`.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " let my_scripts_paths = [\"app/scripts/lua/?.lua\"]\n" " glua.run(glua.new(), {\n" " use _ <- glua.then(glua.set_lua_paths(paths: my_scripts_paths))\n" "\n" " glua.eval(\n" " code: \"local my_math = require 'my_script'; return my_math.square(3)\"\n" " )\n" " |> glua.try(list.first)\n" " |> glua.returning(decode.int)\n" " })\n" " // -> Ok(9)\n" " ```\n" ). -spec set_lua_paths(list(binary())) -> action(nil, any()). set_lua_paths(Paths) -> Paths@1 = begin _pipe = gleam@string:join(Paths, <<";"/utf8>>), glua_ffi:coerce(_pipe) end, set([<<"package"/utf8>>, <<"path"/utf8>>], Paths@1). -file("src/glua.gleam", 975). ?DOC( " Sets a value that is not exposed to the Lua runtime and can only be accessed from Gleam.\n" "\n" " ## Examples\n" " ```gleam\n" " assert glua.new()\n" " |> glua.set(\"secret_value\", \"private_value\")\n" " |> glua.get(\"secret_value\", decode.string)\n" " == Ok(\"secret_value\")\n" " ```\n" ). -spec set_private(lua(), binary(), any()) -> lua(). set_private(Lua, Key, Value) -> luerl:put_private(Key, Value, Lua). -file("src/glua.gleam", 1035). ?DOC( " Remove a private value that is not exposed to the Lua runtime. \n" "\n" " ## Examples\n" "\n" " ```gleam\n" " let lua = glua.set_private(glua.new(), \"my_value\", \"will_be_removed\")\n" " assert glua.get(lua, \"my_value\", decode.string) == Ok(\"will_be_removed\")\n" "\n" " assert glua.delete_private(lua, \"my_value\")\n" " |> glua.get(\"my_value\", decode.string)\n" " == Error(glua.KeyNotFound([\"my_value\"]))\n" " ```\n" ). -spec delete_private(lua(), binary()) -> lua(). delete_private(Lua, Key) -> luerl:delete_private(Key, Lua). -file("src/glua.gleam", 1045). ?DOC( " Parses a string of Lua code and returns it as a compiled chunk.\n" "\n" " To eval the returned chunk, use `glua.eval_chunk`.\n" ). -spec load(binary()) -> action(chunk(), any()). load(Code) -> {action, fun(_capture) -> glua_ffi:load(_capture, Code) end}. -file("src/glua.gleam", 1055). ?DOC( " Parses a Lua source file and returns it as a compiled chunk.\n" "\n" " To eval the returned chunk, use `glua.eval_chunk`.\n" ). -spec load_file(binary()) -> action(chunk(), any()). load_file(Path) -> {action, fun(_capture) -> glua_ffi:load_file(_capture, Path) end}. -file("src/glua.gleam", 1095). ?DOC( " Evaluates a string of Lua code.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " glua.eval(code: \"return 1 + 2\")\n" " |> glua.returning_multi(using: decode.int)\n" " |> glua.run(glua.new(), _)\n" " // -> Ok([3])\n" " ```\n" "\n" " ```gleam\n" " let assert Ok(#(state, [ref1, ref2])) = glua.exec(glua.new(), glua.eval(\n" " code: \"return 'hello, world!', 10\",\n" " ))\n" "\n" " let assert Ok(\"hello world\") =\n" " glua.run(state, glua.dereference(ref: ref1, using: decode.string))\n" " let assert Ok(10) =\n" " glua.run(state, glua.dereference(ref: ref2, using: decode.int))\n" " ```\n" "\n" " ```gleam\n" " glua.run(glua.new(), glua.eval(code: \"return 1 * \"))\n" " // -> Error(glua.LuaCompileFailure(\n" " [glua.LuaCompileError(1, Parse, \"syntax error before: \")]\n" " ))\n" " ```\n" "\n" " > **Note**: If you are evaluating the same piece of code multiple times,\n" " > instead of calling `glua.eval` repeatly it is recommended to first convert\n" " > the code to a chunk by passing it to `glua.load`, and then\n" " > evaluate that chunk using `glua.eval_chunk`.\n" ). -spec eval(binary()) -> action(list(value()), any()). eval(Code) -> {action, fun(_capture) -> glua_ffi:eval(_capture, Code) end}. -file("src/glua.gleam", 1113). ?DOC( " Evaluates a compiled chunk of Lua code.\n" "\n" " ## Examples\n" " \n" " ```gleam\n" " glua.load(code: \"return 'hello, world!'\")\n" " |> glua.then(glua.eval_chunk)\n" " |> glua.returning_multi(using: decode.string)\n" " |> glua.run(glua.new(), _)\n" " // -> Ok([\"hello, world!\"])\n" " ```\n" ). -spec eval_chunk(chunk()) -> action(list(value()), any()). eval_chunk(Chunk) -> {action, fun(_capture) -> glua_ffi:eval_chunk(_capture, Chunk) end}. -file("src/glua.gleam", 1142). ?DOC( " Evaluates a Lua source file.\n" "\n" " ## Examples\n" " \n" " ```gleam\n" " glua.eval_file(\n" " path: \"path/to/hello.lua\",\n" " )\n" " |> glua.returning_multi(using: decode.string)\n" " |> glua.run(glua.new(), _)\n" " // -> Ok([\"hello, world!\"])\n" " ```\n" "\n" " ```gleam\n" " glua.run(glua.new(), glua.eval_file(\n" " path: \"path/to/non/existent/file\",\n" " ))\n" " // -> Error(glua.FileNotFound([\"path/to/non/existent/file\"]))\n" " ```\n" ). -spec eval_file(binary()) -> action(list(value()), any()). eval_file(Path) -> {action, fun(_capture) -> glua_ffi:eval_file(_capture, Path) end}. -file("src/glua.gleam", 1191). ?DOC( " Calls a Lua function by reference.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " glua.run(glua.new(), {\n" " use fun <- glua.then(\n" " glua.eval(code: \"return math.sqrt\") |> glua.try(list.first)\n" " )\n" "\n" " glua.call_function(\n" " ref: fun,\n" " args: [glua.int(81)],\n" " )\n" " |> glua.returning_multi(using: decode.float)\n" " })\n" " // -> Ok([9.0])\n" " ```\n" "\n" " ```gleam\n" " let code = \"function fib(n)\n" " if n <= 1 then\n" " return n\n" " else\n" " return fib(n - 1) + fib(n - 2)\n" " end\n" " end\n" "\n" " return fib\n" " \"\n" "\n" " glua.run(glua.new(), {\n" " use fun <- glua.then(glua.eval(code:) |> glua.try(list.first))\n" "\n" " glua.call_function(\n" " ref: fun,\n" " args: [glua.int(10)],\n" " )\n" " |> glua.returning_multi(using: decode.int)\n" " })\n" " // -> Ok([55])\n" " ```\n" ). -spec call_function(value(), list(value())) -> action(list(value()), any()). call_function(Fun, Args) -> {action, fun(_capture) -> glua_ffi:call_function(_capture, Fun, Args) end}. -file("src/glua.gleam", 1220). ?DOC( " Gets a reference to the function at `keys`, then inmediatly calls it with the provided `args`.\n" "\n" " This is a shorthand for `glua.get` followed by `glua.call_function`.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " glua.call_function_by_name(\n" " keys: [\"string\", \"upper\"],\n" " args: [glua.string(\"hello from Gleam!\")]\n" " ))\n" " |> glua.returning_multi(using: decode.string)\n" " |> glua.run(glua.new(), _)\n" " // -> Ok(\"HELLO FROM GLEAM!\")\n" " ```\n" ). -spec call_function_by_name(list(binary()), list(value())) -> action(list(value()), any()). call_function_by_name(Keys, Args) -> then(get(Keys), fun(Fun) -> call_function(Fun, Args) end). -file("src/glua.gleam", 1248). ?DOC( " Gets the value at `keys` under the provided table.\n" "\n" " This might trigger the `__index` metamethod.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " glua.run(glua.new(), {\n" " let fun = fn(_) {\n" " glua.success([glua.string(\"fixed value\")])\n" " }\n" "\n" " use tbl <- glua.then(glua.table([]))\n" " use mt <- glua.then(glua.table([#(glua.string(\"__index\"), glua.function(fun))]))\n" " use _ <- glua.then(glua.call_function(lib.set_metatable(), [tbl, mt]))\n" "\n" " glua.index(tbl, glua.string(\"a_key\")) |> glua.returning(decode.string)\n" " })\n" " // -> Ok(\"fixed value\")\n" " ```\n" ). -spec index(value(), value()) -> action(value(), any()). index(Ref, Key) -> {action, fun(_capture) -> glua_ffi:get_table_key(_capture, Ref, Key) end}. -file("src/glua.gleam", 1282). ?DOC( " Sets `value` under `key` of the provided table.\n" "\n" " This might trigger the `__newindex` metamethod.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " glua.run(glua.new(), {\n" " let fun = fn(_) {\n" " glua.error(\"this is a read-only table\")\n" " }\n" "\n" " use tbl <- glua.then(glua.table([]))\n" " use mt <- glua.then(glua.table([#(glua.string(\"__newindex\"), glua.function(fun))]))\n" " use _ <- glua.then(glua.call_function(lib.set_metatable(), [tbl, mt]))\n" "\n" " glua.new_index(tbl, glua.string(\"my_new_key\"), glua.string(\"my_new_value\"))\n" " })\n" " // -> Error(glua.LuaRuntimeException(\n" " exception: glua.ErrorCall(\"this is a read-only table\", option.None),\n" " state: _\n" " ))\n" " ```\n" ). -spec new_index(value(), value(), value()) -> action(nil, any()). new_index(Ref, Key, Val) -> {action, fun(_capture) -> glua_ffi:set_table_key(_capture, Ref, Key, Val) end}. -file("src/glua.gleam", 457). ?DOC(" Invokes the Lua `error` function with the provided message.\n"). -spec error(binary()) -> action(any(), any()). error(Message) -> {action, fun(State) -> case (erlang:element( 2, call_function( glua_stdlib_ffi:error(), [glua_ffi:coerce(Message)] ) ))(State) of {ok, _} -> erlang:error(#{gleam_error => panic, message => <<"The error function returned a non error which should never happen! Please report this issue to the git repository."/utf8>>, file => <>, module => <<"glua"/utf8>>, function => <<"error"/utf8>>, line => 460}); {error, E} -> {error, E} end end}. -file("src/glua.gleam", 466). ?DOC(" Invokes the Lua `error` function with the provided message and level.\n"). -spec error_with_level(binary(), integer()) -> action(any(), any()). error_with_level(Message, Level) -> {action, fun(State) -> case (erlang:element( 2, call_function( glua_stdlib_ffi:error(), [glua_ffi:coerce(Message), glua_ffi:coerce(Level)] ) ))(State) of {ok, _} -> erlang:error(#{gleam_error => panic, message => <<"The error function returned a non error which should never happen! Please report this issue to the git repository."/utf8>>, file => <>, module => <<"glua"/utf8>>, function => <<"error_with_level"/utf8>>, line => 471}); {error, E} -> {error, E} end end}. -file("src/glua.gleam", 808). ?DOC( " Creates a new Lua VM instance with sensible modules and functions sandboxed.\n" "\n" " Check `glua.default_sandbox` to see what modules and functions will be sandboxed.\n" "\n" " This function accepts a list of paths to Lua values that will be excluded from being sandboxed,\n" " so needed modules or functions can be enabled while keeping sandboxed the rest.\n" " In case you want to sandbox more Lua values, pass to `glua.sandbox` the returned Lua state.\n" ). -spec new_sandboxed(list(list(binary()))) -> {ok, lua()} | {error, error(any())}. new_sandboxed(Excluded) -> _pipe = erlang:'--'( [[<<"io"/utf8>>], [<<"file"/utf8>>], [<<"os"/utf8>>, <<"execute"/utf8>>], [<<"os"/utf8>>, <<"exit"/utf8>>], [<<"os"/utf8>>, <<"getenv"/utf8>>], [<<"os"/utf8>>, <<"remove"/utf8>>], [<<"os"/utf8>>, <<"rename"/utf8>>], [<<"os"/utf8>>, <<"tmpname"/utf8>>], [<<"package"/utf8>>], [<<"load"/utf8>>], [<<"loadfile"/utf8>>], [<<"require"/utf8>>], [<<"dofile"/utf8>>], [<<"loadstring"/utf8>>]], Excluded ), gleam@list:try_fold(_pipe, luerl:init(), fun sandbox/2).