84 lines
2.3 KiB
Elixir
84 lines
2.3 KiB
Elixir
defmodule Farmbot.CeleryScript.RunTime.Resolver do
|
|
@moduledoc """
|
|
Recursivly climbs a FarmProc stack until a variable is found, or
|
|
raises an error.
|
|
"""
|
|
|
|
alias Farmbot.CeleryScript.RunTime.{FarmProc, Error}
|
|
alias Farmbot.CeleryScript.AST
|
|
|
|
@nodes_with_declerations [:sequence]
|
|
|
|
@spec resolve(FarmProc.t(), Pointer.t(), String.t()) :: AST.t()
|
|
def resolve(%FarmProc{} = farm_proc, %Pointer{} = pointer, label)
|
|
when is_binary(label) do
|
|
# step1 keep climbing (recursivly) __parent until kind in @nodes_with_declerations
|
|
# step2 execute rule for resolution per node
|
|
# step2.5 if no data, explode
|
|
# step3 unslice at address
|
|
# step4 profit??
|
|
search_tree(farm_proc, pointer, label)
|
|
end
|
|
|
|
def search_tree(
|
|
%FarmProc{} = farm_proc,
|
|
%Pointer{} = pointer,
|
|
label
|
|
)
|
|
when is_binary(label) do
|
|
if FarmProc.is_null_address?(pointer) do
|
|
error_opts = [
|
|
farm_proc: farm_proc,
|
|
message: "unbound identifier: #{label} from pc: #{inspect(pointer)}"
|
|
]
|
|
|
|
raise Error, error_opts
|
|
end
|
|
|
|
kind = FarmProc.get_kind(farm_proc, pointer)
|
|
|
|
if kind in @nodes_with_declerations do
|
|
result = do_resolve(kind, farm_proc, pointer, label)
|
|
%Address{} = page = pointer.page_address
|
|
|
|
%Pointer{} =
|
|
new_pointer = Pointer.new(page, FarmProc.get_parent(farm_proc, pointer))
|
|
|
|
if is_nil(result) do
|
|
search_tree(farm_proc, new_pointer, label)
|
|
else
|
|
result
|
|
end
|
|
else
|
|
%Address{} = page = pointer.page_address
|
|
|
|
%Pointer{} =
|
|
new_pointer = Pointer.new(page, FarmProc.get_parent(farm_proc, pointer))
|
|
|
|
search_tree(farm_proc, new_pointer, label)
|
|
end
|
|
end
|
|
|
|
def do_resolve(:sequence, farm_proc, pointer, label) do
|
|
locals_ptr =
|
|
FarmProc.get_cell_attr_as_pointer(farm_proc, pointer, :__locals)
|
|
|
|
ast =
|
|
AST.unslice(
|
|
farm_proc.heap[locals_ptr.page_address],
|
|
locals_ptr.heap_address
|
|
)
|
|
|
|
Enum.find_value(ast.body, fn %{
|
|
args: %{
|
|
label: sub_label,
|
|
data_value: val
|
|
}
|
|
} ->
|
|
if sub_label == label do
|
|
val
|
|
end
|
|
end)
|
|
end
|
|
end
|