85 lines
2.7 KiB
Erlang
85 lines
2.7 KiB
Erlang
-module(wfc_eval).
|
|
|
|
-export_type([
|
|
]).
|
|
|
|
-export([
|
|
eval/1, eval/2
|
|
]).
|
|
|
|
-type context() :: wfc_eval_context:context().
|
|
-type expr() :: wfc_read:expr().
|
|
-type sentence() :: wfc_sentence:sentence().
|
|
-type eval_result() :: noop | sentence().
|
|
|
|
|
|
%-type op() :: {op, '+' | '*'}.
|
|
%-type val() :: {val, 0 | 1}.
|
|
%-type ltr() :: wfc_ltr:ltr().
|
|
%-type snowflake() :: {snowflake, binary()}.
|
|
%-type pattern() :: {pattern, binary()}.
|
|
%-type sexp() :: {sexp, [expr()]}.
|
|
%-type expr() :: sexp() | ltr() | op() | snowflake() | pattern() | val().
|
|
|
|
-spec eval(expr()) -> {ok, eval_result(), context()} | {error, string()}.
|
|
|
|
eval(Expr) ->
|
|
eval(Expr, wfc_eval_context:default()).
|
|
|
|
|
|
-spec eval(expr(), context()) -> {ok, eval_result(), context()} | {error, string()}.
|
|
|
|
eval({sexp, Args}, Ctx) -> eval_sexp(Args, Ctx);
|
|
eval({val, 0}, Ctx) -> {ok, wfc_sentence:zero(), Ctx};
|
|
eval({val, 1}, Ctx) -> {ok, wfc_sentence:one(), Ctx};
|
|
eval({pattern, Pat}, Ctx) ->
|
|
case wfc_eval_context:resolve_pattern(Pat, Ctx) of
|
|
{ok, Sentence} -> {ok, Sentence, Ctx};
|
|
Error -> Error
|
|
end;
|
|
eval(Ltr = {c, _}, Ctx) ->
|
|
case wfc:to_sentence(Ltr) of
|
|
{ok, S} -> {ok, S, Ctx};
|
|
Error -> Error
|
|
end;
|
|
eval(Expr, _) -> {error, wfc_utils:str("wfc_eval:eval: cannot evaluate expression: ~p", [Expr])}.
|
|
|
|
|
|
eval_sexp(Args = [{snowflake, <<"define">>}, {pattern, Pat}, Expr], Ctx0) ->
|
|
case eval(Expr, Ctx0) of
|
|
{ok, noop, _} ->
|
|
{error, wfc_utils:str("wfc_eval:eval_sexp: define X Y: Y evaluated to noop: ~w", [Args])};
|
|
{ok, Sentence, _} ->
|
|
case wfc_eval_context:define(Pat, Sentence, Ctx0) of
|
|
{ok, NewContext} -> {ok, noop, NewContext};
|
|
Error -> Error
|
|
end;
|
|
Error ->
|
|
Error
|
|
end;
|
|
eval_sexp([{op, '+'} | Exprs], Ctx) ->
|
|
case eval_sexp_args(Exprs, Ctx, []) of
|
|
{ok, Sentences, NewCtx} -> {ok, wfc_sentence:add(Sentences), NewCtx};
|
|
Error -> Error
|
|
end;
|
|
eval_sexp([{op, '*'} | Exprs], Ctx) ->
|
|
case eval_sexp_args(Exprs, Ctx, []) of
|
|
{ok, Sentences, NewCtx} -> {ok, wfc_sentence:mul(Sentences), NewCtx};
|
|
Error -> Error
|
|
end;
|
|
eval_sexp(Args, Ctx) ->
|
|
{error, wfc_utils:str("wfc_eval:eval_sexp: bad sexp: Args=~tw; Ctx=~tw", [Args, Ctx])}.
|
|
|
|
|
|
eval_sexp_args(Exprs, Ctx0, Acc) ->
|
|
case Exprs of
|
|
[] -> {ok, lists:reverse(Acc), Ctx0};
|
|
[E | Rest] ->
|
|
case eval(E, Ctx0) of
|
|
{ok, noop, Ctx1} -> eval_sexp_args(Rest, Ctx1, Acc);
|
|
{ok, S, Ctx1} -> eval_sexp_args(Rest, Ctx1, [S | Acc]);
|
|
Error ->
|
|
Error
|
|
end
|
|
end.
|