nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: tidewave-ai/tidewave_phoenix
Pull request #76 (2025-05-14 07:45:34)

Use String.lines equivalent

SteffenDE: So now we‘re gonna have two new functions in Elixir based on our work on Tidewave 😄

Patch:
diff --git a/lib/tidewave/mcp/tools/fs.ex b/lib/tidewave/mcp/tools/fs.ex
index c02faf7..8888550 100644
--- a/lib/tidewave/mcp/tools/fs.ex
+++ b/lib/tidewave/mcp/tools/fs.ex
@@ -380,20 +380,23 @@ defmodule Tidewave.MCP.Tools.FS do
   defp maybe_apply_offset_and_count(content, 0, nil), do: content
 
   defp maybe_apply_offset_and_count(content, offset, count) do
-    splitter_and_joiner =
-      case Utils.detect_line_endings(content) do
-        :lf -> "\n"
-        :crlf -> "\r\n"
-      end
-
-    lines = String.split(content, splitter_and_joiner)
-
-    lines
+    content
+    |> lines(<<>>)
     |> Enum.drop(offset)
     |> take_all_or(count)
-    |> Enum.join(splitter_and_joiner)
+    |> IO.iodata_to_binary()
   end
 
+  # TODO: Use Code.lines/1 when we require Elixir v1.19+
+  defp lines(<<?\n, rest::binary>>, acc),
+    do: [<<acc::binary, ?\n>> | lines(rest, <<>>)]
+
+  defp lines(<<char, rest::binary>>, acc),
+    do: lines(rest, <<acc::binary, char>>)
+
+  defp lines(<<>>, acc),
+    do: [acc]
+
   defp take_all_or(list, nil), do: list
   defp take_all_or(list, count), do: Enum.take(list, count)
 


Test patch:
diff --git a/test/mcp/tools/fs_test.exs b/test/mcp/tools/fs_test.exs
index b464a90..395705a 100644
--- a/test/mcp/tools/fs_test.exs
+++ b/test/mcp/tools/fs_test.exs
@@ -103,10 +103,10 @@ defmodule Tidewave.MCP.Tools.FSTest do
       content = Enum.map_join(1..1000, "\n", &to_string/1) <> "\nmore content\n"
       File.write!(file_path, content)
 
-      assert {:ok, "1\n2\n3\n4\n5\n6", _state, _metadata} =
+      assert {:ok, "1\n2\n3\n4\n5\n6\n", _state, _metadata} =
                FS.read_project_file(%{"path" => file_path, "count" => 6}, %{})
 
-      assert {:ok, "501\n502\n503\n504\n505", _state, _metadata} =
+      assert {:ok, "501\n502\n503\n504\n505\n", _state, _metadata} =
                FS.read_project_file(
                  %{"path" => file_path, "line_offset" => 500, "count" => 5},
                  %{}
Repository: tv-labs/lua
Pull request #7 (2024-03-07 19:59:46)

Fix calls to error/1


Patch:
diff --git a/lib/lua/util.ex b/lib/lua/util.ex
index c93ebae..7830647 100644
--- a/lib/lua/util.ex
+++ b/lib/lua/util.ex
@@ -65,6 +65,7 @@ defmodule Lua.Util do
             nil -> " <unknown function>#{format_args(args)}"
             "-no-name-" -> ""
             {:luerl_lib_basic, :basic_error} -> format_error(func, args)
+            {:luerl_lib_basic, :basic_error, :undefined} -> format_error(func, args)
             func -> " #{format_function([func], args)}"
           end
 
@@ -127,6 +128,10 @@ defmodule Lua.Util do
     format_function("error", args)
   end
 
+  defp format_error({:luerl_lib_basic, :basic_error, :undefined}, args) do
+    format_function("error", args)
+  end
+
   defp format_error(_, {:undefined, args}) do
     format_function("unknown_error", args)
   end
diff --git a/mix.exs b/mix.exs
index 7f63183..16a90f0 100644
--- a/mix.exs
+++ b/mix.exs
@@ -2,7 +2,7 @@ defmodule Lua.MixProject do
   use Mix.Project
 
   @url "https://github.com/tv-labs/lua"
-  @version "0.0.1"
+  @version "0.0.2"
 
   def project do
     [


Test patch:
diff --git a/test/lua_test.exs b/test/lua_test.exs
index f1a7605..dc6c82f 100644
--- a/test/lua_test.exs
+++ b/test/lua_test.exs
@@ -256,6 +256,22 @@ defmodule LuaTest do
         """)
       end
     end
+
+    test "error/1 raises an exception" do
+      error = """
+      Lua runtime error: error("this is an error")
+
+      script line 1:error("this is an error")
+      """
+
+      assert_raise Lua.RuntimeException, error, fn ->
+        lua = Lua.new(sandboxed: [])
+
+        Lua.eval!(lua, """
+        error("this is an error")
+        """)
+      end
+    end
   end
 
   describe "set!/2 and get!/2" do
Repository: tv-labs/lua
Pull request #16 (2024-03-18 20:46:05)

Utilities for converting Lua tables into Elixir datastructures
Adds the module `Lua.Table` which provides utilities for working with Lua tables, converting them into more convenient datastructures


Patch:
diff --git a/lib/lua/table.ex b/lib/lua/table.ex
new file mode 100644
index 0000000..65f0485
--- /dev/null
+++ b/lib/lua/table.ex
@@ -0,0 +1,76 @@
+defmodule Lua.Table do
+  @moduledoc """
+  In Lua, [tables](https://www.lua.org/pil/2.5.html) are the fundamental datastructure,
+  which are used both as associative arrays (maps), and arrays (lists).
+
+  `Lua.Table` provides some utilities for working with Lua tables when passed back to
+  Elixir.
+  """
+
+  @doc """
+  Converts a Lua table into a list. Assumes that the
+  table is correctly ordered.
+
+      iex> Lua.Table.as_list([{1, "a"}, {2, "b"}, {3, "c"}])
+      ["a", "b", "c"]
+
+  To ensure the list is ordered, you can pass the `:sort` option
+
+      iex> Lua.Table.as_list([{2, "b"}, {1, "a"}, {3, "c"}])
+      ["b", "a", "c"]
+
+      iex> Lua.Table.as_list([{2, "b"}, {1, "a"}, {3, "c"}], sort: true)
+      ["a", "b", "c"]
+
+  """
+  def as_list(values, opts \\ []) do
+    opts = Keyword.validate!(opts, sort: false)
+
+    sorter =
+      if Keyword.fetch!(opts, :sort) do
+        &List.keysort(&1, 0)
+      else
+        &Function.identity/1
+      end
+
+    values
+    |> sorter.()
+    |> Enum.map(fn {_, v} -> v end)
+  end
+
+  @doc """
+  Converts a Lua table into a map
+
+      iex> Lua.Table.as_map([{"a", 1}, {"b", 2}])
+      %{"a" => 1, "b" => 2}
+  """
+  def as_map(values) do
+    Map.new(values)
+  end
+
+  @doc """
+  Converts a Lua table into more "native" feeling lists and
+  maps, deeply traversing any sub-tables.
+
+  It uses the heuristic that maps with integer keys starting
+  as 1 will be auto-cast into lists
+
+      iex> Lua.Table.deep_cast([{"a", 1}, {"b", [{1, 3}, {2, 4}]}])
+      %{"a" => 1, "b" => [3, 4]}
+  """
+  def deep_cast(value) do
+    case value do
+      [{1, _val} | _rest] = list ->
+        Enum.map(list, fn
+          {_, v} when is_list(v) -> deep_cast(v)
+          {_, v} -> v
+        end)
+
+      map ->
+        Map.new(map, fn
+          {k, v} when is_list(v) -> {k, deep_cast(v)}
+          {k, v} -> {k, v}
+        end)
+    end
+  end
+end


Test patch:
diff --git a/test/lua/api_test.exs b/test/lua/api_test.exs
index 7547ec4..b58a1dc 100644
--- a/test/lua/api_test.exs
+++ b/test/lua/api_test.exs
@@ -1,5 +1,5 @@
 defmodule Lua.APITest do
-  use ExUnit.Case
+  use ExUnit.Case, async: true
 
   alias Lua
 
diff --git a/test/lua/table_test.exs b/test/lua/table_test.exs
new file mode 100644
index 0000000..cc6f56d
--- /dev/null
+++ b/test/lua/table_test.exs
@@ -0,0 +1,5 @@
+defmodule Lua.TableTest do
+  use ExUnit.Case, async: true
+
+  doctest Lua.Table
+end
diff --git a/test/lua/util_test.exs b/test/lua/util_test.exs
index 3159158..a012ae1 100644
--- a/test/lua/util_test.exs
+++ b/test/lua/util_test.exs
@@ -1,5 +1,5 @@
 defmodule Lua.UtilTest do
-  use ExUnit.Case
+  use ExUnit.Case, async: true
 
   doctest Lua.Util, import: true
Repository: tv-labs/lua
Pull request #18 (2024-03-19 01:30:44)

Implement decode!/2


Patch:
diff --git a/lib/lua.ex b/lib/lua.ex
index 75a0939..a501593 100644
--- a/lib/lua.ex
+++ b/lib/lua.ex
@@ -252,7 +252,17 @@ defmodule Lua do
     {encoded, wrap(state)}
   rescue
     ArgumentError ->
-      reraise Lua.RuntimeException, "Failed to encode value", __STACKTRACE__
+      reraise Lua.RuntimeException, "Failed to encode #{inspect(value)}", __STACKTRACE__
+  end
+
+  @doc """
+  Decodes a Lua value from its internal form
+  """
+  def decode!(%__MODULE__{} = lua, value) do
+    :luerl_new.decode(value, lua.state)
+  rescue
+    ArgumentError ->
+      reraise Lua.RuntimeException, "Failed to decode #{inspect(value)}", __STACKTRACE__
   end
 
   @doc """
diff --git a/mix.exs b/mix.exs
index 1f5a404..4edc0fb 100644
--- a/mix.exs
+++ b/mix.exs
@@ -2,7 +2,7 @@ defmodule Lua.MixProject do
   use Mix.Project
 
   @url "https://github.com/tv-labs/lua"
-  @version "0.0.8"
+  @version "0.0.9"
 
   def project do
     [


Test patch:
diff --git a/test/lua_test.exs b/test/lua_test.exs
index 67ac338..b5d7261 100644
--- a/test/lua_test.exs
+++ b/test/lua_test.exs
@@ -222,24 +222,36 @@ defmodule LuaTest do
     end
   end
 
-  describe "encode!/1" do
+  describe "encode!/1 and decode!/1" do
     test "it can encode values into their internal representation" do
       lua = Lua.new()
 
       assert {"hello", lua} = Lua.encode!(lua, "hello")
+      assert "hello" = Lua.decode!(lua, "hello")
       assert {"hello", lua} = Lua.encode!(lua, :hello)
       assert {5, lua} = Lua.encode!(lua, 5)
-      assert {{:tref, _}, lua} = Lua.encode!(lua, %{a: 1, b: 2})
-      assert {{:tref, _}, _lua} = Lua.encode!(lua, [1, 2, 3, 4])
+      assert 5 = Lua.decode!(lua, 5)
+      assert {{:tref, _} = ref, lua} = Lua.encode!(lua, %{a: 1, b: 2})
+      assert [{"a", 1}, {"b", 2}] = Lua.decode!(lua, ref)
+      assert {{:tref, _} = ref, lua} = Lua.encode!(lua, [1, 2])
+      assert [{1, 1}, {2, 2}] = Lua.decode!(lua, ref)
     end
 
     test "it raises for values that cannot be encoded" do
-      error = "Lua runtime error: Failed to encode value"
+      error = "Lua runtime error: Failed to encode {:foo, :bar}"
 
       assert_raise Lua.RuntimeException, error, fn ->
         Lua.encode!(Lua.new(), {:foo, :bar})
       end
     end
+
+    test "it raises for values that cannot be decoded" do
+      error = "Lua runtime error: Failed to decode :hello"
+
+      assert_raise Lua.RuntimeException, error, fn ->
+        Lua.decode!(Lua.new(), :hello)
+      end
+    end
   end
 
   describe "error messages" do
Repository: tv-labs/lua
Pull request #20 (2024-04-11 14:34:50)

Implement ~LUA for validating Lua code at compile time
Adds a sigil ~LUA which compiles the passed string and raises a Lua.CompilerException if the code does not compile, returning the original string.

This is useful if you have Lua literals in your codebase that you would like to validate before executing them.


Patch:
diff --git a/lib/lua.ex b/lib/lua.ex
index 38f1364..5d496bc 100644
--- a/lib/lua.ex
+++ b/lib/lua.ex
@@ -65,6 +65,23 @@ defmodule Lua do
     |> Enum.reduce(%__MODULE__{state: :luerl.init()}, &sandbox(&2, &1))
   end
 
+  @doc """
+  Write Lua code that is parsed at compile-time. If the code cannot
+  be lexed and parsed, it raises a `Lua.CompilerException`
+
+      iex> ~LUA(return 2 + 2)
+      "return 2 + 2"
+  """
+  defmacro sigil_LUA(code, _opts) do
+    {code, []} = Code.eval_quoted(code)
+
+    raise_on_invalid_lua!(code)
+
+    quote do
+      unquote(code)
+    end
+  end
+
   @doc """
   Sandboxes the given path, swapping out the implementation with
   a function that raises when called
@@ -414,4 +431,12 @@ defmodule Lua do
   end
 
   defp wrap(state), do: %__MODULE__{state: state}
+
+  defp raise_on_invalid_lua!(code) when is_binary(code) do
+    case :luerl_comp.string(code, [:return]) do
+      {:ok, _chunk} -> :ok
+      :error -> raise Lua.CompilerException, {:lua_error, "shit", "fuck"}
+      {:error, error, _warnings} -> raise Lua.CompilerException, error
+    end
+  end
 end
diff --git a/lib/lua/compiler_exception.ex b/lib/lua/compiler_exception.ex
index 6ed9b83..6ab4495 100644
--- a/lib/lua/compiler_exception.ex
+++ b/lib/lua/compiler_exception.ex
@@ -3,6 +3,23 @@ defmodule Lua.CompilerException do
 
   alias Lua.Util
 
+  def exception(errors) when is_list(errors) do
+    for error <- errors do
+      Util.format_error(error)
+    end
+
+    errors = Enum.map_join(errors, "\n", &Util.format_error/1)
+
+    message = """
+    Failed to compile Lua!
+
+    #{errors}
+
+    """
+
+    %__MODULE__{message: message}
+  end
+
   def exception({:lua_error, error, state}) do
     stacktrace = Luerl.New.get_stacktrace(state)
 


Test patch:
diff --git a/test/lua_test.exs b/test/lua_test.exs
index b5d7261..ab2498b 100644
--- a/test/lua_test.exs
+++ b/test/lua_test.exs
@@ -1,7 +1,8 @@
 defmodule LuaTest do
   use ExUnit.Case, async: true
 
-  alias Lua
+  # import Lua, only: [sigil_LUA: 1]
+  import Lua
 
   doctest Lua
 
@@ -22,6 +23,27 @@ defmodule LuaTest do
     end
   end
 
+  describe "~LUA" do
+    test "it can validate code at compile time" do
+      message = """
+      Failed to compile Lua!
+
+      Failed to tokenize: illegal token on line 1: \"hi)
+
+      """
+
+      assert_raise Lua.CompilerException, message, fn ->
+        Code.compile_quoted(
+          quote do
+            import Lua
+
+            ~LUA[print("hi)]
+          end
+        )
+      end
+    end
+  end
+
   describe "load_file!/2" do
     test "loads the lua file into the state" do
       path = test_file("test_api")
Repository: tv-labs/lua
Pull request #28 (2024-05-16 13:32:45)

Handle Lua.APIs that don't have any functions


Patch:
diff --git a/lib/lua.ex b/lib/lua.ex
index c31d2b0..0cf7d32 100644
--- a/lib/lua.ex
+++ b/lib/lua.ex
@@ -370,6 +370,8 @@ defmodule Lua do
     funcs = :functions |> module.__info__() |> Enum.group_by(&elem(&1, 0), &elem(&1, 1))
     scope = scope || module.scope()
 
+    lua = ensure_scope!(lua, scope)
+
     module.__lua_functions__()
     |> Enum.reduce(lua, fn {name, with_state?, variadic?}, lua ->
       arities = Map.get(funcs, name)
@@ -444,6 +446,14 @@ defmodule Lua do
        "Value thrown during function '#{function_name}' execution: #{inspect(thrown_value)}"}
   end
 
+  defp ensure_scope!(lua, []) do
+    lua
+  end
+
+  defp ensure_scope!(lua, scope) do
+    set!(lua, scope, %{})
+  end
+
   defp wrap(state), do: %__MODULE__{state: state}
 
   defp raise_on_invalid_lua!(code) when is_binary(code) do


Test patch:
diff --git a/test/lua_test.exs b/test/lua_test.exs
index 5074ebf..cbfba39 100644
--- a/test/lua_test.exs
+++ b/test/lua_test.exs
@@ -551,6 +551,14 @@ defmodule LuaTest do
       end
     end
 
+    defmodule NoFuncsScope do
+      use Lua.API, scope: "scope"
+    end
+
+    defmodule NoFuncsGlobal do
+      use Lua.API
+    end
+
     setup do
       {:ok, lua: Lua.new()}
     end
@@ -581,6 +589,20 @@ defmodule LuaTest do
       assert {["a default"], _} = Lua.eval!(lua, "return scope.test(\"a\")")
       assert {["a b"], _} = Lua.eval!(lua, "return scope.test(\"a\", \"b\")")
     end
+
+    test "if no functions are exposed, it still creates the scope", %{lua: lua} do
+      lua = Lua.load_api(lua, NoFuncsScope)
+
+      assert {["table"], _} = Lua.eval!(lua, "return type(scope)")
+    end
+
+    test "if the api has no scope defined, it doesnt break anything" do
+      {[], lua} = Lua.eval!("global_var = 22")
+
+      lua = Lua.load_api(lua, NoFuncsGlobal)
+
+      {[22], _} = Lua.eval!(lua, "return global_var")
+    end
   end
 
   describe "examples" do