Skip to content

Instantly share code, notes, and snippets.

@vjache
Created November 28, 2023 17:37
Show Gist options
  • Save vjache/9310838977ee7427ff7e73b0882b810a to your computer and use it in GitHub Desktop.
Save vjache/9310838977ee7427ff7e73b0882b810a to your computer and use it in GitHub Desktop.
Behaviour Tree macro
defmodule EcssManagementSystem.Driver.Bt do
@moduledoc """
Example:`
defmodule BtScript do
use Bt
def run do
a = 1
all do
any do
a > 0
version_expired()
db_changed()
end
update_component()
end
end
defp version_expired do
"version_expired" |> IO.puts()
:false
end
defp db_changed do
"db_changed" |> IO.puts()
:true
end
defp update_component do
"update_component" |> IO.puts()
:success
end
end
"""
@doc false
defmacro __using__(opts) do
quote location: :keep, bind_quoted: [opts: opts] do
import EcssManagementSystem.Driver.Bt
end
end
defmacro any(do: block) do
expr = case block do
{bt, _, _} = x when bt == :any or bt == :all ->
call = Macro.expand(x, __ENV__)
quote do
continue_on_failure(unquote(call))
end
{:__block__, _, calls} ->
{:__block__, [], calls |> Enum.map(fn call ->
call = case call do
{:any, _, _} = x -> Macro.expand(x, __ENV__)
{:all, _, _} = x -> Macro.expand(x, __ENV__)
_ -> call
end
quote do
continue_on_failure(unquote(call))
end
end)}
end
s = quote do
try(do: unquote(expr), catch: (_, :success -> :success))
end
s |> Macro.to_string() |> IO.puts()
s
end
defmacro all(do: block) do
expr = case block do
{bt, _, _} = x when bt == :any or bt == :all ->
call = Macro.expand(x, __ENV__)
quote do
continue_on_success(unquote(call))
end
{:__block__, _, calls} ->
{:__block__, [], calls |> Enum.map(fn call ->
call = case call do
{:any, _, _} = x -> Macro.expand(x, __ENV__)
{:all, _, _} = x -> Macro.expand(x, __ENV__)
_ -> call
end
quote do
continue_on_success(unquote(call))
end
end)}
end
s = quote do
try(do: unquote(expr), catch: (_, :failure -> :failure))
end
s |> Macro.to_string() |> IO.puts()
s
end
def continue_on_failure(:success) do
throw(:success)
end
def continue_on_failure(:true) do
throw(:success)
end
def continue_on_failure(:ok) do
throw(:success)
end
def continue_on_failure(:failure) do
:failure
end
def continue_on_failure(:error) do
:failure
end
def continue_on_failure(:false) do
:failure
end
def continue_on_failure({:error, _}) do
:failure
end
def continue_on_success(:success) do
:success
end
def continue_on_success(:true) do
:success
end
def continue_on_success(:ok) do
:success
end
def continue_on_success(:failure) do
throw(:failure)
end
def continue_on_success(:error) do
throw(:failure)
end
def continue_on_success(:false) do
throw(:failure)
end
def continue_on_success({:error, _}) do
throw(:failure)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment