From 8cb4471731d73d02e39e79ad7232735855db76ae Mon Sep 17 00:00:00 2001 From: Nathanael Sensfelder Date: Mon, 21 Oct 2019 21:30:41 +0200 Subject: Adds 'if-then-else/ternary' and 'let/bind' ops. --- include/ataxia/ataxic.hrl | 23 ++++++++ src/ataxic.erl | 142 +++++++++++++++++++++++++++++++--------------- 2 files changed, 120 insertions(+), 45 deletions(-) diff --git a/include/ataxia/ataxic.hrl b/include/ataxia/ataxic.hrl index 6e6f34b..04186a5 100644 --- a/include/ataxia/ataxic.hrl +++ b/include/ataxia/ataxic.hrl @@ -41,8 +41,31 @@ -record(lor, {params :: list(ataxic:basic())}). -record(neg, {param :: ataxic:basic()}). +%%%% List Operations -record(list_cons, {param :: ataxic:basic()}). +%%%% Condition +-record +( + tern, + { + condition :: ataxic:basic(), + then :: ataxic:basic(), + else :: ataxic:basic() + } +). + +%%%% Memory +-record +( + letr, + { + bindings :: list({ataxic:variable(), ataxic:basic()}), + op :: ataxic:basic() + } +). +-record (var, { name :: ataxic:variable() }). + %%%% META OP %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%% Select -record(read_perm, {op :: ataxic:basic()}). diff --git a/src/ataxic.erl b/src/ataxic.erl index 09cf22e..bb9e561 100644 --- a/src/ataxic.erl +++ b/src/ataxic.erl @@ -31,14 +31,26 @@ | #lor{} | #neg{} - | #list_cons{}. +%%%% List Operations + | #list_cons{} + +%%%% Condition + | #tern{} + +%%%% Memory + | #letr{} + | #var{} +. %%%% META OP %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -type meta() :: #read_perm{} | #write_perm{} | #value{} | #lock{} | #mseq{}. + +-type variable() :: atom(). + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --export_type([basic/0, meta/0]). +-export_type([basic/0, meta/0, variable/0]). -export ( @@ -57,7 +69,9 @@ land/1, lor/1, neg/1, - list_cons/1 + list_cons/1, + ternary/3, + bind/2 ] ). @@ -72,58 +86,85 @@ ] ). --export([basic_apply_to/2, apply_to/2, matches/2]). +-export([apply_basic_to/2, apply_to/2, matches/2]). -export([is_constant/1]). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --spec basic_apply_to (basic(), any()) -> any(). -basic_apply_to (#upfield{ ix = IX, op = OP}, Val) -> - setelement(IX, Val, basic_apply_to(OP, element(IX, Val))); -basic_apply_to (#field{ ix = IX, op = OP}, Val) -> - basic_apply_to(OP, element(IX, Val)); -basic_apply_to (#apply_fun{ module = M, function = F, params = P }, Val) -> +-spec apply_basic_to (basic(), any(), dict:dict(variable(), basic())) -> any(). +apply_basic_to (#upfield{ ix = IX, op = OP}, Val, Mem) -> + setelement(IX, Val, apply_basic_to(OP, element(IX, Val), Mem)); +apply_basic_to (#field{ ix = IX, op = OP}, Val, Mem) -> + apply_basic_to(OP, element(IX, Val), Mem); +apply_basic_to (#apply_fun{ module = M, function = F, params = P }, Val, Mem) -> erlang:apply ( M, F, - lists:map(fun (Param) -> basic_apply_to(Param, Val) end, P) + lists:map(fun (Param) -> apply_basic_to(Param, Val, Mem) end, P) ); -basic_apply_to (#seq{ ops = List }, Val) -> - lists:foldl(fun basic_apply_to/2, Val, List); +apply_basic_to (#seq{ ops = List }, Val, Mem) -> + lists:foldl + ( + fun (OP, CurrentVal) -> + apply_basic_to(OP, CurrentVal, Mem) + end, + Val, + List + ); -basic_apply_to (#const{ value = Val }, _Val) -> +apply_basic_to (#const{ value = Val }, _Val, _Mem) -> Val; -basic_apply_to (#current{}, Val) -> +apply_basic_to (#current{}, Val, _Mem) -> Val; +apply_basic_to (#var{ name = Name }, _Val, Mem) -> + dict:fetch(Name, Mem); + +apply_basic_to (#ge{ p0 = P0, p1 = P1 }, Val, Mem) -> + apply_basic_to(P0, Val, Mem) >= apply_basic_to(P1, Val, Mem); +apply_basic_to (#gt{ p0 = P0, p1 = P1 }, Val, Mem) -> + apply_basic_to(P0, Val, Mem) > apply_basic_to(P1, Val, Mem); +apply_basic_to (#le{ p0 = P0, p1 = P1 }, Val, Mem) -> + apply_basic_to(P0, Val, Mem) =< apply_basic_to(P1, Val, Mem); +apply_basic_to (#lt{ p0 = P0, p1 = P1 }, Val, Mem) -> + apply_basic_to(P0, Val, Mem) < apply_basic_to(P1, Val, Mem); +apply_basic_to (#eq{ p0 = P0, p1 = P1 }, Val, Mem) -> + apply_basic_to(P0, Val, Mem) == apply_basic_to(P1, Val, Mem); + +apply_basic_to (#land{ params = List }, Val, Mem) -> + lists:all(fun (E) -> apply_basic_to(E, Val, Mem) end, List); +apply_basic_to (#lor{ params = List }, Val, Mem) -> + lists:any(fun (E) -> apply_basic_to(E, Val, Mem) end, List); +apply_basic_to (#neg{ param = V }, Val, Mem) -> + not apply_basic_to(V, Val, Mem); + +apply_basic_to (#list_cons{ param = V }, Val, Mem) -> + [apply_basic_to(V, Val, Mem)|Val]; + +apply_basic_to (#tern{ condition = C, then = T, else = E }, Val, Mem) -> + case apply_basic_to(C, Val, Mem) of + true -> apply_basic_to(T, Val, Mem); + false -> apply_basic_to(E, Val, Mem); + Other -> error({"Expected boolean from ternary condition, got", Other}) + end; + +apply_basic_to (#letr{ bindings = Bindings, op = OP }, Val, S0Mem) -> + S1Mem = + lists:foldl + ( + fun ({Key, Value}, Memory) -> dict:store(Key, Value, Memory) end, + S0Mem, + Bindings + ), + + apply_basic_to(OP, Val, S1Mem). -basic_apply_to (#ge{ p0 = P0, p1 = P1 }, Val) -> - basic_apply_to(P0, Val) >= basic_apply_to(P1, Val); -basic_apply_to (#gt{ p0 = P0, p1 = P1 }, Val) -> - basic_apply_to(P0, Val) > basic_apply_to(P1, Val); -basic_apply_to (#le{ p0 = P0, p1 = P1 }, Val) -> - basic_apply_to(P0, Val) =< basic_apply_to(P1, Val); -basic_apply_to (#lt{ p0 = P0, p1 = P1 }, Val) -> - basic_apply_to(P0, Val) < basic_apply_to(P1, Val); -basic_apply_to (#eq{ p0 = P0, p1 = P1 }, Val) -> - basic_apply_to(P0, Val) == basic_apply_to(P1, Val); - -basic_apply_to (#land{ params = List }, Val) -> - lists:all(fun (E) -> basic_apply_to(E, Val) end, List); -basic_apply_to (#lor{ params = List }, Val) -> - lists:any(fun (E) -> basic_apply_to(E, Val) end, List); -basic_apply_to (#neg{ param = V }, Val) -> - not basic_apply_to(V, Val); - -basic_apply_to (#list_cons{ param = V }, Val) -> - [basic_apply_to(V, Val)|Val]. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -spec update_field (non_neg_integer(), basic()) -> basic(). update_field (IX, OP) -> #upfield{ ix = IX, op = OP }. @@ -171,6 +212,13 @@ neg (V) -> #neg{ param = V }. -spec list_cons (basic()) -> basic(). list_cons (V) -> #list_cons{ param = V}. +-spec ternary (basic(), basic(), basic()) -> basic(). +ternary (Cond, Then, Else) -> + #tern{ condition = Cond, then = Then, else = Else }. + +-spec bind (list({variable(), basic()}), basic()) -> basic(). +bind (Bindings, OP) -> #letr{ bindings = Bindings, op = OP }. + -spec sequence_meta (list(meta())) -> meta(). sequence_meta (List) -> #mseq{ ops = List }. @@ -191,35 +239,39 @@ update_value (OP) -> #value{ op = OP }. apply_to (#value{ op = OP }, Entry) -> ataxia_entry:set_value ( - basic_apply_to(OP, ataxia_entry:get_value(Entry)), + apply_basic_to(OP, ataxia_entry:get_value(Entry)), Entry ); apply_to (#lock{ op = OP }, Entry) -> ataxia_entry:set_lock ( - basic_apply_to(OP, ataxia_entry:get_lock(Entry)), + apply_basic_to(OP, ataxia_entry:get_lock(Entry)), Entry ); apply_to (#read_perm{ op = OP }, Entry) -> ataxia_entry:set_read_permission ( - basic_apply_to(OP, ataxia_entry:get_read_permission(Entry)), + apply_basic_to(OP, ataxia_entry:get_read_permission(Entry)), Entry ); apply_to (#write_perm{ op = OP }, Entry) -> ataxia_entry:set_write_permission ( - basic_apply_to(OP, ataxia_entry:get_write_permission(Entry)), + apply_basic_to(OP, ataxia_entry:get_write_permission(Entry)), Entry ); apply_to (#mseq { ops = List }, Entry) -> lists:foldl(fun apply_to/2, Entry, List). +-spec apply_basic_to (basic(), any()) -> any(). +apply_basic_to (OP, Val) -> + apply_basic_to(OP, Val, dict:new()). + -spec matches (basic(), ataxia_entry:type()) -> boolean(). matches (OP, Entry) -> - Result = basic_apply_to(OP, Entry), + Result = apply_basic_to(OP, Entry), io:format("matches test result:~p~n", [Result]), - case basic_apply_to(OP, Entry) of + case apply_basic_to(OP, Entry) of true -> true; _ -> false end. -- cgit v1.2.3-70-g09d2