ok. That hurt.
This commit is contained in:
parent
1d04c3ed71
commit
4f025c3233
37
generate_args.exs
Normal file
37
generate_args.exs
Normal file
|
@ -0,0 +1,37 @@
|
|||
args = Farmbot.HTTP.get!("/api/corpuses/4").body |> Poison.decode! |> Map.get("args") |> Enum.map(&Map.get(&1, "name"))
|
||||
nodes = Farmbot.HTTP.get!("/api/corpuses/4").body |> Poison.decode! |> Map.get("nodes")
|
||||
|
||||
arg_template = """
|
||||
defmodule Farmbot.CeleryScript.AST.Arg.<%= arg %> do
|
||||
@moduledoc false
|
||||
@behaviour Farmbot.CeleryScript.AST.Arg
|
||||
|
||||
def verify(_), do: :ok
|
||||
end
|
||||
"""
|
||||
|
||||
node_template = """
|
||||
defmodule Farmbot.CeleryScript.AST.Node.<%= node %> do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [<%= allowed_args %>]
|
||||
end
|
||||
"""
|
||||
|
||||
for arg <- args do
|
||||
camel_arg = Macro.camelize(arg)
|
||||
str = EEx.eval_string(arg_template, [arg: camel_arg])
|
||||
File.write!("lib/farmbot/celery_script/ast/arg/#{arg}.ex", str)
|
||||
# |> Code.eval_string()
|
||||
end
|
||||
|
||||
for node <- nodes do
|
||||
camel_node = Macro.camelize(node["name"])
|
||||
allowed_args = Map.get(node, "allowed_args") |> Enum.map(fn(arg_str) -> ":#{arg_str}" end) |> Enum.join(", ")
|
||||
IO.puts "#{node["name"]} => #{allowed_args}"
|
||||
str = EEx.eval_string(node_template, [allowed_args: allowed_args, node: camel_node])
|
||||
File.write!("lib/farmbot/celery_script/ast/node/#{node["name"]}.ex", str)
|
||||
# |> Code.eval_string()
|
||||
end
|
||||
|
||||
Farmbot.HTTP.get!("/api/sequences/2").body |> Farmbot.CeleryScript.AST.decode
|
6
lib/farmbot/celery_script/ast/arg/_else.ex
Normal file
6
lib/farmbot/celery_script/ast/arg/_else.ex
Normal file
|
@ -0,0 +1,6 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Arg.Else do
|
||||
@moduledoc false
|
||||
@behaviour Farmbot.CeleryScript.AST.Arg
|
||||
|
||||
def verify(_), do: :ok
|
||||
end
|
6
lib/farmbot/celery_script/ast/arg/_then.ex
Normal file
6
lib/farmbot/celery_script/ast/arg/_then.ex
Normal file
|
@ -0,0 +1,6 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Arg.Then do
|
||||
@moduledoc false
|
||||
@behaviour Farmbot.CeleryScript.AST.Arg
|
||||
|
||||
def verify(_), do: :ok
|
||||
end
|
6
lib/farmbot/celery_script/ast/arg/axis.ex
Normal file
6
lib/farmbot/celery_script/ast/arg/axis.ex
Normal file
|
@ -0,0 +1,6 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Arg.Axis do
|
||||
@moduledoc false
|
||||
@behaviour Farmbot.CeleryScript.AST.Arg
|
||||
|
||||
def verify(_), do: :ok
|
||||
end
|
6
lib/farmbot/celery_script/ast/arg/channel_name.ex
Normal file
6
lib/farmbot/celery_script/ast/arg/channel_name.ex
Normal file
|
@ -0,0 +1,6 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Arg.ChannelName do
|
||||
@moduledoc false
|
||||
@behaviour Farmbot.CeleryScript.AST.Arg
|
||||
|
||||
def verify(_), do: :ok
|
||||
end
|
6
lib/farmbot/celery_script/ast/arg/is_outdated.ex
Normal file
6
lib/farmbot/celery_script/ast/arg/is_outdated.ex
Normal file
|
@ -0,0 +1,6 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Arg.IsOutdated do
|
||||
@moduledoc false
|
||||
@behaviour Farmbot.CeleryScript.AST.Arg
|
||||
|
||||
def verify(_), do: :ok
|
||||
end
|
6
lib/farmbot/celery_script/ast/arg/label.ex
Normal file
6
lib/farmbot/celery_script/ast/arg/label.ex
Normal file
|
@ -0,0 +1,6 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Arg.Label do
|
||||
@moduledoc false
|
||||
@behaviour Farmbot.CeleryScript.AST.Arg
|
||||
|
||||
def verify(_), do: :ok
|
||||
end
|
6
lib/farmbot/celery_script/ast/arg/lhs.ex
Normal file
6
lib/farmbot/celery_script/ast/arg/lhs.ex
Normal file
|
@ -0,0 +1,6 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Arg.Lhs do
|
||||
@moduledoc false
|
||||
@behaviour Farmbot.CeleryScript.AST.Arg
|
||||
|
||||
def verify(_), do: :ok
|
||||
end
|
6
lib/farmbot/celery_script/ast/arg/location.ex
Normal file
6
lib/farmbot/celery_script/ast/arg/location.ex
Normal file
|
@ -0,0 +1,6 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Arg.Location do
|
||||
@moduledoc false
|
||||
@behaviour Farmbot.CeleryScript.AST.Arg
|
||||
|
||||
def verify(_), do: :ok
|
||||
end
|
6
lib/farmbot/celery_script/ast/arg/message.ex
Normal file
6
lib/farmbot/celery_script/ast/arg/message.ex
Normal file
|
@ -0,0 +1,6 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Arg.Message do
|
||||
@moduledoc false
|
||||
@behaviour Farmbot.CeleryScript.AST.Arg
|
||||
|
||||
def verify(_), do: :ok
|
||||
end
|
6
lib/farmbot/celery_script/ast/arg/message_type.ex
Normal file
6
lib/farmbot/celery_script/ast/arg/message_type.ex
Normal file
|
@ -0,0 +1,6 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Arg.MessageType do
|
||||
@moduledoc false
|
||||
@behaviour Farmbot.CeleryScript.AST.Arg
|
||||
|
||||
def verify(_), do: :ok
|
||||
end
|
6
lib/farmbot/celery_script/ast/arg/milliseconds.ex
Normal file
6
lib/farmbot/celery_script/ast/arg/milliseconds.ex
Normal file
|
@ -0,0 +1,6 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Arg.Milliseconds do
|
||||
@moduledoc false
|
||||
@behaviour Farmbot.CeleryScript.AST.Arg
|
||||
|
||||
def verify(_), do: :ok
|
||||
end
|
6
lib/farmbot/celery_script/ast/arg/offset.ex
Normal file
6
lib/farmbot/celery_script/ast/arg/offset.ex
Normal file
|
@ -0,0 +1,6 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Arg.Offset do
|
||||
@moduledoc false
|
||||
@behaviour Farmbot.CeleryScript.AST.Arg
|
||||
|
||||
def verify(_), do: :ok
|
||||
end
|
6
lib/farmbot/celery_script/ast/arg/op.ex
Normal file
6
lib/farmbot/celery_script/ast/arg/op.ex
Normal file
|
@ -0,0 +1,6 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Arg.Op do
|
||||
@moduledoc false
|
||||
@behaviour Farmbot.CeleryScript.AST.Arg
|
||||
|
||||
def verify(_), do: :ok
|
||||
end
|
6
lib/farmbot/celery_script/ast/arg/package.ex
Normal file
6
lib/farmbot/celery_script/ast/arg/package.ex
Normal file
|
@ -0,0 +1,6 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Arg.Package do
|
||||
@moduledoc false
|
||||
@behaviour Farmbot.CeleryScript.AST.Arg
|
||||
|
||||
def verify(_), do: :ok
|
||||
end
|
6
lib/farmbot/celery_script/ast/arg/pin_mode.ex
Normal file
6
lib/farmbot/celery_script/ast/arg/pin_mode.ex
Normal file
|
@ -0,0 +1,6 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Arg.PinMode do
|
||||
@moduledoc false
|
||||
@behaviour Farmbot.CeleryScript.AST.Arg
|
||||
|
||||
def verify(_), do: :ok
|
||||
end
|
6
lib/farmbot/celery_script/ast/arg/pin_number.ex
Normal file
6
lib/farmbot/celery_script/ast/arg/pin_number.ex
Normal file
|
@ -0,0 +1,6 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Arg.PinNumber do
|
||||
@moduledoc false
|
||||
@behaviour Farmbot.CeleryScript.AST.Arg
|
||||
|
||||
def verify(_), do: :ok
|
||||
end
|
6
lib/farmbot/celery_script/ast/arg/pin_value.ex
Normal file
6
lib/farmbot/celery_script/ast/arg/pin_value.ex
Normal file
|
@ -0,0 +1,6 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Arg.PinValue do
|
||||
@moduledoc false
|
||||
@behaviour Farmbot.CeleryScript.AST.Arg
|
||||
|
||||
def verify(_), do: :ok
|
||||
end
|
6
lib/farmbot/celery_script/ast/arg/pointer_id.ex
Normal file
6
lib/farmbot/celery_script/ast/arg/pointer_id.ex
Normal file
|
@ -0,0 +1,6 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Arg.PointerId do
|
||||
@moduledoc false
|
||||
@behaviour Farmbot.CeleryScript.AST.Arg
|
||||
|
||||
def verify(_), do: :ok
|
||||
end
|
6
lib/farmbot/celery_script/ast/arg/pointer_type.ex
Normal file
6
lib/farmbot/celery_script/ast/arg/pointer_type.ex
Normal file
|
@ -0,0 +1,6 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Arg.PointerType do
|
||||
@moduledoc false
|
||||
@behaviour Farmbot.CeleryScript.AST.Arg
|
||||
|
||||
def verify(_), do: :ok
|
||||
end
|
6
lib/farmbot/celery_script/ast/arg/radius.ex
Normal file
6
lib/farmbot/celery_script/ast/arg/radius.ex
Normal file
|
@ -0,0 +1,6 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Arg.Radius do
|
||||
@moduledoc false
|
||||
@behaviour Farmbot.CeleryScript.AST.Arg
|
||||
|
||||
def verify(_), do: :ok
|
||||
end
|
6
lib/farmbot/celery_script/ast/arg/rhs.ex
Normal file
6
lib/farmbot/celery_script/ast/arg/rhs.ex
Normal file
|
@ -0,0 +1,6 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Arg.Rhs do
|
||||
@moduledoc false
|
||||
@behaviour Farmbot.CeleryScript.AST.Arg
|
||||
|
||||
def verify(_), do: :ok
|
||||
end
|
6
lib/farmbot/celery_script/ast/arg/sequence_id.ex
Normal file
6
lib/farmbot/celery_script/ast/arg/sequence_id.ex
Normal file
|
@ -0,0 +1,6 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Arg.SequenceId do
|
||||
@moduledoc false
|
||||
@behaviour Farmbot.CeleryScript.AST.Arg
|
||||
|
||||
def verify(_), do: :ok
|
||||
end
|
6
lib/farmbot/celery_script/ast/arg/speed.ex
Normal file
6
lib/farmbot/celery_script/ast/arg/speed.ex
Normal file
|
@ -0,0 +1,6 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Arg.Speed do
|
||||
@moduledoc false
|
||||
@behaviour Farmbot.CeleryScript.AST.Arg
|
||||
|
||||
def verify(_), do: :ok
|
||||
end
|
6
lib/farmbot/celery_script/ast/arg/tool_id.ex
Normal file
6
lib/farmbot/celery_script/ast/arg/tool_id.ex
Normal file
|
@ -0,0 +1,6 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Arg.ToolId do
|
||||
@moduledoc false
|
||||
@behaviour Farmbot.CeleryScript.AST.Arg
|
||||
|
||||
def verify(_), do: :ok
|
||||
end
|
6
lib/farmbot/celery_script/ast/arg/url.ex
Normal file
6
lib/farmbot/celery_script/ast/arg/url.ex
Normal file
|
@ -0,0 +1,6 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Arg.Url do
|
||||
@moduledoc false
|
||||
@behaviour Farmbot.CeleryScript.AST.Arg
|
||||
|
||||
def verify(_), do: :ok
|
||||
end
|
6
lib/farmbot/celery_script/ast/arg/value.ex
Normal file
6
lib/farmbot/celery_script/ast/arg/value.ex
Normal file
|
@ -0,0 +1,6 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Arg.Value do
|
||||
@moduledoc false
|
||||
@behaviour Farmbot.CeleryScript.AST.Arg
|
||||
|
||||
def verify(_), do: :ok
|
||||
end
|
6
lib/farmbot/celery_script/ast/arg/version.ex
Normal file
6
lib/farmbot/celery_script/ast/arg/version.ex
Normal file
|
@ -0,0 +1,6 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Arg.Version do
|
||||
@moduledoc false
|
||||
@behaviour Farmbot.CeleryScript.AST.Arg
|
||||
|
||||
def verify(_), do: :ok
|
||||
end
|
6
lib/farmbot/celery_script/ast/arg/x.ex
Normal file
6
lib/farmbot/celery_script/ast/arg/x.ex
Normal file
|
@ -0,0 +1,6 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Arg.X do
|
||||
@moduledoc false
|
||||
@behaviour Farmbot.CeleryScript.AST.Arg
|
||||
|
||||
def verify(_), do: :ok
|
||||
end
|
6
lib/farmbot/celery_script/ast/arg/y.ex
Normal file
6
lib/farmbot/celery_script/ast/arg/y.ex
Normal file
|
@ -0,0 +1,6 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Arg.Y do
|
||||
@moduledoc false
|
||||
@behaviour Farmbot.CeleryScript.AST.Arg
|
||||
|
||||
def verify(_), do: :ok
|
||||
end
|
6
lib/farmbot/celery_script/ast/arg/z.ex
Normal file
6
lib/farmbot/celery_script/ast/arg/z.ex
Normal file
|
@ -0,0 +1,6 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Arg.Z do
|
||||
@moduledoc false
|
||||
@behaviour Farmbot.CeleryScript.AST.Arg
|
||||
|
||||
def verify(_), do: :ok
|
||||
end
|
|
@ -4,72 +4,141 @@ defmodule Farmbot.CeleryScript.AST do
|
|||
Ast nodes.
|
||||
"""
|
||||
|
||||
alias Farmbot.CeleryScript.Error
|
||||
defmodule Arg do
|
||||
@moduledoc "CeleryScript Argument."
|
||||
|
||||
@typedoc """
|
||||
CeleryScript args.
|
||||
"""
|
||||
@type args :: map
|
||||
|
||||
@typedoc """
|
||||
Type for CeleryScript Ast's.
|
||||
"""
|
||||
@type t :: %__MODULE__{
|
||||
args: args,
|
||||
body: [t, ...],
|
||||
kind: String.t(),
|
||||
comment: String.t() | nil
|
||||
}
|
||||
|
||||
@enforce_keys [:args, :body, :kind]
|
||||
defstruct kind: nil,
|
||||
args: %{},
|
||||
body: [],
|
||||
comment: nil
|
||||
|
||||
@doc """
|
||||
Parses json and traverses the tree and turns everything can
|
||||
possibly be parsed.
|
||||
"""
|
||||
@spec parse(map | [map, ...]) :: t
|
||||
def parse(map_or_json_map)
|
||||
|
||||
def parse(%{"kind" => kind, "args" => args} = thing) do
|
||||
body = thing["body"] || []
|
||||
comment = thing["comment"]
|
||||
%__MODULE__{kind: kind, args: parse_args(args), body: parse(body), comment: comment}
|
||||
@doc "Verify this arg."
|
||||
@callback verify(any) :: :ok | {:error, term}
|
||||
end
|
||||
|
||||
def parse(%{__struct__: _} = thing) do
|
||||
thing |> Map.from_struct() |> parse
|
||||
end
|
||||
defmodule Node do
|
||||
@moduledoc "CeleryScript Node."
|
||||
|
||||
def parse(%{kind: kind, args: args} = thing) do
|
||||
body = thing[:body] || []
|
||||
comment = thing[:comment]
|
||||
%__MODULE__{kind: kind, body: parse(body), args: parse_args(args), comment: comment}
|
||||
end
|
||||
@doc "Decode and validate arguments."
|
||||
@callback decode_args(map) :: {:ok, map} | {:error, term}
|
||||
|
||||
# You can give a list of nodes.
|
||||
def parse(body) when is_list(body) do
|
||||
Enum.reduce(body, [], fn blah, acc ->
|
||||
acc ++ [parse(blah)]
|
||||
end)
|
||||
end
|
||||
@doc false
|
||||
defmacro __using__(_) do
|
||||
quote do
|
||||
import Farmbot.CeleryScript.AST.Node
|
||||
@behaviour Farmbot.CeleryScript.AST.Node
|
||||
|
||||
# TODO: This is a pretty heavy memory leak, what should happen is
|
||||
# The corpus should create a bunch of atom, and then this should be
|
||||
# Strint.to_existing_atom
|
||||
@spec parse_args(map) :: map
|
||||
def parse_args(map) when is_map(map) do
|
||||
Enum.reduce(map, %{}, fn {key, val}, acc ->
|
||||
if is_map(val) do
|
||||
# if it is a map, it could be another node so parse it too.
|
||||
real_val = parse(val)
|
||||
Map.put(acc, String.to_atom(key), real_val)
|
||||
else
|
||||
Map.put(acc, String.to_atom(key), val)
|
||||
# Struct to allow for usage of Elixir Protocols.
|
||||
defstruct [:ast]
|
||||
|
||||
@doc false
|
||||
def decode_args(args, acc \\ [])
|
||||
|
||||
# The AST Decoder comes in as a map. Change it to a Keyword list
|
||||
# before enumeration.
|
||||
def decode_args(args, acc) when is_map(args) do
|
||||
decode_args(Map.to_list(args), acc)
|
||||
end
|
||||
|
||||
def decode_args([{arg_name, val} = arg | rest], acc) do
|
||||
# if this is an expected argument, there will be a function
|
||||
# defined that points to the argument type implementation.
|
||||
# This requires that the Node module has
|
||||
# `allow_args [<arg_name>]`
|
||||
if {arg_name, 0} in __MODULE__.module_info(:exports) do
|
||||
case apply(__MODULE__, arg_name, []).verify(val) do
|
||||
# if this argument is valid, continue enumeration.
|
||||
:ok -> decode_args(rest, [arg | acc])
|
||||
{:error, _} = err -> err
|
||||
end
|
||||
else
|
||||
{:error, {:unknown_arg, arg_name}}
|
||||
end
|
||||
end
|
||||
|
||||
# When we have validated all of the arguments
|
||||
# Change it back to a map.
|
||||
def decode_args([], acc) do
|
||||
{:ok, Map.new(acc)}
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
@doc "Allow a list of args."
|
||||
defmacro allow_args(args) do
|
||||
arg_mod_base = Farmbot.CeleryScript.AST.Arg
|
||||
args_and_mods = for arg <- args do
|
||||
mod = Module.concat(arg_mod_base, Macro.camelize(arg |> to_string))
|
||||
{arg, mod}
|
||||
end
|
||||
|
||||
for {arg, mod} <- args_and_mods do
|
||||
quote do
|
||||
# Define this arg, pointing to the module responsible
|
||||
# For validating it.
|
||||
@doc false
|
||||
def unquote(arg)() do
|
||||
unless Code.ensure_loaded?(unquote(mod)) do
|
||||
raise CompileError,
|
||||
description: "Unknown CeleryScript arg: #{unquote(arg)} (#{unquote(mod)})", file: __ENV__.file
|
||||
end
|
||||
unquote(mod)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# AST struct.
|
||||
defstruct [:kind, :args, :body, :comment]
|
||||
|
||||
@doc "Try to decode anything into an AST struct."
|
||||
def decode(arg1)
|
||||
|
||||
def decode(binary) when is_binary(binary) do
|
||||
case Poison.decode(binary, keys: :atoms) do
|
||||
{:ok, string_map} -> decode(string_map)
|
||||
{:error, _} -> {:error, :unknown_binary}
|
||||
end
|
||||
end
|
||||
|
||||
def decode(list) when is_list(list), do: decode_body(list)
|
||||
|
||||
def decode(%{kind: kind, args: args} = map) do
|
||||
case kind_to_mod(kind) do
|
||||
nil -> {:error, {:unknown_kind, kind}}
|
||||
mod when is_atom(mod) ->
|
||||
case decode_body(map[:body] || []) do
|
||||
{:ok, body} ->
|
||||
case mod.decode_args(args) do
|
||||
{:ok, decoded} ->
|
||||
opts = [kind: mod,
|
||||
args: decoded,
|
||||
body: body,
|
||||
comment: map[:comment]]
|
||||
val = struct(__MODULE__, opts)
|
||||
{:ok, val}
|
||||
{:error, _} = err -> err
|
||||
end
|
||||
{:error, _} = err -> err
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# decode a list of ast nodes.
|
||||
defp decode_body(body, acc \\ [])
|
||||
defp decode_body([node | rest], acc) do
|
||||
case decode(node) do
|
||||
{:ok, re} -> decode_body(rest, [re | acc])
|
||||
{:error, _} = err -> err
|
||||
end
|
||||
end
|
||||
|
||||
defp decode_body([], acc), do: {:ok, Enum.reverse(acc)}
|
||||
|
||||
@doc "Lookup a module by it's kind."
|
||||
def kind_to_mod(kind) when is_binary(kind) do
|
||||
mod = [__MODULE__, "Node", Macro.camelize(kind)] |> Module.concat()
|
||||
case Code.ensure_loaded?(mod) do
|
||||
false -> nil
|
||||
true -> mod
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Compiler.CompileError do
|
||||
defexception [:message]
|
||||
|
||||
def exception(message) do
|
||||
%__MODULE__{message: message}
|
||||
end
|
||||
end
|
|
@ -1,99 +0,0 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Compiler do
|
||||
@moduledoc false
|
||||
|
||||
require Logger
|
||||
|
||||
alias Farmbot.CeleryScript.AST
|
||||
alias Farmbot.CeleryScript.AST.Compiler.CompileError
|
||||
alias Farmbot.CeleryScript.VirtualMachine.InstructionSet
|
||||
|
||||
defmodule SnapShot do
|
||||
@moduledoc false
|
||||
defstruct [count: 0, points: %{}, sequences: %{}, tools: %{}]
|
||||
|
||||
def add(node, snapshot) do
|
||||
apply(__MODULE__, :"#{node.kind}", [node, snapshot])
|
||||
end
|
||||
|
||||
def point(node, snapshot) do
|
||||
count_and_add_to(snapshot, :points, :pointer_id, node)
|
||||
end
|
||||
|
||||
def execute(node, snapshot) do
|
||||
count_and_add_to(snapshot, :sequences, :sequence_id, node)
|
||||
end
|
||||
|
||||
def tool(node, snapshot) do
|
||||
count_and_add_to(snapshot, :tools, :tool_id, node)
|
||||
end
|
||||
|
||||
def count_and_add_to(snapshot, collection_name, arg_name, node) do
|
||||
id = node.args[arg_name] || raise "no id"
|
||||
collection = Map.get(snapshot, collection_name) || raise "no collection"
|
||||
case collection[id] do
|
||||
nil ->
|
||||
snapshot
|
||||
|> Map.put(:count, snapshot.count + 1)
|
||||
|> Map.put(collection_name, Map.put(collection, id, node))
|
||||
_ -> snapshot
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Freezer do
|
||||
def climb(node, snapshot, callback) do
|
||||
go(node, snapshot, callback)
|
||||
end
|
||||
|
||||
def go(%AST{kind: kind, args: args, body: body} = node, snapshot, callback) do
|
||||
{node, snapshot} = maybe_freeze(node, snapshot, callback)
|
||||
{body, snapshot} = Enum.reduce(node.body, {[], snapshot}, fn(sub_ast, {body, snapshot}) ->
|
||||
{node, snapshot} = maybe_freeze(sub_ast, snapshot, callback)
|
||||
{body ++ [node], snapshot}
|
||||
end)
|
||||
{%{node | body: body}, snapshot}
|
||||
end
|
||||
|
||||
def maybe_freeze(node, snapshot, callback) do
|
||||
if node.kind in ["execute", "point", "tool"] do
|
||||
snapshot = apply(SnapShot, callback, [node, snapshot])
|
||||
{node, snapshot}
|
||||
else
|
||||
{node, snapshot}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def compile(ast, %InstructionSet{} = instruction_set, snapshot \\ nil) do
|
||||
snapshot = snapshot || struct(SnapShot)
|
||||
starting = snapshot.count
|
||||
{ast, snapshot} = Freezer.climb(ast, snapshot, :add)
|
||||
ending = snapshot.count
|
||||
if (ending > starting && ending != 0) do
|
||||
fetch_sequences(instruction_set, snapshot, Map.keys(snapshot.sequences))
|
||||
else
|
||||
IO.puts "stop recursion."
|
||||
snapshot
|
||||
end
|
||||
end
|
||||
|
||||
def fetch_sequences(instruction_set, snapshot, []) do
|
||||
snapshot
|
||||
end
|
||||
|
||||
def fetch_sequences(instruction_set, snapshot, [id | rest]) do
|
||||
replace_me = Map.get(snapshot.sequences, id) || raise "no sequencce: #{id}"
|
||||
if replace_me.kind == "execute" do
|
||||
IO.puts "replacing: #{inspect replace_me}"
|
||||
seq_ast = Farmbot.HTTP.get!("/api/sequences/#{replace_me.args.sequence_id}").body |> Poison.decode! |> Farmbot.CeleryScript.AST.parse
|
||||
sequences = %{snapshot.sequences | id => seq_ast}
|
||||
snapshot = compile(seq_ast, instruction_set, %{snapshot | sequences: sequences})
|
||||
fetch_sequences(instruction_set, snapshot, rest)
|
||||
else
|
||||
fetch_sequences(instruction_set, snapshot, rest)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# Farmbot.HTTP.get!("/api/sequences/2") |> Map.get(:body) |> Poison.decode! |> Farmbot.CeleryScript.AST.parse |> Farmbot.CeleryScript.VirtualMachine.execute
|
|
@ -1,6 +1,6 @@
|
|||
defimpl Inspect, for: Farmbot.CeleryScript.AST do
|
||||
def inspect(ast, _opts) do
|
||||
body = Enum.map(ast.body, fn(sub_ast) -> sub_ast.kind end) |> inspect()
|
||||
"#CeleryScript<#{ast.kind}: #{inspect(Map.keys(ast.args))}, #{body}>"
|
||||
end
|
||||
end
|
||||
# defimpl Inspect, for: Farmbot.CeleryScript.AST do
|
||||
# def inspect(ast, _opts) do
|
||||
# body = Enum.map(ast.body, fn(sub_ast) -> sub_ast.kind end) |> inspect()
|
||||
# "#CeleryScript<#{ast.kind}: #{inspect(Map.keys(ast.args))}, #{body}>"
|
||||
# end
|
||||
# end
|
||||
|
|
5
lib/farmbot/celery_script/ast/node/_if.ex
Normal file
5
lib/farmbot/celery_script/ast/node/_if.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.If do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:lhs, :op, :rhs, :_then, :_else]
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/add_point.ex
Normal file
5
lib/farmbot/celery_script/ast/node/add_point.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.AddPoint do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:location]
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/calibrate.ex
Normal file
5
lib/farmbot/celery_script/ast/node/calibrate.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.Calibrate do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:axis]
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/channel.ex
Normal file
5
lib/farmbot/celery_script/ast/node/channel.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.Channel do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:channel_name]
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/check_updates.ex
Normal file
5
lib/farmbot/celery_script/ast/node/check_updates.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.CheckUpdates do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:package]
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/config_update.ex
Normal file
5
lib/farmbot/celery_script/ast/node/config_update.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.ConfigUpdate do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:package]
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/coordinate.ex
Normal file
5
lib/farmbot/celery_script/ast/node/coordinate.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.Coordinate do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:x, :y, :z]
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/data_update.ex
Normal file
5
lib/farmbot/celery_script/ast/node/data_update.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.DataUpdate do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:value]
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/emergency_lock.ex
Normal file
5
lib/farmbot/celery_script/ast/node/emergency_lock.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.EmergencyLock do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args []
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/emergency_unlock.ex
Normal file
5
lib/farmbot/celery_script/ast/node/emergency_unlock.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.EmergencyUnlock do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args []
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/execute.ex
Normal file
5
lib/farmbot/celery_script/ast/node/execute.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.Execute do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:sequence_id]
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/execute_script.ex
Normal file
5
lib/farmbot/celery_script/ast/node/execute_script.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.ExecuteScript do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:label]
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/explanation.ex
Normal file
5
lib/farmbot/celery_script/ast/node/explanation.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.Explanation do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:message]
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/factory_reset.ex
Normal file
5
lib/farmbot/celery_script/ast/node/factory_reset.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.FactoryReset do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:package]
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/find_home.ex
Normal file
5
lib/farmbot/celery_script/ast/node/find_home.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.FindHome do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:speed, :axis]
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/home.ex
Normal file
5
lib/farmbot/celery_script/ast/node/home.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.Home do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:speed, :axis]
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/install_farmware.ex
Normal file
5
lib/farmbot/celery_script/ast/node/install_farmware.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.InstallFarmware do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:url]
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.InstallFirstPartyFarmware do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args []
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/move_absolute.ex
Normal file
5
lib/farmbot/celery_script/ast/node/move_absolute.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.MoveAbsolute do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:location, :speed, :offset]
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/move_relative.ex
Normal file
5
lib/farmbot/celery_script/ast/node/move_relative.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.MoveRelative do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:x, :y, :z, :speed]
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/nothing.ex
Normal file
5
lib/farmbot/celery_script/ast/node/nothing.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.Nothing do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args []
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/pair.ex
Normal file
5
lib/farmbot/celery_script/ast/node/pair.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.Pair do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:label, :value]
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/point.ex
Normal file
5
lib/farmbot/celery_script/ast/node/point.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.Point do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:pointer_type, :pointer_id]
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/power_off.ex
Normal file
5
lib/farmbot/celery_script/ast/node/power_off.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.PowerOff do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args []
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/read_pin.ex
Normal file
5
lib/farmbot/celery_script/ast/node/read_pin.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.ReadPin do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:pin_number, :label, :pin_mode]
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/read_status.ex
Normal file
5
lib/farmbot/celery_script/ast/node/read_status.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.ReadStatus do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args []
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/reboot.ex
Normal file
5
lib/farmbot/celery_script/ast/node/reboot.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.Reboot do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args []
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/remove_farmware.ex
Normal file
5
lib/farmbot/celery_script/ast/node/remove_farmware.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.RemoveFarmware do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:package]
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/rpc_error.ex
Normal file
5
lib/farmbot/celery_script/ast/node/rpc_error.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.RpcError do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:label]
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/rpc_ok.ex
Normal file
5
lib/farmbot/celery_script/ast/node/rpc_ok.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.RpcOk do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:label]
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/rpc_request.ex
Normal file
5
lib/farmbot/celery_script/ast/node/rpc_request.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.RpcRequest do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:label]
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/send_message.ex
Normal file
5
lib/farmbot/celery_script/ast/node/send_message.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.SendMessage do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:message, :message_type]
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/sequence.ex
Normal file
5
lib/farmbot/celery_script/ast/node/sequence.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.Sequence do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:version, :is_outdated]
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/set_user_env.ex
Normal file
5
lib/farmbot/celery_script/ast/node/set_user_env.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.SetUserEnv do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args []
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/sync.ex
Normal file
5
lib/farmbot/celery_script/ast/node/sync.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.Sync do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args []
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/take_photo.ex
Normal file
5
lib/farmbot/celery_script/ast/node/take_photo.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.TakePhoto do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args []
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/toggle_pin.ex
Normal file
5
lib/farmbot/celery_script/ast/node/toggle_pin.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.TogglePin do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:pin_number]
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/tool.ex
Normal file
5
lib/farmbot/celery_script/ast/node/tool.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.Tool do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:tool_id]
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/update_farmware.ex
Normal file
5
lib/farmbot/celery_script/ast/node/update_farmware.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.UpdateFarmware do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:package]
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/wait.ex
Normal file
5
lib/farmbot/celery_script/ast/node/wait.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.Wait do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:milliseconds]
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/write_pin.ex
Normal file
5
lib/farmbot/celery_script/ast/node/write_pin.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.WritePin do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:pin_number, :pin_value, :pin_mode]
|
||||
end
|
5
lib/farmbot/celery_script/ast/node/zero.ex
Normal file
5
lib/farmbot/celery_script/ast/node/zero.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.Zero do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:axis]
|
||||
end
|
|
@ -1,8 +0,0 @@
|
|||
defmodule Farmbot.CeleryScript.VirtualMachine.Instruction do
|
||||
@moduledoc "Behaviour for implementing CeleryScript nodes."
|
||||
alias Farmbot.CeleryScript.AST
|
||||
|
||||
@callback precompile(AST.t) :: {:ok, AST.t} | {:error, term}
|
||||
|
||||
@callback execute() :: {:ok, Ast.t} | {:error, term}
|
||||
end
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue