MrDoops

MrDoops

Escaping runtime values in a macro with `^`

I’ve been building a tool that compiles elixir expressions into a “workflow” a directed acyclic graph of steps, conditions, and other nodes. Some examples in a livebook here. The advantage of doing this is it allows for composition of functionality at runtime - with varying levels of potential user defined logic. Should be handy for data pipelines, rule based expert systems or other runtime dependent workflows.

A big part of expert systems is to build rules at runtime, but to do this I need to be able to inject runtime values into a macro (at least as implemented - if there’s a better way to extract atomic conditionals in a function I’m all ears).

So the idea is supporting ^ as an escape value like Ecto and Explorer do, but I barely understand Macros and have been struggling to figure out how to access the runtime values in this situation.

test "escapes runtime values with '^'" do
    some_values = [:potato, :ham, :tomato]

    escaped_rule = Dagger.rule(
      name: "escaped_rule",
      condition: fn val when val in ^some_values -> true end,
      reaction: "food"
    )

    assert match?(%Rule{}, escaped_rule)
    assert Rule.check(escaped_rule, :potato)
end

I want the left hand side of this rule to build a function such as:

fn val when val in [:potato, :ham, :tomato] -> true end

I noticed Jose implemented something similar in Explorer recently: explorer/lib/explorer/query.ex at v0.5.5 · elixir-explorer/explorer · GitHub but I don’t quite understand how it works yet.

I’ve tried a few variations such as:

check =
  Macro.prewalk(lhs, fn
    {:^, _meta, [{bind, _, _} = expr]} = ast ->
      Macro.Env.has_var?(context, {bind, nil}) |> IO.inspect(label: "has var?") # true
      runtime_value = Macro.Env.vars(context) |> IO.inspect() # [some_values: nil]

      if runtime_value do
        var = Macro.unique_var(bind, __MODULE__)
        quote do: unquote(var)
      else
        ast
      end

    ast ->
      ast
  end)

Can anyone more familiar with macros and/or escaping runtime values help me understand how this works or how you’d approach this problem? Any feedback is appreciated.

Thanks.

First Post!

zachallaun

zachallaun

You can’t access the runtime value at compile time, because, well, it doesn’t have a value yet. :slight_smile: what you can do is strip the ^ and inject the variable into the quoted expression such that the runtime value will be used when things finally execute.

The ^ isn’t special in any way, it’s just a conventional signal to the macro that what follows should be left untouched and not further transformed.

Where Next?

Popular in Questions Top

Tee
can someone please explain to me how Enum.reduce works with maps
New
fireproofsocks
I’m working on defining a simple Ecto schema for a table (in PostGres), but I don’t see where I can define a column as NOT NULL. Conside...
New
JulienCorb
I am trying to implement my new.html.eex file to create new posts on my website. new.html.eex: <h1>Create Post</h1> <%= ...
New
hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a > b) do {:ok, "a"} end if (a < b) do {:ok, b} end if (a == b) do {:ok, "equa...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
chensan
I have a User schema with a :from_id field set to type :string: defmodule TweetBot.Repo.Migrations.CreateUsers do use Ecto.Migration ...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
komlanvi
Hi everyone, I was playing with phoenix liveView but I run into an issue. I have a form and want to validate each input text when the te...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
svb
Hi! Currently I want to submit a form by pressing the Enter key. However, since my input field is of type “textarea” this is just adds a...
New

Other popular topics Top

AstonJ
Posting this to see if we can make things easier for people to get into Neovim. If you use Neovim and have a favourite distro please let ...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 52341 488
New
marick
I had some trouble figuring out how to make many-to-many associations work. Once I got it working, I wrote a blog post. Because I’m a nov...
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" => #BSON.ObjectId<58eb1a7a9ad169198c3dXXXX>, "email" => ...
New
svb
Hi! Currently I want to submit a form by pressing the Enter key. However, since my input field is of type “textarea” this is just adds a...
New

We're in Beta

About us Mission Statement