Current section
Files
Jump to
Current section
Files
lib/wongi/engine/compiler.ex
defmodule Wongi.Engine.Compiler do
@moduledoc false
alias Wongi.Engine.Beta
alias Wongi.Engine.Beta.Production
alias Wongi.Engine.DSL.Clause
alias Wongi.Engine.DSL.Rule
alias Wongi.Engine.Rete
defstruct [:rete, :node_ref, :variables]
def compile(rete, %Rule{} = rule) do
context = %__MODULE__{
rete: rete,
node_ref: Beta.ref(rete.beta_root),
variables: MapSet.new()
}
context =
Enum.reduce(rule.forall, context, &Clause.compile/2)
|> production(rule.ref, rule.actions)
context.rete
end
def find_existing(%__MODULE__{rete: rete, node_ref: node_ref} = _context, node) do
rete
|> Rete.beta_subscriptions(node_ref)
|> Enum.find(&Beta.equivalent?(&1, node, rete))
end
def declare_variable(%__MODULE__{variables: variables} = context, var) do
%__MODULE__{context | variables: MapSet.put(variables, var)}
end
def advance(%__MODULE__{rete: rete, node_ref: parent_ref} = context, node) do
rete =
Beta.seed(parent_ref, node, rete)
|> Rete.add_beta(node)
context
|> put_node(node)
|> put_rete(rete)
end
def advance_existing(%__MODULE__{} = context, node) do
context
|> put_node(node)
end
def put_rete(context, rete) do
%__MODULE__{context | rete: rete}
end
defp put_node(%__MODULE__{} = context, node) do
%__MODULE__{context | node_ref: Beta.ref(node)}
end
defp production(context, ref, actions) do
node = Production.new(ref, context.node_ref, actions)
case find_existing(context, node) do
nil ->
context
|> advance(node)
node ->
context
|> advance_existing(node)
end
end
end