Permalink
Browse files

figured out how to abstract erl_eval funs

  • Loading branch information...
1 parent 6926bb0 commit 9116c6e38558abd2bfa1a9c9fd50d07811a34513 @uwiger committed Jan 28, 2012
Showing with 66 additions and 10 deletions.
  1. +8 −8 examples/ct_expand_test.erl
  2. +58 −2 src/ct_expand.erl
View
16 examples/ct_expand_test.erl
@@ -16,16 +16,14 @@ f() ->
g() ->
ct_expand:term(zip([1,2], [a,b])).
-%% this doesn't work: a function in the expanded expr returns a fun, which is then passed
-%% to another function. This is because erl_eval returns results as concrete terms, which
-%% must then be abstracted in order to be passed as input arguments to am interpreted
-%% function. This works most of the time, but erl_parse:abstract/1 crashes on funs.
-%%
-%% h() ->
-%% ct_expand:term(wrap(my_fun())).
+h() ->
+ ct_expand:term(wrap(my_fun())).
+
+i() ->
+ ct_expand:term(wrap(my_fun2())).
zip([H1|T1], [H2|T2]) ->
- F = fun wrap/1,
+ F = my_fun2(),
[{F(H1),F(H2)} | zip(T1, T2)];
zip([], []) ->
[].
@@ -36,3 +34,5 @@ wrap(X) ->
my_fun() ->
fun() -> foo end.
+my_fun2() ->
+ fun wrap/1.
View
60 src/ct_expand.erl
@@ -98,7 +98,7 @@ xform_fun(application, Form, _Ctxt, Acc, Forms, Trace) ->
RevArgs = parse_trans:revert(Args),
case erl_eval:exprs(RevArgs, [], {eval, LFH}) of
{value, Value,[]} ->
- {erl_syntax:abstract(Value), Acc};
+ {abstract(Value), Acc};
Other ->
parse_trans:error(cannot_evaluate,?LINE,
[{expr, RevArgs},
@@ -126,7 +126,7 @@ eval_lfun({function,L,F,_,Clauses}, Args, Bs, Forms, Trace) ->
fun(A, Bs_) ->
{value,AV,Bs1_} =
erl_eval:expr(A, Bs_, lfh(Forms, Trace)),
- {erl_parse:abstract(AV), Bs1_}
+ {abstract(AV), Bs1_}
end, Bs, Args),
Expr = {call, L, {'fun', L, {clauses, lfun_rewrite(Clauses, Forms)}}, ArgsV},
call_trace(Trace =/= [], L, F, ArgsV),
@@ -180,3 +180,59 @@ lfun_rewrite(Exprs, Forms) ->
(_) ->
continue
end, Exprs).
+
+
+%% abstract/1 - modified from erl_eval:abstract/1:
+-type abstract_expr() :: term().
+-spec abstract(Data) -> AbsTerm when
+ Data :: term(),
+ AbsTerm :: abstract_expr().
+abstract(T) when is_function(T) ->
+ case erlang:fun_info(T, module) of
+ {module, erl_eval} ->
+ case erl_eval:fun_data(T) of
+ {fun_data, _Imports, Clauses} ->
+ {'fun', 0, {clauses, Clauses}};
+ false ->
+ erlang:error(function_clause) % mimicking erl_parse:abstract(T)
+ end;
+ _ ->
+ erlang:error(function_clause)
+ end;
+abstract(T) when is_integer(T) -> {integer,0,T};
+abstract(T) when is_float(T) -> {float,0,T};
+abstract(T) when is_atom(T) -> {atom,0,T};
+abstract([]) -> {nil,0};
+abstract(B) when is_bitstring(B) ->
+ {bin, 0, [abstract_byte(Byte, 0) || Byte <- bitstring_to_list(B)]};
+abstract([C|T]) when is_integer(C), 0 =< C, C < 256 ->
+ abstract_string(T, [C]);
+abstract([H|T]) ->
+ {cons,0,abstract(H),abstract(T)};
+abstract(Tuple) when is_tuple(Tuple) ->
+ {tuple,0,abstract_list(tuple_to_list(Tuple))}.
+
+abstract_string([C|T], String) when is_integer(C), 0 =< C, C < 256 ->
+ abstract_string(T, [C|String]);
+abstract_string([], String) ->
+ {string, 0, lists:reverse(String)};
+abstract_string(T, String) ->
+ not_string(String, abstract(T)).
+
+not_string([C|T], Result) ->
+ not_string(T, {cons, 0, {integer, 0, C}, Result});
+not_string([], Result) ->
+ Result.
+
+abstract_list([H|T]) ->
+ [abstract(H)|abstract_list(T)];
+abstract_list([]) ->
+ [].
+
+abstract_byte(Byte, Line) when is_integer(Byte) ->
+ {bin_element, Line, {integer, Line, Byte}, default, default};
+abstract_byte(Bits, Line) ->
+ Sz = bit_size(Bits),
+ <<Val:Sz>> = Bits,
+ {bin_element, Line, {integer, Line, Val}, {integer, Line, Sz}, default}.
+

0 comments on commit 9116c6e

Please sign in to comment.