From 291d6c54878feb5d40acaf50f59fed49c596aeed Mon Sep 17 00:00:00 2001 From: Dave Lucia Date: Thu, 15 May 2025 09:37:07 -0400 Subject: [PATCH 1/5] feat: allow guards in deflua functions --- lib/lua/api.ex | 3 +++ test/lua/api_test.exs | 28 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/lib/lua/api.ex b/lib/lua/api.ex index 4310676..d83a5b4 100644 --- a/lib/lua/api.ex +++ b/lib/lua/api.ex @@ -164,6 +164,8 @@ defmodule Lua.API do """ defmacro deflua(fa, state, rest) do + dbg() + {fa, _acc} = Macro.prewalk(fa, false, fn {name, context, args}, false -> {{name, context, args ++ List.wrap(state)}, true} @@ -187,6 +189,7 @@ defmodule Lua.API do See `deflua/3` """ defmacro deflua(fa, rest) do + dbg() {name, _, _} = fa quote do diff --git a/test/lua/api_test.exs b/test/lua/api_test.exs index 3e16f59..0c24ba4 100644 --- a/test/lua/api_test.exs +++ b/test/lua/api_test.exs @@ -299,5 +299,33 @@ defmodule Lua.APITest do assert module.fail(1, 2) == 3 assert module.fail(1, "2") == "rescued" end + + test "deflua functions can have guards" do + assert [{module, _}] = + Code.compile_string(""" + defmodule WithGuards do + use Lua.API + + deflua has_a_guard(a) when is_integer(a) do + a + end + + deflua has_a_guard(_) do + "not a int" + end + + deflua with_state(a) when is_integer(a), state do + a + end + + end + """) + + assert module.has_a_guard(1) == 1 + assert module.has_a_guard(true) == "not a int" + + assert module.with_state(1, Lua.new()) == 1 + assert module.with_state(true, Lua.new()) == "not a int" + end end end From 485f8a6d257eda7c5da38184e601bcc33a5bea56 Mon Sep 17 00:00:00 2001 From: Dave Lucia Date: Wed, 4 Jun 2025 07:25:11 -0400 Subject: [PATCH 2/5] wip --- lib/lua/api.ex | 17 ++++++++++++----- test/lua/api_test.exs | 14 +++++++++++--- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/lib/lua/api.ex b/lib/lua/api.ex index d83a5b4..84e418a 100644 --- a/lib/lua/api.ex +++ b/lib/lua/api.ex @@ -164,15 +164,22 @@ defmodule Lua.API do """ defmacro deflua(fa, state, rest) do - dbg() - {fa, _acc} = Macro.prewalk(fa, false, fn - {name, context, args}, false -> {{name, context, args ++ List.wrap(state)}, true} - ast, true -> {ast, true} + {name, context, args}, false -> + {{name, context, args ++ List.wrap(state)}, true} + + ast, true -> + {ast, true} end) - {name, _, _} = fa + name = + case fa do + {:when, _, [{name, _, _} | _]} -> name + {name, _, _} -> name + end + + dbg() quote do @lua_function validate_func!( diff --git a/test/lua/api_test.exs b/test/lua/api_test.exs index 0c24ba4..a934ac4 100644 --- a/test/lua/api_test.exs +++ b/test/lua/api_test.exs @@ -310,18 +310,26 @@ defmodule Lua.APITest do a end + deflua has_a_guard(a) when is_binary(a) and not is_boolean(a) do + a + end + deflua has_a_guard(_) do - "not a int" + "not a int" end - deflua with_state(a) when is_integer(a), state do + deflua with_state(a), state when is_integer(a) do a end - + # + # deflua with_state(_), state do + # "not a int" + # end end """) assert module.has_a_guard(1) == 1 + assert module.has_a_guard("foo") == "foo" assert module.has_a_guard(true) == "not a int" assert module.with_state(1, Lua.new()) == 1 From f7542d2029db402c36ced12462ca073228692a61 Mon Sep 17 00:00:00 2001 From: Dave Lucia Date: Sun, 8 Jun 2025 14:15:04 -0400 Subject: [PATCH 3/5] working guards --- lib/lua/api.ex | 19 ++++++++----------- test/lua/api_test.exs | 16 ++++++++-------- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/lib/lua/api.ex b/lib/lua/api.ex index 84e418a..bc439bb 100644 --- a/lib/lua/api.ex +++ b/lib/lua/api.ex @@ -164,22 +164,20 @@ defmodule Lua.API do """ defmacro deflua(fa, state, rest) do - {fa, _acc} = - Macro.prewalk(fa, false, fn - {name, context, args}, false -> - {{name, context, args ++ List.wrap(state)}, true} - - ast, true -> - {ast, true} - end) - name = case fa do {:when, _, [{name, _, _} | _]} -> name {name, _, _} -> name end - dbg() + {fa, _acc} = + Macro.prewalk(fa, :ok, fn + {^name, context, args}, acc -> + {{name, context, args ++ List.wrap(state)}, acc} + + ast, acc -> + {ast, acc} + end) quote do @lua_function validate_func!( @@ -196,7 +194,6 @@ defmodule Lua.API do See `deflua/3` """ defmacro deflua(fa, rest) do - dbg() {name, _, _} = fa quote do diff --git a/test/lua/api_test.exs b/test/lua/api_test.exs index a934ac4..3729732 100644 --- a/test/lua/api_test.exs +++ b/test/lua/api_test.exs @@ -318,13 +318,13 @@ defmodule Lua.APITest do "not a int" end - deflua with_state(a), state when is_integer(a) do - a + deflua with_state(a) when is_integer(a), state do + {a, state} + end + + deflua with_state(_), state do + {"not a int", state} end - # - # deflua with_state(_), state do - # "not a int" - # end end """) @@ -332,8 +332,8 @@ defmodule Lua.APITest do assert module.has_a_guard("foo") == "foo" assert module.has_a_guard(true) == "not a int" - assert module.with_state(1, Lua.new()) == 1 - assert module.with_state(true, Lua.new()) == "not a int" + assert {1, _} = module.with_state(1, Lua.new()) + assert {"not a int", _} = module.with_state(true, Lua.new()) end end end From 4290eabf44a61a0cfb6bbe9cc6226f557702ced6 Mon Sep 17 00:00:00 2001 From: Dave Lucia Date: Sun, 8 Jun 2025 14:20:58 -0400 Subject: [PATCH 4/5] document guards --- lib/lua/api.ex | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/lua/api.ex b/lib/lua/api.ex index bc439bb..160942a 100644 --- a/lib/lua/api.ex +++ b/lib/lua/api.ex @@ -122,7 +122,7 @@ defmodule Lua.API do @doc """ Defines a function that can be exposed in Lua through `Lua.load_api/3` - deflua add_two(number) do + deflua add_two(number) when is_number(number) do number + 2 end @@ -143,6 +143,18 @@ defmodule Lua.API do {[], Lua.set!(lua, [key])} 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. + + deflua set_int(key, value) when is_integer(value), state do + # Return nothing but modify the state + {[], Lua.set!(lua, [key])} + end + + Specifyiing the `when` cluase and guards last will result in a confusing error message. + ## Variadic functions Technically, all Lua functions are variadic, which means they can receive From 015c40477b737cb6b908201c2551112e5be6d8cf Mon Sep 17 00:00:00 2001 From: Dave Lucia Date: Sun, 8 Jun 2025 14:22:21 -0400 Subject: [PATCH 5/5] changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 11a9e75..091373a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Fixed +- `deflua` function can now specify guards when using or not using state + ## [v0.2.1] - 2025-05-14 ### Added