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
27 changes: 14 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,8 @@ and raise catchable runtime errors, so `pcall` recovers from them in-band:
iex> message =~ "instruction budget exceeded"
true

See the [Sandboxing guide](guides/examples/sandboxing.livemd) for details.
See the runnable [Sandboxing example](guides/examples/sandboxing.livemd), or
the [Security and sandboxing](guides/sandboxing.md) guide, for details.

### Metatables and metamethods

Expand Down Expand Up @@ -188,21 +189,21 @@ deliberate non-goal rather than a missing feature:

For the live Lua 5.3 official test-suite pass count and the rationale behind
each deferral, see the
[`ROADMAP.md`](https://github.com/tv-labs/lua/blob/main/ROADMAP.md). This
release is `1.0.0-rc.0`.
[`ROADMAP.md`](https://github.com/tv-labs/lua/blob/main/ROADMAP.md).

## Examples

Runnable, end-to-end scripts live in
[`examples/`](https://github.com/tv-labs/lua/blob/main/examples/README.md). Run
any of them with `mix run examples/<name>.exs`:

- [`examples/01_quickstart.exs`](https://github.com/tv-labs/lua/blob/main/examples/01_quickstart.exs) — eval some Lua and get the result.
- [`examples/02_userdata.exs`](https://github.com/tv-labs/lua/blob/main/examples/02_userdata.exs) — pass an Elixir struct as userdata and call methods on it from Lua.
- [`examples/03_custom_stdlib.exs`](https://github.com/tv-labs/lua/blob/main/examples/03_custom_stdlib.exs) — add an Elixir-defined function to the state and call it from Lua.
- [`examples/04_sandboxing.exs`](https://github.com/tv-labs/lua/blob/main/examples/04_sandboxing.exs) — the default sandbox plus allowing specific `os.*` ops explicitly.
- [`examples/05_chunks.exs`](https://github.com/tv-labs/lua/blob/main/examples/05_chunks.exs) — compile once, eval many times.
- [`examples/06_error_handling.exs`](https://github.com/tv-labs/lua/blob/main/examples/06_error_handling.exs) — `pcall`, structured exception fields, source/line attribution.
End-to-end, runnable [Livebook](https://livebook.dev) notebooks live in
[`guides/examples/`](https://github.com/tv-labs/lua/tree/main/guides/examples).
Open any of them in Livebook, or read them rendered under **Examples** on
[HexDocs](https://hexdocs.pm/lua):

- [`quickstart.livemd`](https://github.com/tv-labs/lua/blob/main/guides/examples/quickstart.livemd) — eval some Lua and get the result.
- [`userdata.livemd`](https://github.com/tv-labs/lua/blob/main/guides/examples/userdata.livemd) — pass an Elixir struct as userdata and call methods on it from Lua.
- [`custom_stdlib.livemd`](https://github.com/tv-labs/lua/blob/main/guides/examples/custom_stdlib.livemd) — add an Elixir-defined function to the state and call it from Lua.
- [`sandboxing.livemd`](https://github.com/tv-labs/lua/blob/main/guides/examples/sandboxing.livemd) — the default sandbox plus allowing specific `os.*` ops explicitly.
- [`chunks.livemd`](https://github.com/tv-labs/lua/blob/main/guides/examples/chunks.livemd) — compile once, eval many times.
- [`error_handling.livemd`](https://github.com/tv-labs/lua/blob/main/guides/examples/error_handling.livemd) — `pcall`, structured exception fields, source/line attribution.

## Documentation

Expand Down
4 changes: 2 additions & 2 deletions guides/sandboxing.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ the standard library:
`loadstring`, `dofile`

Everything else — `string`, `table`, `math`, `utf8`, the `debug`
library, metatables, coroutity-free control flow — remains available.
library, metatables, coroutine-free control flow — remains available.

```elixir
# os.exit is sandboxed by default
Expand Down Expand Up @@ -72,7 +72,7 @@ lua = Lua.new(sandboxed: [])
### Sandboxing a single path

`Lua.sandbox/2` sandboxes one path on an existing VM, which is handy when
building a configuration up in instruction_count:
building a configuration up in stages:

```elixir
lua =
Expand Down
6 changes: 3 additions & 3 deletions guides/working-with-lua.livemd
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

```elixir
Mix.install([
{:lua, "~> 0.4.0"}
{:lua, "~> 1.0.0-rc"}
])
```

Expand All @@ -24,7 +24,7 @@ Lua

```elixir
code = ~LUA"""

return 2 + 2
"""

{value, %Lua{}} = Lua.eval!(code)
Expand All @@ -33,7 +33,7 @@ code = ~LUA"""
<!-- livebook:{"output":true} -->

```
{[], #Lua<>}
{[4], #Lua<>}
```

## Getting and Setting values
Expand Down
12 changes: 6 additions & 6 deletions lib/lua/api.ex
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ defmodule Lua.API do
end

If you don't need to write Elixir, but want to execute some Lua
to setup global variables, modify state, or expose some additonal
to setup global variables, modify state, or expose some additional
APIs, you can simply return a Lua chunk directly using the `c` modifier
on `Lua.sigil_LUA/2`

Expand Down Expand Up @@ -190,27 +190,27 @@ defmodule Lua.API do

deflua get_value(key), state do
# Access the Lua environment
Lua.get!(lua, [key])
Lua.get!(state, [key])
end

To modify and return new state, return a tuple

deflua set_value(key, value), state do
# Return nothing but modify the state
{[], Lua.set!(lua, [key])}
{[], Lua.set!(state, [key], value)}
end

## Using guards

Since `deflua` uses non-conventional syntax to receive the current state, make sure
you specifiy the `when` clause and guards first, e.g.
you specify the `when` clause and guards first, e.g.

deflua set_int(key, value) when is_integer(value), state do
# Return nothing but modify the state
{[], Lua.set!(state, [key])}
end

Specifyiing the `when` clause and guards last will result in a confusing error message.
Specifying the `when` clause and guards last will result in a confusing error message.

## Variadic functions

Expand All @@ -226,7 +226,7 @@ defmodule Lua.API do
IO.puts(Enum.join(args, " "))
end

> #### @variadic behavior {: .neutal}
> #### @variadic behavior {: .neutral}
> When using the `@variadic` attribute, note that it is per-function. `Lua` will
> reset this attribute after every function definition, so there is no need to
> manually reset it yourself
Expand Down
32 changes: 19 additions & 13 deletions lib/lua/parser/error.ex
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
defmodule Lua.Parser.Error do
@moduledoc """
Beautiful error reporting for the Lua parser.
Structured, wire-safe error reporting for the Lua parser.

Provides detailed error messages with:
Each error carries:
- Source code context with line numbers
- Visual indicators pointing to the error location
- Helpful suggestions for common mistakes
- Multiple error reporting
"""
- Position information pointing to the error location
- A human-readable message and, where possible, a suggested fix
- Related errors, for multi-error reporting

alias Lua.AST.Meta
Produced when parsing fails: the parser's parse_structured/1 entry point
returns `{:error, [t()]}`. Call `to_map/2` for a JSON-serializable shape
suitable for editors, LSPs, and web frontends.
"""

@type position :: Meta.position()
@type position :: %{
line: pos_integer(),
column: pos_integer(),
byte_offset: non_neg_integer()
}

@type t :: %__MODULE__{
type: error_type(),
Expand All @@ -37,9 +43,9 @@ defmodule Lua.Parser.Error do
}

@typedoc """
Wire-safe representation produced by `to_map/2`. Mirrors the shape of
`Lua.VM.ErrorFormatter.to_map/3` so runtime and parse errors render
through one path. `source`, `call_stack`, and `error_kind` are constant
Wire-safe representation produced by `to_map/2`. Mirrors the shape used
for runtime errors so runtime and parse errors render through one path.
`source`, `call_stack`, and `error_kind` are constant
for parse errors (no file name, stack, or error kind) and exist only for
shape parity.
"""
Expand Down Expand Up @@ -146,8 +152,8 @@ defmodule Lua.Parser.Error do
@doc """
Returns a wire-safe structured representation of a parse error.

The shape is identical to `Lua.VM.ErrorFormatter.to_map/3`, so runtime and
parse errors can flow through a single renderer (HTML, JSON, structured
The shape is identical to the map produced for runtime errors, so runtime
and parse errors can flow through a single renderer (HTML, JSON, structured
logs). No ANSI escapes appear in any string field, and leading/trailing
whitespace from the internal message/suggestion templates is trimmed.

Expand Down
2 changes: 1 addition & 1 deletion lib/lua/runtime_exception.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ defmodule Lua.RuntimeException do

* `:message` — formatted error string
* `:original` — the underlying VM error term
* `:state` — `Lua.VM.State` at the point of failure
* `:state` — the internal VM state at the point of failure
* `:line` — line number where the error was raised
* `:source` — source name (filename or `<stdin>`)
* `:call_stack` — list of Lua frames at failure
Expand Down
48 changes: 39 additions & 9 deletions mix.exs
Original file line number Diff line number Diff line change
@@ -1,9 +1,26 @@
defmodule Lua.MixProject do
use Mix.Project

alias Lua.Parser.Error
alias Mix.Tasks.Lua.Eval

@url "https://github.com/tv-labs/lua"
@version "1.0.0-rc.2"

# The curated public API surface rendered on HexDocs. Everything else is an
# implementation detail: its @moduledoc stays intact for source readers and
# `h Mod` in IEx, but `filter_modules/2` keeps it out of the published sidebar.
@public_modules [
Lua,
Lua.API,
Lua.Table,
Lua.Chunk,
Lua.RuntimeException,
Lua.CompilerException,
Error,
Eval
]

def project do
[
app: :lua,
Expand Down Expand Up @@ -34,18 +51,31 @@ defmodule Lua.MixProject do
main: "Lua",
source_url: @url,
source_ref: "v#{@version}",
# Render only the curated public surface; keep internals in source/IEx.
filter_modules: fn module, _meta -> module in @public_modules end,
groups_for_modules: [
Core: [Lua, Lua.API, Lua.Table, Lua.Chunk],
Errors: [Lua.RuntimeException, Lua.CompilerException, Error],
"Mix Tasks": [Eval]
],
extras: [
"CHANGELOG.md",
"guides/working-with-lua.livemd",
"guides/sandboxing.md",
"guides/examples/quickstart.livemd",
"guides/examples/userdata.livemd",
"guides/examples/custom_stdlib.livemd",
"guides/examples/sandboxing.livemd",
"guides/examples/chunks.livemd",
"guides/examples/error_handling.livemd"
"guides/working-with-lua.livemd": [title: "Working with Lua"],
"guides/sandboxing.md": [title: "Security & Sandboxing"],
"guides/mix_tasks.md": [title: "Mix Tasks & the ~LUA sigil"],
"guides/examples/quickstart.livemd": [title: "Quickstart"],
"guides/examples/userdata.livemd": [title: "Userdata"],
"guides/examples/custom_stdlib.livemd": [title: "Custom stdlib"],
"guides/examples/sandboxing.livemd": [title: "Sandboxing"],
"guides/examples/chunks.livemd": [title: "Chunks"],
"guides/examples/error_handling.livemd": [title: "Error handling"],
"CHANGELOG.md": []
],
groups_for_extras: [
Guides: [
"guides/working-with-lua.livemd",
"guides/sandboxing.md",
"guides/mix_tasks.md"
],
Examples: ~r{guides/examples/}
]
]
Expand Down
Loading