diff --git a/src/aeso_ast_to_fcode.erl b/src/aeso_ast_to_fcode.erl index c7f355d..708406f 100644 --- a/src/aeso_ast_to_fcode.erl +++ b/src/aeso_ast_to_fcode.erl @@ -32,6 +32,7 @@ | {var, var_name()} | {tuple, [fexpr()]} | {proj, fexpr(), integer()} + | {set_proj, fexpr(), integer(), fexpr()} %% tuple, field, new_value | {binop, binop(), fexpr(), fexpr()} | {'let', var_name(), fexpr(), fexpr()} | {switch, fsplit()}. @@ -236,17 +237,23 @@ expr_to_fcode(Env, {record_t, FieldTypes}, {record, _Ann, Fields}) -> {tuple, lists:map(FVal, FieldTypes)}; expr_to_fcode(Env, {record_t, FieldTypes}, {record, _Ann, Rec, Fields}) -> - %% TODO: update once we have a SETELEMENT instruction X = fresh_name(), Proj = fun(I) -> {proj, {var, X}, I - 1} end, - Comp = fun(I, FT) -> - case field_value(FT, Fields) of - false -> Proj(I); - {set, E} -> expr_to_fcode(Env, E); - {upd, Z, E} -> {'let', Z, Proj(I), expr_to_fcode(Env, E)} - end end, - {'let', X, expr_to_fcode(Env, Rec), - {tuple, [Comp(I, FT) || {I, FT} <- indexed(FieldTypes)]}}; + Comp = fun({I, false}) -> Proj(I); + ({_, {set, E}}) -> expr_to_fcode(Env, E); + ({I, {upd, Z, E}}) -> {'let', Z, Proj(I), expr_to_fcode(Env, E)} + end, + Set = fun({_, false}, R) -> R; + ({I, {set, E}}, R) -> {set_proj, R, I - 1, expr_to_fcode(Env, E)}; + ({I, {upd, Z, E}}, R) -> {set_proj, R, I - 1, {'let', Z, Proj(I), expr_to_fcode(Env, E)}} + end, + Expand = length(Fields) == length(FieldTypes), + Updates = [ {I, field_value(FT, Fields)} || {I, FT} <- indexed(FieldTypes) ], + Body = case Expand of + true -> {tuple, lists:map(Comp, Updates)}; + false -> lists:foldr(Set, {var, X}, Updates) + end, + {'let', X, expr_to_fcode(Env, Rec), Body}; %% Lists expr_to_fcode(Env, _Type, {list, _, Es}) -> @@ -411,6 +418,7 @@ rename(Ren, Expr) -> {var, X} -> {var, rename_var(Ren, X)}; {tuple, Es} -> {tuple, [rename(Ren, E) || E <- Es]}; {proj, E, I} -> {proj, rename(Ren, E), I}; + {set_proj, R, I, E} -> {set_proj, rename(Ren, R), I, rename(Ren, E)}; {binop, Op, E1, E2} -> {binop, Op, rename(Ren, E1), rename(Ren, E2)}; {'let', X, E, Body} -> {Z, Ren1} = rename_binding(Ren, X), diff --git a/src/aeso_fcode_to_fate.erl b/src/aeso_fcode_to_fate.erl index b456aed..57b57d2 100644 --- a/src/aeso_fcode_to_fate.erl +++ b/src/aeso_fcode_to_fate.erl @@ -154,6 +154,11 @@ to_scode(Env, {proj, E, I}) -> [to_scode(Env, E), aeb_fate_code:element_op(?a, ?i(I), ?a)]; +to_scode(Env, {set_proj, R, I, E}) -> + [to_scode(Env, E), + to_scode(Env, R), + aeb_fate_code:setelement(?a, ?i(I), ?a, ?a)]; + to_scode(Env, {binop, Op, A, B}) -> [ to_scode(notail(Env), B), to_scode(Env, A), @@ -425,6 +430,7 @@ attributes(I) -> {'NOT', A, B} -> Pure(A, B); {'TUPLE', _} -> Pure(?a, []); {'ELEMENT', A, B, C} -> Pure(A, [B, C]); + {'SETELEMENT', A, B, C, D} -> Pure(A, [B, C, D]); {'MAP_EMPTY', A} -> Pure(A, []); {'MAP_LOOKUP', A, B, C} -> Pure(A, [B, C]); {'MAP_LOOKUPD', A, B, C, D} -> Pure(A, [B, C, D]); @@ -732,12 +738,12 @@ r_write_to_dead_var(_, _) -> false. op_view({Op, R, A, B}) when ?IsBinOp(Op) -> {Op, R, [A, B]}; -op_view({Op, R, A}) when ?IsUnOp(Op) -> +op_view({Op, R, A}) when ?IsUnOp(Op); Op == 'STORE' -> {Op, R, [A]}; -op_view({'STORE', R, A}) -> - {'STORE', R, [A]}; -op_view({'NIL', R}) -> - {'NIL', R, []}; +op_view({Op, R, A, B, C}) when Op == 'SETELEMENT' -> + {Op, R, [A, B, C]}; +op_view({Op, R}) when Op == 'NIL' -> + {Op, R, []}; op_view(_) -> false.