Current section

Files

Jump to
rex lib rex.ex
Raw

lib/rex.ex

defmodule Rex do
defmacro __using__(_) do
quote do
import Rex
import Rex.Stack
import Rex.Control
import Rex.Math
end
end
import Rex.Core
@doc ~S"""
Define a new Rex function.
You can call `drex` to define a new _word_ that acts either as a
*stack shuffler* or as *operator on the stack*.
To define a stack *shuffling* word, the syntax is:
# (example from `Rex.Stack.swap/1`)
drex swap(a, b) (b, a)
To define a stack *operator* you use the `~>` or `<~` syntax:
# pushes 1 then 2 then performs adition
drex three 1 ~> 2 ~> Kernel.+/2
# pushes 2 then performs multiplication
# expecting a first value already on stack (ie. partial function)
drex double Kernel.*/2 <~ 2
As *operators* are the most frequent types of words you will be creating,
the following *concatenative* syntax is supported:
# This will multiply the second element on the stack
# and then print the final stack state to stdout.
drex double_second swap double swap show
However, if you want to also push an integer or any other Elixir literal,
trying something like `3 double` wont work because its not valid Elixir syntax.
But you can use the `do` notation for `drex`:
drex thirtysix do
3
double dup Kernel.*/2
end
is exactly the same as:
drex thirtysix 3 ~> double ~> dup ~> Kernel.*/2
The `do` form is peferred for large words. Most likely you'll just want to
keep them short as concatenative programs are very composable.
"""
defmacro drex({{name, _, patterns}, _, exprs}) when length(patterns) > 0 do
rex_def({:def, :stack_effect}, {name, patterns, exprs})
end
defmacro drex({name, _, [expr]}) do
rex_def({:def, :stack_expr}, {name, expr}, __CALLER__)
end
defmacro drex({name, _, nil}, expr = [do: _]) do
rex_def({:def, :stack_expr}, {name, expr}, __CALLER__)
end
@doc """
Compile a Rex expression into an Elixir function.
The returned anonymous function can be given a stack to operate on.
"""
defmacro rex(expr) do
rex_fn(expr, __CALLER__)
end
@doc ~S"""
Pipe an exising stack to a new Rex expression.
[5, 2, 3] |> rex(double ~> swap ~> double) #=> [4, 10, 3]
"""
defmacro rex(stack, expr) when is_list(stack) do
quote do
unquote(stack) |> unquote(rex_fn(expr, __CALLER__)).()
end
end
end