Skip to content
This repository has been archived by the owner on Dec 21, 2024. It is now read-only.

Commit

Permalink
Rewrites all Ast usage to use Tuples
Browse files Browse the repository at this point in the history
  • Loading branch information
Lucassifoni committed Apr 24, 2024
1 parent 3b8e695 commit c5b9822
Show file tree
Hide file tree
Showing 13 changed files with 359 additions and 343 deletions.
2 changes: 1 addition & 1 deletion ovo/lib/ovo.ex
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ defmodule Ovo do
Runs Ovo code through the interpreter
iex> Ovo.run("addone = \\a -> add(1, a) end addone(2)")
iex> {%Ovo.Ast{kind: :integer, nodes: [], value: 3}}
iex> {{:integer, [], 3}}
"""
def run(code, input \\ %{}), do: Ovo.Interpreter.run(code, input)
Expand Down
17 changes: 6 additions & 11 deletions ovo/lib/ovo/ast.ex
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,14 @@ defmodule Ovo.Ast do
@typedoc """
An Ast node.
"""
@type t :: %__MODULE__{
kind: kind(),
nodes: list(t()),
value: term()
}
defstruct [:kind, :nodes, :value]
@type t :: {kind(), list(t()), term()}

@doc """
Helper to instantiate Ast Nodes.
"""
@spec make(kind(), term(), list(t())) :: t()
def make(kind, value, children),
do: %__MODULE__{kind: kind, nodes: children, value: value}
do: {kind, children, value}

@doc """
Instantiates a root node.
Expand Down Expand Up @@ -102,21 +97,21 @@ defmodule Ovo.Ast do
Currently used for parenthesized expressions, but will certainly be refactored out later.
"""
@spec expr(t() | list(t())) :: t()
def expr([val]) when is_struct(val, Ast), do: make(:expr, val, [])
def expr(val) when is_struct(val, Ast), do: val
def expr([val]) when is_tuple(val), do: make(:expr, val, [])
def expr(val) when is_tuple(val), do: val

@doc """
Instantiates an assignment node, where symbol must be a symbol node and expr an Ast node.
"""
@spec assignment(t(), t()) :: t()
def assignment(symbol, expr) when is_struct(symbol, Ast) and is_struct(expr, Ast),
def assignment(symbol, expr) when is_tuple(symbol) and is_tuple(expr),
do: make(:assignment, symbol, expr)

@doc """
Instantiates a shakable lambda node, where lambda must be a Lambda ast node.
"""
@spec shake(t()) :: t()
def shake(lambda) when is_struct(lambda, Ast), do: make(:shake, lambda, [])
def shake(lambda) when is_tuple(lambda), do: make(:shake, lambda, [])

@doc """
Instantiates a block node. Will probably be removed.
Expand Down
76 changes: 38 additions & 38 deletions ovo/lib/ovo/builtins.ex
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ defmodule Ovo.Builtins do

defp hex(nodes, env) do
case map_nodes(nodes, env) do
[%{kind: :integer, value: v}] ->
[{:integer, _, v}] ->
Ovo.Ast.string(Integer.to_string(v, 16))

_ ->
Expand All @@ -63,7 +63,7 @@ defmodule Ovo.Builtins do
import Bitwise

case map_nodes(nodes, env) do
[%{kind: :integer, value: v}] ->
[{:integer, _, v}] ->
Ovo.Ast.integer(v &&& 0xFFFFFFFF)

_ ->
Expand All @@ -75,7 +75,7 @@ defmodule Ovo.Builtins do
import Bitwise

case map_nodes(nodes, env) do
[%{kind: :integer, value: v}, %{kind: :integer, value: v1}] ->
[{:integer, _, v}, {:integer, _, v1}] ->
Ovo.Ast.integer(v <<< v1)

_ ->
Expand All @@ -87,7 +87,7 @@ defmodule Ovo.Builtins do
import Bitwise

case map_nodes(nodes, env) do
[%{kind: :integer, value: v}, %{kind: :integer, value: v1}] ->
[{:integer, _, v}, {:integer, _, v1}] ->
Ovo.Ast.integer(v >>> v1)

_ ->
Expand All @@ -99,7 +99,7 @@ defmodule Ovo.Builtins do
import Bitwise

case map_nodes(nodes, env) do
[%{kind: :integer, value: v}, %{kind: :integer, value: v1}] ->
[{:integer, _, v}, {:integer, _, v1}] ->
Ovo.Ast.integer(bxor(v, v1))

_ ->
Expand All @@ -109,7 +109,7 @@ defmodule Ovo.Builtins do

defp intval(nodes, env) do
case map_nodes(nodes, env) do
[%{kind: :string, value: v}] ->
[{:string, _, v}] ->
<<k::utf8>> = v
Ovo.Ast.integer(k)

Expand All @@ -120,14 +120,14 @@ defmodule Ovo.Builtins do

defp o_len(nodes, env) do
case map_nodes(nodes, env) do
[%{kind: :string, value: v}] -> Ovo.Ast.integer(String.length(v))
[{:string, _, v}] -> Ovo.Ast.integer(String.length(v))
_ -> :error
end
end

defp at(nodes, env) do
case map_nodes(nodes, env) do
[%{kind: :string, value: v}, %{kind: :integer, value: v1}] ->
[{:string, _, v}, {:integer, _, v1}] ->
Ovo.Ast.string(String.at(v, v1))

_ ->
Expand All @@ -137,10 +137,10 @@ defmodule Ovo.Builtins do

defp concat(nodes, env) do
case map_nodes(nodes, env) do
[%{kind: :string, value: v}, %{kind: :string, value: v2}] ->
[{:string, _, v}, {:string, _, v2}] ->
Ovo.Ast.string("#{v}#{v2}")

[%{kind: :list, nodes: n1}, %{kind: :list, nodes: n2}] ->
[{:list, n1, _}, {:list, n2, _}] ->
Ovo.Ast.list(n1 ++ n2)

_ ->
Expand All @@ -150,7 +150,7 @@ defmodule Ovo.Builtins do

defp to_string(nodes, env) do
case map_nodes(nodes, env) do
[%{kind: k, value: v}] when k in [:string, :float, :integer] ->
[{k, _, v}] when k in [:string, :float, :integer] ->
Ovo.Ast.string("#{v}")

_ ->
Expand All @@ -167,7 +167,7 @@ defmodule Ovo.Builtins do

defp invoke(nodes, env) do
case map_nodes(nodes, env) do
[%{kind: :string, value: hash}, %{kind: :list, nodes: ns}] ->
[{:string, _, hash}, {:list, ns, _}] ->
{h, host} =
case String.split(hash, "@") do
[h] -> {h, Node.self()}
Expand All @@ -193,9 +193,9 @@ defmodule Ovo.Builtins do

defp arg(nodes, env) do
case map_nodes(nodes, env) do
[%{kind: :integer, value: v}] ->
data = Ovo.Env.find_value("data", env)
Map.get(data.value, "arg#{v}")
[{:integer, _, v}] ->
{_, _, data} = Ovo.Env.find_value("data", env)
Map.get(data, "arg#{v}")

_ ->
:error
Expand All @@ -204,9 +204,9 @@ defmodule Ovo.Builtins do

defp access(nodes, env) do
case map_nodes(nodes, env) do
[%{kind: :string, value: v}] ->
data = Ovo.Env.find_value("data", env)
Map.get(data.value, v)
[{:string, _, v}] ->
{_, _, data} = Ovo.Env.find_value("data", env)
Map.get(data, v)

_ ->
:error
Expand All @@ -215,7 +215,7 @@ defmodule Ovo.Builtins do

defp compare(nodes, env, operator) do
case map_nodes(nodes, env) do
[%{kind: k1, value: v1}, %{kind: k2, value: v2}]
[{k1, _, v1}, {k2, _, v2}]
when k1 in [:float, :integer] and k2 in [:float, :integer] ->
Ovo.Ast.bool(operator.(v1, v2))

Expand All @@ -230,7 +230,7 @@ defmodule Ovo.Builtins do
def strictly_smaller(nodes, env), do: compare(nodes, env, &Kernel.</2)

def different(nodes, env) do
%Ast{value: v} = equals(nodes, env)
{_, _, v} = equals(nodes, env)
Ovo.Ast.bool(not v)
end

Expand Down Expand Up @@ -260,7 +260,7 @@ defmodule Ovo.Builtins do

defp rshake(nodes, env) do
case map_nodes(nodes, env) do
[%{kind: :string, value: v}] ->
[{:string, _, v}] ->
Ovo.Runner.shake(v)

_ ->
Expand All @@ -270,7 +270,7 @@ defmodule Ovo.Builtins do

defp map(nodes, env) do
case map_nodes(nodes, env) do
[fun, %Ast{kind: :list, nodes: items}] when is_function(fun) ->
[fun, {:list, items, _}] when is_function(fun) ->
Ovo.Ast.list(Enum.map(items, fn i -> fun.([i]) end))

_ ->
Expand All @@ -280,7 +280,7 @@ defmodule Ovo.Builtins do

defp filter(nodes, env) do
case map_nodes(nodes, env) do
[fun, %Ast{kind: :list, nodes: items}] when is_function(fun) ->
[fun, {:list, items, _}] when is_function(fun) ->
Ovo.Ast.list(Enum.filter(items, fn i -> fun.([i]) end))

_ ->
Expand All @@ -290,7 +290,7 @@ defmodule Ovo.Builtins do

defp reduce(nodes, env) do
case map_nodes(nodes, env) do
[fun, %Ast{kind: :list, nodes: items}, %Ast{} = initial_value] when is_function(fun) ->
[fun, {:list, items, _}, {} = initial_value] when is_function(fun) ->
Enum.reduce(items, initial_value, fn i, acc ->
fun.([acc, i])
end)
Expand All @@ -302,13 +302,13 @@ defmodule Ovo.Builtins do

defp add(nodes, env) do
case map_nodes(nodes, env) do
[%Ast{kind: :integer, value: v1}, %Ast{kind: :integer, value: v2}] ->
[{:integer, _, v1}, {:integer, _, v2}] ->
Ast.integer(v1 + v2)

[%Ast{kind: :float, value: v1}, %Ast{kind: :float, value: v2}] ->
[{:float, _, v1}, {:float, _, v2}] ->
Ast.float(v1 + v2)

[%Ast{kind: k1, value: v1}, %Ast{kind: k2, value: v2}]
[{k1, _, v1}, {k2, _, v2}]
when k1 in [:integer, :float] and k2 in [:integer, :float] ->
Ast.float(v1 + v2)

Expand All @@ -319,13 +319,13 @@ defmodule Ovo.Builtins do

defp subtract(nodes, env) do
case map_nodes(nodes, env) do
[%Ast{kind: :integer, value: v1}, %Ast{kind: :integer, value: v2}] ->
[{:integer, _, v1}, {:integer, _, v2}] ->
Ast.integer(v1 - v2)

[%Ast{kind: :float, value: v1}, %Ast{kind: :float, value: v2}] ->
[{:float, _, v1}, {:float, _, v2}] ->
Ast.float(v1 - v2)

[%Ast{kind: k1, value: v1}, %Ast{kind: k2, value: v2}]
[{k1, _, v1}, {k2, _, v2}]
when k1 in [:integer, :float] and k2 in [:integer, :float] ->
Ast.float(v1 - v2)

Expand All @@ -336,13 +336,13 @@ defmodule Ovo.Builtins do

defp multiply(nodes, env) do
case map_nodes(nodes, env) do
[%Ast{kind: :integer, value: v1}, %Ast{kind: :integer, value: v2}] ->
[{:integer, _, v1}, {:integer, _, v2}] ->
Ast.integer(v1 * v2)

[%Ast{kind: :float, value: v1}, %Ast{kind: :float, value: v2}] ->
[{:float, _, v1}, {:float, _, v2}] ->
Ast.float(v1 * v2)

[%Ast{kind: k1, value: v1}, %Ast{kind: k2, value: v2}]
[{k1, _, v1}, {k2, _, v2}]
when k1 in [:integer, :float] and k2 in [:integer, :float] ->
Ast.float(v1 * v2)

Expand All @@ -353,13 +353,13 @@ defmodule Ovo.Builtins do

defp divide(nodes, env) do
case map_nodes(nodes, env) do
[%Ast{kind: :integer, value: v1}, %Ast{kind: :integer, value: v2}] ->
[{:integer, _, v1}, {:integer, _, v2}] ->
Ast.integer(v1 / v2)

[%Ast{kind: :float, value: v1}, %Ast{kind: :float, value: v2}] ->
[{:float, _, v1}, {:float, _, v2}] ->
Ast.float(v1 / v2)

[%Ast{kind: k1, value: v1}, %Ast{kind: k2, value: v2}]
[{k1, _, v1}, {k2, _, v2}]
when k1 in [:integer, :float] and k2 in [:integer, :float] ->
Ast.float(v1 / v2)

Expand All @@ -370,14 +370,14 @@ defmodule Ovo.Builtins do

defp map_access(nodes, env) do
case map_nodes(nodes, env) do
[%Ast{kind: :map, value: v}, %Ast{kind: :string, value: v2}] -> Map.get(v, v2)
[{:map, _, v}, {:string, _, v2}] -> Map.get(v, v2)
_ -> :error
end
end

defp map_set(nodes, env) do
case map_nodes(nodes, env) do
[%Ast{kind: :map, value: v}, %Ast{kind: :string, value: v2}, %Ast{} = v3] ->
[{:map, _, v}, {:string, _, v2}, {} = v3] ->
Map.put(v, v2, v3)

_ ->
Expand Down
18 changes: 9 additions & 9 deletions ovo/lib/ovo/converter.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ defmodule Ovo.Converter do
alias Ovo.Ast

@spec elixir_to_ovo(term()) :: Ovo.Ast.t()
def elixir_to_ovo(%Ast{} = term), do: term
def elixir_to_ovo(term) when is_integer(term), do: Ast.integer(term)
def elixir_to_ovo(term) when is_number(term), do: Ast.float(term)
def elixir_to_ovo(term) when is_number(term), do: Ast.float(term)
Expand All @@ -16,16 +15,17 @@ defmodule Ovo.Converter do
def elixir_to_ovo(term) when is_map(term),
do: Ast.map(Enum.map(term, fn {k, v} -> {k, elixir_to_ovo(v)} end) |> Enum.into(%{}))

def elixir_to_ovo(term), do: term
@spec elixir_to_ovo(Ovo.Ast.t()) :: term()
def ovo_to_elixir(%Ast{kind: :bool, value: v}), do: v
def ovo_to_elixir(%Ast{kind: :float, value: v}), do: v
def ovo_to_elixir(%Ast{kind: :integer, value: v}), do: v
def ovo_to_elixir(%Ast{kind: :string, value: v}), do: v
def ovo_to_elixir(%Ast{kind: :symbol, value: v}), do: v
def ovo_to_elixir(%Ast{kind: :expr, value: v}), do: ovo_to_elixir(v)
def ovo_to_elixir({:bool, _, v}), do: v
def ovo_to_elixir({:float, _, v}), do: v
def ovo_to_elixir({:integer, _, v}), do: v
def ovo_to_elixir({:string, _, v}), do: v
def ovo_to_elixir({:symbol, _, v}), do: v
def ovo_to_elixir({:expr, _, v}), do: ovo_to_elixir(v)

def ovo_to_elixir(%Ast{kind: :map, value: v}),
def ovo_to_elixir({:map, _, v}),
do: v |> Enum.map(fn {k, v1} -> {k, ovo_to_elixir(v1)} end) |> Enum.into(%{})

def ovo_to_elixir(%Ast{kind: :list, nodes: n}), do: n |> Enum.map(&ovo_to_elixir/1)
def ovo_to_elixir({:list, n, _}), do: n |> Enum.map(&ovo_to_elixir/1)
end
Loading

0 comments on commit c5b9822

Please sign in to comment.