Parsers and generators
Raw definitions
By default, DSLs generated with Diesel are compiled into a tree-like structure of nodes as tuples.
This is similar to the structure you'd expect from a HTML document parsed with Loki. For example, the following code:
defmodule MyApp.Fsm.Paymnent do
use MyApp.Fsm
fsm do
state :pending do
end
end
end
gives the following internal raw definition:
{:fsm, [], [
{:state, [name: :pending], []}
]}
By default, this is the datastructure that will be then consumed by code generators.
The parser behaviour
It is possible however to add parsing steps and convert the raw definition into a more suitable data structure, before it is consumed by generators.
All you need to do is implement the Diesel.Parser
behaviour in a new elixir module:
defmodule MyApp.Fsm.MyParser do
@moduledoc "Converts a fsm definition into structs"
@behaviour Diesel.Parser
@impl true
def parse(caller, {:fsm, [], states}) do
%Fsm{states: [...]}
end
end
and add it to the list of parsers:
defmodule MyApp.Fsm do
use Diesel,
otp_app: ...,
dsl: ...,
parsers: [
MyApp.Fsm.MyParser
]
defstruct states: []
end
The Diesel
module provides with several convenience functions to traverse definitions:
children/2
: returns all children elements with the given tag namenodes/2
: returns all elements in the given list with the given tag namechild/2
: returns the first child with the given tag namechild/1
: returns the first child of the given element or list of elements
Generating code
By implementing the Diesel.Generator
behaviour, developers can produce elixir code, based on a DSL
definition. For example, we could imagine a GenServer based implementation of a state machine:
defmodule MyApp.Fsm do
use Diesel,
otp_app: ...,
dsl: ...,
parsers: [...],
generators: [
MyApp.Fsm.Generator.GenServer
]
where:
defmodule MyApp.Fsm.Generator.GenServer do
@moduledoc "Generates a GenServer for a state machine DSL"
@behaviour Diesel.Generator
@impl true
def generate(caller, definition) do
quote do
use GenServer
...
end
end
end