Skip to content

Instantly share code, notes, and snippets.

@lalbuquerque
Created July 13, 2016 02:11
Show Gist options
  • Save lalbuquerque/921cb6d7726e1a8fd40a5e21a738bb25 to your computer and use it in GitHub Desktop.
Save lalbuquerque/921cb6d7726e1a8fd40a5e21a738bb25 to your computer and use it in GitHub Desktop.
@doc """
Breaks a pipeline expression into a list.
The AST for a pipeline (a sequence of applications of `|>`) is similar to the
AST of a sequence of binary operators or function applications: the top-level
expression is the right-most `:|>` (which is the last one to be executed), and
its left-hand and right-hand sides are its arguments:
quote do: 100 |> div(5) |> div(2)
#=> {:|>, _, [arg1, arg2]}
In the example above, the `|>` pipe is the right-most pipe; `arg1` is the AST
for `100 |> div(5)`, and `arg2` is the AST for `div(2)`.
It's often useful to have the AST for such a pipeline as a list of function
applications. This function does exactly that:
Macro.unpipe(quote do: 100 |> div(5) |> div(2))
#=> [{100, 0}, {{:div, [], [5]}, 0}, {{:div, [], [2]}, 0}]
We get a list that follows the pipeline directly: first the `100`, then the
`div(5)` (more precisely, its AST), then `div(2)`. The `0` as the second
element of the tuples is the position of the previous element in the pipeline
inside the current function application: `{{:div, [], [5]}, 0}` means that the
previous element (`100`) will be inserted as the 0th (first) argument to the
`div/2` function, so that the AST for that function will become `{:div, [],
[100, 5]}` (`div(100, 5)`).
"""
@spec unpipe(Macro.t) :: [Macro.t]
def unpipe(expr) do
:lists.reverse(unpipe(expr, []))
end
defp unpipe({:|>, _, [left, right]}, acc) do
unpipe(right, unpipe(left, acc))
end
defp unpipe(other, acc) do
[{other, 0} | acc]
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment