glua

A library to embed Lua in Gleam programs.

Gleam wrapper around Luerl.

Types

The exception that happens when a functi Represents a chunk of Lua code that is already loaded into the Lua VM

pub type Chunk

Represents an instance of the Lua VM.

pub type Lua

Represents the errors than can happend during the parsing and execution of Lua code

pub type LuaError {
  LuaCompilerException(messages: List(String))
  LuaRuntimeException(
    exception: LuaRuntimeExceptionKind,
    state: Lua,
  )
  KeyNotFound
  UnexpectedResultType(List(decode.DecodeError))
  UnknownError
}

Constructors

  • LuaCompilerException(messages: List(String))

    There was an exception when compiling the Lua code.

  • LuaRuntimeException(
      exception: LuaRuntimeExceptionKind,
      state: Lua,
    )

    The Lua environment threw an exception during code execution.

  • KeyNotFound

    A certain key was not found in the Lua environment.

  • UnexpectedResultType(List(decode.DecodeError))

    The value returned by the Lua environment could not be decoded using the provided decoder.

  • UnknownError

    An error that could not be identified.

Represents the kind of exceptions that can happen at runtime during Lua code execution.

pub type LuaRuntimeExceptionKind {
  IllegalIndex(value: String, index: String)
  ErrorCall(messages: List(String))
  UndefinedFunction(value: String)
  BadArith(operator: String, args: List(String))
  AssertError(message: String)
  UnknownException
}

Constructors

  • IllegalIndex(value: String, index: String)

    The exception that happens when trying to access an index that does not exists on a table (also happens when indexing non-table values).

  • ErrorCall(messages: List(String))

    The exception that happens when the error function is called.

  • UndefinedFunction(value: String)

    The exception that happens when trying to call a function that is not defined.

  • BadArith(operator: String, args: List(String))

    The exception that happens when an invalid arithmetic operation is performed.

  • AssertError(message: String)

    The exception that happens when a call to assert is made passing a value that evalues to false as the first argument.

  • UnknownException

    An exception that could not be identified

Represents a value that can be passed to the Lua environment.

pub type Value

Represents a reference to a value inside the Lua environment.

Each one of the functions that returns values from the Lua environment has a ref_ counterpart that will return references to the values instead of decoding them.

pub type ValueRef

Values

pub fn bool(lua: Lua, v: Bool) -> #(Lua, Value)
pub fn call_function(
  state lua: Lua,
  ref fun: ValueRef,
  args args: List(Value),
  using decoder: decode.Decoder(a),
) -> Result(#(Lua, List(a)), LuaError)

Calls a Lua function by reference.

Examples

let assert Ok(#(lua, fun)) = glua.ref_eval(state: glua.new(), code: "return math.sqrt")

let #(lua, encoded) = glua.int(lua, 81)
let assert Ok(#(_, [result])) = glua.call_function(
  state: lua,
  ref: fun,
  args: [encoded],
  using: decode.int
)

assert result == 9
let code = "function fib(n)
  if n <= 1 then
    return n
  else
    return fib(n - 1) + fib(n - 2)
  end
end

return fib
"
let assert Ok(#(lua, fun)) = glua.ref_eval(state: glua.new(), code:)

let #(lua, encoded) = glua.int(lua, 10)
let assert Ok(#(_, [result])) = glua.call_function(
  state: lua,
  ref: fun,
  args: [encoded],
  using: decode.int
)

assert result == 55 
pub fn call_function_by_name(
  state lua: Lua,
  keys keys: List(String),
  args args: List(Value),
  using decoder: decode.Decoder(a),
) -> Result(#(Lua, List(a)), LuaError)

Gets a reference to the function at keys, then inmediatly calls it with the provided args.

This is a shorthand for glua.ref_get followed by glua.call_function.

Examples

let #(lua, encoded) = glua.new() |> glua.string("hello from gleam!")
let assert Ok(#(_, [s])) = glua.call_function_by_name(
  state: lua,
  keys: ["string", "upper"],
  args: [encoded],
  using: decode.string
)

assert s == "HELLO FROM GLEAM!" 
pub const default_sandbox: List(List(String))

List of Lua modules and functions that will be sandboxed by default

pub fn delete_private(state lua: Lua, key key: String) -> Lua

Remove a private value that is not exposed to the Lua runtime.

Examples

let lua = glua.set_private(glua.new(), "my_value", "will_be_removed"
assert glua.get(lua, "my_value", decode.string) == Ok("will_be_removed")

assert glua.delete_private(lua, "my_value")
       |> glua.get("my_value", decode.string)
  == Error(glua.KeyNotFound)
pub fn eval(
  state lua: Lua,
  code code: String,
  using decoder: decode.Decoder(a),
) -> Result(#(Lua, List(a)), LuaError)

Evaluates a string of Lua code.

Examples

let assert Ok(#(_, results)) = glua.eval(
  state: glua.new(),
  code: "return 1 + 2",
  using: decode.int
)
assert results == [3]
let my_decoder = decode.one_of(decode.string, or: [
  decode.int |> decode.map(int.to_string)
])

let assert Ok(#(_, results)) = glua.eval(
  state: glua.new(),
  code: "return 'hello, world!', 10",
  using: my_decoder
)
assert results == ["hello, world!", "10"]
glua.eval(state: glua.new(), code: "return 1 * ", using: decode.int)
// -> Error(glua.LuaCompilerException(
  messages: ["syntax error before: ", "1"]
))
glua.eval(state: glua.new(), code: "return 'Hello, world!'", using: decode.int)
// -> Error(glua.UnexpectedResultType(
  [decode.DecodeError("Int", "String", [])]
))

Note: If you are evaluating the same piece of code multiple times, instead of calling glua.eval repeatly it is recommended to first convert the code to a chunk by passing it to glua.load, and then evaluate that chunk using glua.eval_chunk or glua.ref_eval_chunk.

pub fn eval_chunk(
  state lua: Lua,
  chunk chunk: Chunk,
  using decoder: decode.Decoder(a),
) -> Result(#(Lua, List(a)), LuaError)

Evaluates a compiled chunk of Lua code.

Examples

let assert Ok(#(lua, chunk)) = glua.load(
  state: glua.new(),
  code: "return 'hello, world!'"
)

let assert Ok(#(_, results)) = glua.eval_chunk(
  state: lua,
  chunk:,
  using: decode.string
)

assert results == ["hello, world!"]
pub fn eval_file(
  state lua: Lua,
  path path: String,
  using decoder: decode.Decoder(a),
) -> Result(#(Lua, List(a)), LuaError)

Evaluates a Lua source file.

Examples

let assert Ok(#(_, results)) = glua.eval_file(
  state: glua.new(),
  path: "path/to/hello.lua",
  using: decode.string
)

assert results == ["hello, world!"]
pub fn float(lua: Lua, v: Float) -> #(Lua, Value)
pub fn function(
  lua: Lua,
  f: fn(Lua, List(dynamic.Dynamic)) -> #(Lua, List(Value)),
) -> #(Lua, Value)
pub fn get(
  state lua: Lua,
  keys keys: List(String),
  using decoder: decode.Decoder(a),
) -> Result(a, LuaError)

Gets a value in the Lua environment.

Examples

glua.get(state: glua.new(), keys: ["_VERSION"], using: decode.string)
// -> Ok("Lua 5.3")
let #(lua, encoded) = glua.new() |> glua.bool(True)
let assert Ok(lua) = glua.set(
  state: lua,
  keys: ["my_table", "my_value"],
  value: encoded
)

glua.get(
  state: lua,
  keys: ["my_table", "my_value"],
  using: decode.bool
)
// -> Ok(True)
glua.get(state: glua.new(), keys: ["non_existent"], using: decode.string)
// -> Error(glua.KeyNotFound)
pub fn get_private(
  state lua: Lua,
  key key: String,
  using decoder: decode.Decoder(a),
) -> Result(a, LuaError)

Gets a private value that is not exposed to the Lua runtime.

Examples

assert glua.new()
     |> glua.set_private("private_value", "secret_value")
     |> glua.get_private("private_value", decode.string)
  == Ok("secret_value")
pub fn int(lua: Lua, v: Int) -> #(Lua, Value)
pub fn list(
  lua: Lua,
  encoder: fn(Lua, a) -> #(Lua, Value),
  values: List(a),
) -> #(Lua, List(Value))
pub fn load(
  state lua: Lua,
  code code: String,
) -> Result(#(Lua, Chunk), LuaError)

Parses a string of Lua code and returns it as a compiled chunk.

To eval the returned chunk, use glua.eval_chunk or glua.ref_eval_chunk.

pub fn load_file(
  state lua: Lua,
  path path: String,
) -> Result(#(Lua, Chunk), LuaError)

Parses a Lua source file and returns it as a compiled chunk.

To eval the returned chunk, use glua.eval_chunk or glua.ref_eval_chunk.

pub fn new() -> Lua

Creates a new Lua VM instance

pub fn new_sandboxed(
  allow excluded: List(List(String)),
) -> Result(Lua, LuaError)

Creates a new Lua VM instance with sensible modules and functions sandboxed.

Check glua.default_sandbox to see what modules and functions will be sandboxed.

This function accepts a list of paths to Lua values that will be excluded from being sandboxed, so needed modules or functions can be enabled while keeping sandboxed the rest. In case you want to sandbox more Lua values, pass to glua.sandbox the returned Lua state.

pub fn nil(lua: Lua) -> #(Lua, Value)
pub fn ref_call_function(
  state lua: Lua,
  ref fun: ValueRef,
  args args: List(Value),
) -> Result(#(Lua, List(ValueRef)), LuaError)

Same as glua.call_function, but returns references to the values instead of decode them.

pub fn ref_call_function_by_name(
  state lua: Lua,
  keys keys: List(String),
  args args: List(Value),
) -> Result(#(Lua, List(ValueRef)), LuaError)

Same as glua.call_function_by_name, but it chains glua.ref_get with glua.ref_call_function instead of glua.call_function

pub fn ref_eval(
  state lua: Lua,
  code code: String,
) -> Result(#(Lua, List(ValueRef)), LuaError)

Same as glua.eval, but returns references to the values instead of decode them

pub fn ref_eval_chunk(
  state lua: Lua,
  chunk chunk: Chunk,
) -> Result(#(Lua, List(ValueRef)), LuaError)

Same as glua.eval_chunk, but returns references to the values instead of decode them

pub fn ref_eval_file(
  state lua: Lua,
  path path: String,
) -> Result(#(Lua, List(ValueRef)), LuaError)

Same as glua.eval_file, but returns references to the values instead of decode them.

pub fn ref_get(
  state lua: Lua,
  keys keys: List(String),
) -> Result(ValueRef, LuaError)

Same as glua.get, but returns a reference to the value instead of decoding it

pub fn sandbox(
  state lua: Lua,
  keys keys: List(String),
) -> Result(Lua, LuaError)

Swaps out the value at keys with a function that causes a Lua error when called.

Examples

let assert Ok(lua) = glua.new() |> glua.sandbox(["os"], ["execute"])
let assert Error(glua.LuaRuntimeException(exception, _)) = glua.eval(
  state: lua,
  code: "os.execute(\"rm -f important_file\"); return 0",
  using: decode.int
)
// 'important_file' was not deleted
assert exception == glua.ErrorCall(["os.execute is sandboxed"])
pub fn set(
  state lua: Lua,
  keys keys: List(String),
  value val: Value,
) -> Result(Lua, LuaError)

Sets a value in the Lua environment.

All nested keys will be created as intermediate tables.

If successfull, this function will return the updated Lua state and the setted value will be available in Lua scripts.

Examples

let #(lua, encoded) = glua.new() |> glua.int(10)
let assert Ok(lua) = glua.set(
  state: lua,
  keys: ["my_number"],
  value: encoded
)

glua.get(state: lua, keys: ["my_number"], using: decode.int)
// -> Ok(10)
let emails = ["jhondoe@example.com", "lucy@example.com"]
let #(lua, encoded) = glua.new() |> glua.list(glua.string, emails)
let assert Ok(lua) = glua.set(
  state: lua,
  keys: ["info", "emails"],
  value: encoded
)

let assert Ok(#(_, results)) = glua.eval(
  state: lua,
  code: "return info.emails",
  using: decode.string
)

assert results == emails
pub fn set_api(
  lua: Lua,
  keys: List(String),
  values: List(#(String, Value)),
) -> Result(Lua, LuaError)

Sets a group of values under a particular table in the Lua environment.

pub fn set_lua_paths(
  state lua: Lua,
  paths paths: List(String),
) -> Result(Lua, LuaError)

Sets the paths where the Lua runtime will look when requiring other Lua files.

Warning: This function will not work properly if ["package"] or ["require"] are sandboxed in the provided Lua state. If you constructed the Lua state using glua.new_sandboxed, remember to allow the required values by passing [["package"], ["require"]] to glua.new_sandboxed.

Examples

let my_scripts_paths = ["app/scripts/lua/?.lua"]
let assert Ok(state) = glua.set_lua_paths(
  state: glua.new(),
  paths: my_scripts_paths
)

let assert Ok(#(_, [result])) = glua.eval(
  state:,
  code: "local my_math = require 'my_script'; return my_math.square(3)"
  using: decode.int
)

assert result = 9
pub fn set_private(
  state lua: Lua,
  key key: String,
  value value: a,
) -> Lua

Sets a value that is not exposed to the Lua runtime and can only be accessed from Gleam.

Examples

assert glua.new()
       |> glua.set("secret_value", "private_value")
       |> glua.get("secret_value")
  == Ok("secret_value")
pub fn string(lua: Lua, v: String) -> #(Lua, Value)
pub fn table(
  lua: Lua,
  encoders: #(
    fn(Lua, a) -> #(Lua, Value),
    fn(Lua, b) -> #(Lua, Value),
  ),
  values: List(#(a, b)),
) -> #(Lua, Value)
pub fn table_decoder(
  keys_decoder: decode.Decoder(a),
  values_decoder: decode.Decoder(b),
) -> decode.Decoder(List(#(a, b)))
Search Document