diff --git a/src/internal.hrl b/src/internal.hrl index a3ee471..63b60fc 100644 --- a/src/internal.hrl +++ b/src/internal.hrl @@ -1 +1 @@ --record(seresye, {kb, alfa, join, agenda, pending_actions, client_state}). +-record(seresye, {kb, alfa, join, agenda, pending_actions, client_state, fired_rule, hooks = []}). diff --git a/src/seresye.erl b/src/seresye.erl index 962fbc3..5f59914 100644 --- a/src/seresye.erl +++ b/src/seresye.erl @@ -15,6 +15,7 @@ -export([start/0, start/1, start/2, stop/1, get_engine/1, add_rules/2, add_rule/2, add_rule/3, assert/2, get_kb/1, get_rules_fired/1, get_client_state/1, + set_hooks/2, get_fired_rule/1, set_client_state/2, query_kb/2, remove_rule/2, retract/2]). %% gen_server callbacks @@ -33,6 +34,9 @@ start(Name) -> start(Name, ClientState) -> seresye_sup:start_engine(Name, ClientState). +set_hooks(Name, Hooks) when is_list(Hooks) -> + gen_server:cast(Name, {set_hooks, Hooks}). + set_client_state(Name, NewState) -> gen_server:cast(Name, {set_client_state, NewState}). @@ -72,6 +76,9 @@ remove_rule(Name, Rule) -> get_rules_fired(Name) -> gen_server:call(Name, get_rules_fired). +get_fired_rule(Name) -> + gen_server:call(Name, get_fired_rule). + get_kb(Name) -> gen_server:call(Name, get_kb). @@ -172,6 +179,15 @@ handle_call(get_rules_fired, _From, State0) -> {error, {Type, Reason}} end, {reply, Reply, State0}; +handle_call(get_fired_rule, _From, State0) -> + Reply = + try + seresye_engine:get_fired_rule(State0) + catch + Type:Reason -> + {error, {Type, Reason}} + end, + {reply, Reply, State0}; handle_call(get_engine, _From, State0) -> {reply, State0, State0}; handle_call(get_kb, _From, State0) -> @@ -193,6 +209,9 @@ handle_call({query_kb, Pattern}, _From, State0) -> end, {reply, Reply, State0}. +handle_cast({set_hooks, Hooks}, State) -> + {noreply, seresye_engine:set_hooks(State, Hooks)}; + handle_cast({set_client_state, CS}, State) -> {noreply, seresye_engine:set_client_state(State, CS)}. diff --git a/src/seresye_agenda.erl b/src/seresye_agenda.erl index 6baee3b..c08991a 100644 --- a/src/seresye_agenda.erl +++ b/src/seresye_agenda.erl @@ -314,4 +314,18 @@ execute_rule(EngineState, {{M,F}, Args, X1, X2}) -> L = length(Args) + 1, execute_rule(EngineState, {fun M:F/L, Args, X1, X2}); execute_rule(EngineState, {Fun, Args, _, _}) when is_function(Fun) -> - apply(Fun, [EngineState | Args]). + case proplists:get_value(before_rule, EngineState#seresye.hooks) of + BF when is_function(BF) -> + BF(EngineState, Fun, Args); + _ -> + ignore + end, + Result = apply(Fun, [EngineState#seresye { fired_rule = {Fun, Args} } | Args]), + case proplists:get_value(after_rule, EngineState#seresye.hooks) of + AF when is_function(AF) -> + AF(Result, Fun, Args); + _ -> + ignore + end, + Result#seresye{ fired_rule = undefined }. + diff --git a/src/seresye_engine.erl b/src/seresye_engine.erl index a2b635a..293349d 100644 --- a/src/seresye_engine.erl +++ b/src/seresye_engine.erl @@ -25,6 +25,7 @@ %%==================================================================== -export([new/0, new/1, + set_hooks/2, get_fired_rule/1, add_rules/2, add_rule/2, add_rule/3, assert/2, get_kb/1, get_rules_fired/1, get_client_state/1, set_client_state/2, query_kb/2, remove_rule/2, retract/2]). @@ -41,6 +42,9 @@ new(ClientState) -> pending_actions=[], client_state=ClientState}). +set_hooks(EngineState, Hooks) when is_list(Hooks) -> + EngineState#seresye{ hooks = Hooks }. + set_client_state(EngineState, NewState) -> EngineState#seresye{client_state=NewState}. @@ -130,6 +134,9 @@ add_rule(EngineState0, {Module, Fun}, ClauseID, Salience) -> remove_rule(EngineState0, Rule) -> execute_pending(remove_prod(seresye_agenda:delete_rule(EngineState0, Rule), Rule)). +get_fired_rule(#seresye{ fired_rule = Rule }) -> + Rule. + get_rules_fired(EngineState) -> seresye_agenda:get_rules_fired(EngineState).