Oliver

Oliver

DSL options within elixir modules?

As far as I can see, there are the following options for extending elixir with extensions or change the meaning of syntax:

The regular macros and the optional rules

So I can have my own macros with do-end blocks and rewrite any elixir code that is supplied within, like:

defmodule A do
  defmacro foo(do: block) do IO.inspect(block) end
end

defmodule B do
  import A
  foo do
     [1, 2, 3]
     x + y -> z
  end
end

So I’m allowed all elixir syntax in there and a few constructs like the -> but only within the typical limits how they are are used in elixir syntax itself. I could use the + and -> however to describe for example who syncs to whom or to describe a tree, do my own fancy flow control, etc.

It seems I cannot do:

defmodule B do
  import A
  foo do
    x -> y -> z
    1, 2, 3
    silly: :nilly
  end
end

So I cannot omit list brackets or use the -> more than once without line break or ; or have a keyword list while omitting brackets. (Please correct me if I’m missing something.)

So I could redefine to my heart’s content what elixir’s allowed constructs mean (or replace them arbitrarily) but not use its low-level primitives (comma lists without brackets, keyword lists without brackets, chaining the ->, etc). Do I understand it correctly?

[EDIT: I can see from examples I found since posting that I can get around some of these limitations by using the optional rules and faking a function call, so I could do this at least:

defmodule B do
  import A
  foo do
    something 1, 2, 3
    other silly: :nilly
  end
end

Because then the optional rules at least apply.]

Sigils

Anything in a sigil can pretty much be anything. I get a string and also what follows after the ending delimiter, and I can parse it in any way I see fit and if I do so inside a macro, I can even write code to replace the sigil.

So I could do this:

defmodule A do
  defmacro sigil_p(_, _) do
     quote do
       def silly, do: IO.puts("silly")
     end
  end
end

defmodule B do
   import A
   ~p"doesn't matter"
end

B.silly

So any of the allowed sigils could be used to inject a DSL anywhere in elixir, and since it allows a variety of delimiters, the sigils could emulate elixir constructs like lists in syntax and yet have additional or different semantics.

So I see these two mechanisms - which are undoubtedly powerful and very useful - and wonder if there are other ways to do this without writing such DSLs into separate files and let elixir be simply the compiler that transforms them into usable code.

I mean, I have no problem packing my custom syntax into sigils, but if the same could be done within a do-end block that would even be nicer.

To make it clear, I’m not complaining. I’m looking for all options to allow me to have more of my own syntax for my own DSLs, and this is what I found. If you know more, please share. :slight_smile:

Thank you for any feedback!

Most Liked

zachallaun

zachallaun

I think you have the gist of it! The issues you’re running up against with the do/end block is a limitation of the parser, which has to use its knowledge of Elixir syntax to construct an abstract syntax tree that obeys syntax precedence, associativity, etc.

Last Post!

vfsoraki

vfsoraki

You’re totally right.

Macro is for when you can use Elixir’s syntax, but you want to (re-)define what’s the meaning of some (or all!) of operators/functions/arguments/…. . For example, ExUnit is a kind of DSL.

Sigils are bare strings, you parse it as you will. The most obvious example for me is Heex to embed HTML in Elixir files.

Maybe look at both of them to see how they work.

Where Next?

Popular in Questions Top

nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New

Other popular topics Top

JakeBecker
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
1144 54996 245
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
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
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New

We're in Beta

About us Mission Statement