Compile let
to FATE
This commit is contained in:
parent
bc8b2d1c81
commit
33bb8a37d0
@ -31,9 +31,15 @@
|
||||
| {var, var_name()}
|
||||
| {binop, ftype(), binop(), fexpr(), fexpr()}
|
||||
| {'if', fexpr(), fexpr(), fexpr()}
|
||||
| {todo, term()}.
|
||||
| {switch, fexpr(), [falt()]}.
|
||||
|
||||
-type fpat() :: {var, var_name()}.
|
||||
|
||||
-type falt() :: {fpat(), fexpr()}.
|
||||
|
||||
-type ftype() :: aeb_fate_data:fate_type_type().
|
||||
|
||||
|
||||
-type fun_def() :: #{ attrs := [attribute()],
|
||||
args := [{var_name(), ftype()}],
|
||||
return := ftype(),
|
||||
@ -173,20 +179,43 @@ expr_to_fcode(Env, _Type, {'if', _, Cond, Then, Else}) ->
|
||||
expr_to_fcode(Env, Then),
|
||||
expr_to_fcode(Env, Else)};
|
||||
|
||||
%% Blocks
|
||||
expr_to_fcode(Env, _Type, {block, _, Stmts}) ->
|
||||
stmts_to_fcode(Env, Stmts);
|
||||
|
||||
%% Binary operator
|
||||
expr_to_fcode(Env, Type, {app, _Ann, {Op, _}, [A, B]}) when is_atom(Op) ->
|
||||
FOp = binop_to_fcode(Op),
|
||||
{binop, Type, FOp, expr_to_fcode(Env, A), expr_to_fcode(Env, B)};
|
||||
|
||||
expr_to_fcode(_Env, Type, Expr) ->
|
||||
{todo, {Expr, '::', Type}}.
|
||||
{todo, {Expr, ':', Type}}.
|
||||
|
||||
binop_to_fcode(Op) when Op == '+'; Op == '-'; Op == '==' -> Op.
|
||||
|
||||
-spec pat_to_fcode(env(), aeso_syntax:pattern()) -> fpat().
|
||||
pat_to_fcode(Env, {typed, _, Pat, Type}) ->
|
||||
pat_to_fcode(Env, type_to_fcode(Env, Type), Pat);
|
||||
pat_to_fcode(Env, Pat) ->
|
||||
pat_to_fcode(Env, no_type, Pat).
|
||||
|
||||
-spec pat_to_fcode(env(), ftype() | no_type, aeso_syntax:pattern()) -> fpat().
|
||||
pat_to_fcode(_Env, _Type, {id, _, X}) -> {var, X};
|
||||
pat_to_fcode(_Env, Type, Pat) -> {todo, Pat, ':', Type}.
|
||||
|
||||
-spec stmts_to_fcode(env(), [aeso_syntax:stmt()]) -> fexpr().
|
||||
stmts_to_fcode(Env, [{letval, _, Pat, _, Expr} | Stmts]) ->
|
||||
{switch, expr_to_fcode(Env, Expr),
|
||||
[{pat_to_fcode(Env, Pat), stmts_to_fcode(Env, Stmts)}]};
|
||||
|
||||
stmts_to_fcode(Env, [Expr]) ->
|
||||
expr_to_fcode(Env, Expr).
|
||||
|
||||
%% -- Optimisations ----------------------------------------------------------
|
||||
|
||||
%% - Translate && and || to ifte
|
||||
%% - Deadcode elimination
|
||||
%% - Simplified case trees (FATE has special instructions for shallow matching)
|
||||
|
||||
%% -- Helper functions -------------------------------------------------------
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
-define(i(__X__), {immediate, __X__}).
|
||||
-define(a, {stack, 0}).
|
||||
|
||||
-record(env, { args = [], stack = [], tailpos = true }).
|
||||
-record(env, { args = [], stack = [], locals = [], tailpos = true }).
|
||||
|
||||
%% -- Debugging --------------------------------------------------------------
|
||||
|
||||
@ -69,15 +69,18 @@ init_env(Args) ->
|
||||
#env{ args = Args, stack = [], tailpos = true }.
|
||||
|
||||
push_env(Type, Env) ->
|
||||
Env#env{ stack = [{"_", Type} | Env#env.stack] }.
|
||||
Env#env{ stack = [Type | Env#env.stack] }.
|
||||
|
||||
bind_local(Name, Env = #env{ locals = Locals }) ->
|
||||
{length(Locals), Env#env{ locals = Locals ++ [Name] }}.
|
||||
|
||||
notail(Env) -> Env#env{ tailpos = false }.
|
||||
|
||||
lookup_var(#env{ args = Args, stack = S }, X) ->
|
||||
case {keyfind_index(X, 1, S), keyfind_index(X, 1, Args)} of
|
||||
{false, false} -> false;
|
||||
lookup_var(Env = #env{ args = Args, locals = Locals }, X) ->
|
||||
case {find_index(X, Locals), keyfind_index(X, 1, Args)} of
|
||||
{false, false} -> error({unbound_variable, X, Env});
|
||||
{false, Arg} -> {arg, Arg};
|
||||
{Local, _} -> {stack, Local}
|
||||
{Local, _} -> {var, Local}
|
||||
end.
|
||||
|
||||
%% -- The compiler --
|
||||
@ -86,23 +89,30 @@ to_scode(_Env, {integer, N}) ->
|
||||
[aeb_fate_code:push(?i(N))]; %% Doesn't exist (yet), translated by desugaring
|
||||
|
||||
to_scode(Env, {var, X}) ->
|
||||
case lookup_var(Env, X) of
|
||||
false -> error({unbound_variable, X, Env});
|
||||
{stack, N} -> [aeb_fate_code:dup(?i(N))];
|
||||
{arg, N} -> [aeb_fate_code:push({arg, N})]
|
||||
end;
|
||||
[aeb_fate_code:push(lookup_var(Env, X))];
|
||||
|
||||
to_scode(Env, {binop, Type, Op, A, B}) ->
|
||||
[ to_scode(notail(Env), B)
|
||||
, to_scode(push_env(Type, Env), A)
|
||||
, binop_to_scode(Op) ];
|
||||
[ to_scode(notail(Env), B),
|
||||
to_scode(push_env(Type, Env), A),
|
||||
binop_to_scode(Op) ];
|
||||
|
||||
to_scode(Env, {'if', Dec, Then, Else}) ->
|
||||
[ to_scode(notail(Env), Dec)
|
||||
, {ifte, to_scode(Env, Then), to_scode(Env, Else)} ];
|
||||
[ to_scode(notail(Env), Dec),
|
||||
{ifte, to_scode(Env, Then), to_scode(Env, Else)} ];
|
||||
|
||||
to_scode(Env, {switch, Expr, Alts}) ->
|
||||
[ to_scode(notail(Env), Expr),
|
||||
alts_to_scode(Env, Alts) ];
|
||||
|
||||
to_scode(_Env, Icode) -> ?TODO(Icode).
|
||||
|
||||
alts_to_scode(Env, [{{var, X}, Body}]) ->
|
||||
{I, Env1} = bind_local(X, Env),
|
||||
[ aeb_fate_code:store({var, I}, {stack, 0}),
|
||||
to_scode(Env1, Body) ];
|
||||
alts_to_scode(_Env, Alts) ->
|
||||
?TODO(Alts).
|
||||
|
||||
%% -- Operators --
|
||||
|
||||
binop_to_scode('+') -> add_a_a_a(); %% Optimization introduces other variants
|
||||
@ -283,3 +293,9 @@ keyfind_index(X, J, Xs) ->
|
||||
[] -> false
|
||||
end.
|
||||
|
||||
find_index(X, Xs) ->
|
||||
case lists:keyfind(X, 2, with_ixs(Xs)) of
|
||||
{I, _} -> I;
|
||||
false -> false
|
||||
end.
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user