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
-> 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.]
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.
Thank you for any feedback!