Introduction

Meta-programming in Elixir allows writing code that generates and manipulates other code. This is useful for creating Domain-Specific Languages (DSLs), reducing boilerplate, and implementing compile-time optimizations.

Abstract Syntax Trees (AST)

This is how Elixir code is represented, as an AST.

So when a function or expression is parsed, it’s broken down into tokens (Lexing) and then structured into the AST.

ast = quote do: 1 + 2
IO.inspect(ast)  # {:+, [context: Elixir, import: Kernel], [1, 2]}

quote and unquote

The quote function captures expressions as AST instead of evaluating them.

Whereas the unquote function forces the evaluation of an expression inside a quote.

x = quote do: 1 + 2
quote do: 3 * unquote(x) 
# This results in AST for `3 * (1 + 2)`

// If no unquote, x would be treated as a literal AST instead of evaluated.


Macros

A Macro function takes an AST as input and returns another AST.

defmacro inspect_macro(x) do
  IO.inspect(x)  # Print AST of x
end

//The inspect function Inspects and writes the given item to the standard output.