Repository: tv-labs/lua
Pull request #8 (2024-03-13 14:49:29)

Propagate original error information
Improves the error handling of Lua to include the original exception and lua state, so
that callers can provide additional context in their logs and alerts if neccessary


Patch:
diff --git a/lib/lua.ex b/lib/lua.ex
index fdac960..ea10575 100644
--- a/lib/lua.ex
+++ b/lib/lua.ex
@@ -159,19 +159,16 @@ defmodule Lua do
         raise Lua.CompilerException, reason: reason
     end
   rescue
-    e in [ArgumentError, FunctionClauseError] ->
-      reraise e, __STACKTRACE__
-
-    e in [CaseClauseError, MatchError] ->
-      reraise Lua.RuntimeException, "Could not match #{inspect(e.term)}", __STACKTRACE__
-
     e in [UndefinedFunctionError] ->
       reraise Lua.RuntimeException,
               Util.format_function([e.module, e.function], e.arity),
               __STACKTRACE__
 
-    e in [ErlangError] ->
-      reraise Lua.RuntimeException, e.original, __STACKTRACE__
+    e in [Lua.RuntimeException, Lua.CompilerException] ->
+      reraise e, __STACKTRACE__
+
+    e ->
+      reraise Lua.RuntimeException, e, __STACKTRACE__
   end
 
   # Deep-set a value within a nested Lua table structure,
diff --git a/lib/lua/runtime_exception.ex b/lib/lua/runtime_exception.ex
index bb40251..b1ef1ea 100644
--- a/lib/lua/runtime_exception.ex
+++ b/lib/lua/runtime_exception.ex
@@ -1,5 +1,5 @@
 defmodule Lua.RuntimeException do
-  defexception [:message]
+  defexception [:message, :original, :state]
 
   alias Lua.Util
 
@@ -29,6 +29,8 @@ defmodule Lua.RuntimeException do
     stacktrace = Luerl.New.get_stacktrace(state)
 
     %__MODULE__{
+      original: error,
+      state: state,
       message: """
       Lua runtime error: #{message}
 
@@ -37,8 +39,8 @@ defmodule Lua.RuntimeException do
     }
   end
 
-  def exception({:api_error, details, _state}) do
-    %__MODULE__{message: "Lua API error: #{details}"}
+  def exception({:api_error, details, state}) do
+    %__MODULE__{original: details, state: state, message: "Lua API error: #{details}"}
   end
 
   def exception(list) when is_list(list) do
@@ -47,6 +49,8 @@ defmodule Lua.RuntimeException do
     message = Keyword.fetch!(list, :message)
 
     %__MODULE__{
+      original: list,
+      state: nil,
       message: "Lua runtime error: #{format_function(scope, function)} failed, #{message}"
     }
   end
@@ -56,7 +60,14 @@ defmodule Lua.RuntimeException do
   end
 
   def exception(error) do
-    %__MODULE__{message: "Lua runtime error: #{inspect(error)}"}
+    message =
+      if is_exception(error) do
+        Exception.message(error)
+      else
+        inspect(error)
+      end
+
+    %__MODULE__{original: error, message: "Lua runtime error: #{message}"}
   end
 
   defp format_function([], function), do: "#{function}()"
diff --git a/mix.exs b/mix.exs
index 16a90f0..6408062 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.2"
+  @version "0.0.3"
 
   def project do
     [


Test patch:
diff --git a/test/lua_test.exs b/test/lua_test.exs
index dc6c82f..6a71659 100644
--- a/test/lua_test.exs
+++ b/test/lua_test.exs
@@ -272,6 +272,16 @@ defmodule LuaTest do
         """)
       end
     end
+
+    test "arithmetic exceptions are handled" do
+      error = "Lua runtime error: bad argument in arithmetic expression"
+
+      assert_raise Lua.RuntimeException, error, fn ->
+        lua = Lua.new()
+
+        Lua.eval!(lua, "return 5 / 0")
+      end
+    end
   end
 
   describe "set!/2 and get!/2" do
@@ -404,7 +414,9 @@ defmodule LuaTest do
     end
 
     test "it cannot return tuples from Elixir", %{lua: lua} do
-      assert_raise ArgumentError, fn ->
+      error = "Lua runtime error: argument error"
+
+      assert_raise Lua.RuntimeException, error, fn ->
         Lua.eval!(lua, "return example.tuple()")
       end
     end