diff --git a/apps/ff_core/src/ff_pipeline.erl b/apps/ff_core/src/ff_pipeline.erl index 064b40606..f6972f224 100644 --- a/apps/ff_core/src/ff_pipeline.erl +++ b/apps/ff_core/src/ff_pipeline.erl @@ -7,16 +7,21 @@ -module(ff_pipeline). +-include_lib("syntax_tools/include/merl.hrl"). + -export([do/1]). -export([do/2]). -export([unwrap/1]). -export([unwrap/2]). +-export([wrap/1]). -export([expect/2]). -export([flip/1]). -export([valid/2]). -export([with/3]). +-export([parse_transform/2]). + %% -type thrown(_E) :: @@ -42,7 +47,7 @@ do(Fun) -> ok | result(T, {Tag, E}). do(Tag, Fun) -> - do(fun () -> unwrap(Tag, do(Fun)) end). + ff_pipeline:do(fun () -> unwrap(Tag, do(Fun)) end). -spec unwrap (ok) -> ok; @@ -56,6 +61,14 @@ unwrap({ok, V}) -> unwrap({error, E}) -> throw(E). +-spec wrap(any()) -> + ok | {ok, any()}. + +wrap(ok) -> + ok; +wrap(V) -> + {ok, V}. + -spec expect (_E, ok) -> ok; (_E, {ok, V}) -> V; @@ -117,3 +130,82 @@ with(Model, St, F) -> {error, Reason} -> {error, {Model, Reason}} end. + +%% Parse transform +% -import(ff_pipeline, [do/1, unwrap/1]). +% f() -> +% do(fun() -> +% R0 = 1, +% R1 = unwrap(do_smth(R0)), +% R2 = ff_pipeline:unwrap(do_smth2(R1)), +% R2 + 1 +% end). +% To +% -import(ff_pipeline, [unwrap/1]). +% f() -> +% try +% ff_pipeline:wrap(begin +% R0 = 1, +% R1 = unwrap(do_smth(R0)), +% R2 = ff_pipeline:unwrap(do_smth2(R1)), +% R2 + 1 +% end) +% catch +% Thrown -> {error, Thrown} +% end. + +-spec parse_transform(Forms, [compile:option()]) -> Forms when + Forms :: [erl_parse:abstract_form() | erl_parse:form_info()]. +parse_transform(Forms, _Options) -> + [erl_syntax:revert(erl_syntax_lib:map(fun transform_do/1, Form)) || Form <- Forms]. + +transform_do(Tree) -> + TreePos = erl_syntax:get_pos(Tree), + case Tree of + ?Q("do(_@Tag, fun() -> _@@Body end)") -> + build_do_statement(TreePos, Tag, Body); + ?Q("ff_pipeline:do(_@Tag, fun() -> _@@Body end)") -> + build_do_statement(TreePos, Tag, Body); + ?Q("do(fun() -> _@@Body end)") -> + build_do_statement(TreePos, Body); + ?Q("ff_pipeline:do(fun() -> _@@Body end)") -> + build_do_statement(TreePos, Body); + ?Q("-import(ff_pipeline, ['@_@Imports'/0]).") -> + build_import_statement(TreePos, Imports); + _ -> + Tree + end. + +build_do_statement(Pos, Body) -> + ThrownVar = build_var(<<"Thrown">>, Pos), + build_do_statement(Pos, ThrownVar, ThrownVar, Body). + +build_do_statement(Pos, Tag, Body) -> + ThrownVar = build_var(<<"Thrown">>, Pos), + Error = ?Q("{_@Tag, _@ThrownVar}"), + build_do_statement(Pos, ThrownVar, Error, Body). + +build_do_statement(_Pos, ThrownVar, Error, Body) -> + ?Q([ + "try ff_pipeline:wrap(begin _@@Body end)", + "catch _@ThrownVar -> {error, _@Error} end" + ]). + +build_import_statement(_Pos, Imports) -> + FilteredImports = lists:filter(fun is_import_not_replaced/1, Imports), + ?Q("-import(ff_pipeline, ['@_@FilteredImports'/0])."). + +is_import_not_replaced(ImportItem) -> + case ?Q("-export(['@_ImportItem'/0]).") of + ?Q("-export([do/1]).") -> + false; + ?Q("-export([do/2]).") -> + false; + _ -> + true + end. + +build_var(Name, Line) -> + LineStr = erlang:integer_to_binary(Line), + VarName = erlang:binary_to_atom(<<"$Pipeline", Name/binary, "-", LineStr/binary>>, latin1), + merl:var(VarName). diff --git a/apps/ff_transfer/src/ff_deposit.erl b/apps/ff_transfer/src/ff_deposit.erl index 881493890..b596359b0 100644 --- a/apps/ff_transfer/src/ff_deposit.erl +++ b/apps/ff_transfer/src/ff_deposit.erl @@ -55,6 +55,7 @@ %% Pipeline +-compile({parse_transform, ff_pipeline}). -import(ff_pipeline, [do/1, unwrap/1, unwrap/2, valid/2]). %% Internal types diff --git a/apps/ff_transfer/src/ff_instrument.erl b/apps/ff_transfer/src/ff_instrument.erl index b739d7e41..d40b1e2f2 100644 --- a/apps/ff_transfer/src/ff_instrument.erl +++ b/apps/ff_transfer/src/ff_instrument.erl @@ -59,6 +59,7 @@ %% Pipeline +-compile({parse_transform, ff_pipeline}). -import(ff_pipeline, [do/1, unwrap/1, unwrap/2]). %% Accessors diff --git a/apps/ff_transfer/src/ff_instrument_machine.erl b/apps/ff_transfer/src/ff_instrument_machine.erl index 555216e19..1c900cdfc 100644 --- a/apps/ff_transfer/src/ff_instrument_machine.erl +++ b/apps/ff_transfer/src/ff_instrument_machine.erl @@ -38,6 +38,7 @@ %% Pipeline +-compile({parse_transform, ff_pipeline}). -import(ff_pipeline, [do/1, unwrap/1]). %% diff --git a/apps/ff_transfer/src/ff_transfer.erl b/apps/ff_transfer/src/ff_transfer.erl index 35a63163a..544f3002d 100644 --- a/apps/ff_transfer/src/ff_transfer.erl +++ b/apps/ff_transfer/src/ff_transfer.erl @@ -88,6 +88,7 @@ %% Pipeline +-compile({parse_transform, ff_pipeline}). -import(ff_pipeline, [do/1, unwrap/1, with/3]). %% Internal types diff --git a/apps/ff_transfer/src/ff_transfer_machine.erl b/apps/ff_transfer/src/ff_transfer_machine.erl index 399319876..1acfb8d36 100644 --- a/apps/ff_transfer/src/ff_transfer_machine.erl +++ b/apps/ff_transfer/src/ff_transfer_machine.erl @@ -74,6 +74,7 @@ %% Pipeline +-compile({parse_transform, ff_pipeline}). -import(ff_pipeline, [do/1, unwrap/1]). %% Internal types diff --git a/apps/ff_transfer/src/ff_withdrawal.erl b/apps/ff_transfer/src/ff_withdrawal.erl index 3e6a7db3c..5a417dc85 100644 --- a/apps/ff_transfer/src/ff_withdrawal.erl +++ b/apps/ff_transfer/src/ff_withdrawal.erl @@ -70,6 +70,7 @@ %% Pipeline +-compile({parse_transform, ff_pipeline}). -import(ff_pipeline, [do/1, unwrap/1, unwrap/2, valid/2]). %% Internal types diff --git a/apps/ff_transfer/src/ff_withdrawal_session.erl b/apps/ff_transfer/src/ff_withdrawal_session.erl index 205cd54a9..0c3ba4ab1 100644 --- a/apps/ff_transfer/src/ff_withdrawal_session.erl +++ b/apps/ff_transfer/src/ff_withdrawal_session.erl @@ -78,6 +78,7 @@ %% Pipeline +-compile({parse_transform, ff_pipeline}). -import(ff_pipeline, [unwrap/1]). %% diff --git a/apps/ff_transfer/src/ff_withdrawal_session_machine.erl b/apps/ff_transfer/src/ff_withdrawal_session_machine.erl index 1be84cd53..03ab05cdf 100644 --- a/apps/ff_transfer/src/ff_withdrawal_session_machine.erl +++ b/apps/ff_transfer/src/ff_withdrawal_session_machine.erl @@ -53,6 +53,7 @@ %% Pipeline +-compile({parse_transform, ff_pipeline}). -import(ff_pipeline, [do/1, unwrap/1]). %% diff --git a/apps/fistful/src/ff_account.erl b/apps/fistful/src/ff_account.erl index 76083e208..5c7d8b9e1 100644 --- a/apps/fistful/src/ff_account.erl +++ b/apps/fistful/src/ff_account.erl @@ -45,6 +45,7 @@ %% Pipeline +-compile({parse_transform, ff_pipeline}). -import(ff_pipeline, [do/1, unwrap/1, unwrap/2]). %% Internal types diff --git a/apps/fistful/src/ff_cash_flow.erl b/apps/fistful/src/ff_cash_flow.erl index 70f965d73..30879f9d0 100644 --- a/apps/fistful/src/ff_cash_flow.erl +++ b/apps/fistful/src/ff_cash_flow.erl @@ -83,6 +83,7 @@ %% Pipeline +-compile({parse_transform, ff_pipeline}). -import(ff_pipeline, [do/1, unwrap/1, unwrap/2]). %% Internal types diff --git a/apps/fistful/src/ff_currency.erl b/apps/fistful/src/ff_currency.erl index b18d5ef68..9bc2e7f57 100644 --- a/apps/fistful/src/ff_currency.erl +++ b/apps/fistful/src/ff_currency.erl @@ -28,6 +28,7 @@ %% Pipeline +-compile({parse_transform, ff_pipeline}). -import(ff_pipeline, [do/1, unwrap/1]). %% Accessors diff --git a/apps/fistful/src/ff_identity.erl b/apps/fistful/src/ff_identity.erl index 84f05a2b5..601b93789 100644 --- a/apps/fistful/src/ff_identity.erl +++ b/apps/fistful/src/ff_identity.erl @@ -95,6 +95,7 @@ %% Pipeline +-compile({parse_transform, ff_pipeline}). -import(ff_pipeline, [do/1, unwrap/1, unwrap/2, expect/2, flip/1, valid/2]). %% Accessors diff --git a/apps/fistful/src/ff_identity_challenge.erl b/apps/fistful/src/ff_identity_challenge.erl index 2c5bd4646..0fa174a9a 100644 --- a/apps/fistful/src/ff_identity_challenge.erl +++ b/apps/fistful/src/ff_identity_challenge.erl @@ -104,6 +104,7 @@ %% Pipeline +-compile({parse_transform, ff_pipeline}). -import(ff_pipeline, [do/1, unwrap/1, valid/2]). %% diff --git a/apps/fistful/src/ff_identity_machine.erl b/apps/fistful/src/ff_identity_machine.erl index c96287efc..b67b4472a 100644 --- a/apps/fistful/src/ff_identity_machine.erl +++ b/apps/fistful/src/ff_identity_machine.erl @@ -56,6 +56,7 @@ %% Pipeline +-compile({parse_transform, ff_pipeline}). -import(ff_pipeline, [do/1, do/2, unwrap/1]). -define(NS, 'ff/identity'). diff --git a/apps/fistful/src/ff_machine.erl b/apps/fistful/src/ff_machine.erl index 8fca031a4..fb2204568 100644 --- a/apps/fistful/src/ff_machine.erl +++ b/apps/fistful/src/ff_machine.erl @@ -74,6 +74,7 @@ %% Pipeline helpers +-compile({parse_transform, ff_pipeline}). -import(ff_pipeline, [do/1, unwrap/1]). %% Internal types diff --git a/apps/fistful/src/ff_party.erl b/apps/fistful/src/ff_party.erl index 4246a04d1..273118168 100644 --- a/apps/fistful/src/ff_party.erl +++ b/apps/fistful/src/ff_party.erl @@ -87,6 +87,7 @@ %% Pipeline +-compile({parse_transform, ff_pipeline}). -import(ff_pipeline, [do/1, unwrap/1, unwrap/2]). %% diff --git a/apps/fistful/src/ff_payment_institution.erl b/apps/fistful/src/ff_payment_institution.erl index 544d78dd1..d2180732f 100644 --- a/apps/fistful/src/ff_payment_institution.erl +++ b/apps/fistful/src/ff_payment_institution.erl @@ -33,6 +33,7 @@ %% Pipeline +-compile({parse_transform, ff_pipeline}). -import(ff_pipeline, [do/1, unwrap/1]). %% diff --git a/apps/fistful/src/ff_payouts_provider.erl b/apps/fistful/src/ff_payouts_provider.erl index 59f5122be..16c9b58de 100644 --- a/apps/fistful/src/ff_payouts_provider.erl +++ b/apps/fistful/src/ff_payouts_provider.erl @@ -31,6 +31,7 @@ %% Pipeline +-compile({parse_transform, ff_pipeline}). -import(ff_pipeline, [do/1, unwrap/1]). %% diff --git a/apps/fistful/src/ff_postings_transfer.erl b/apps/fistful/src/ff_postings_transfer.erl index 557b09c6c..b7c72b6c3 100644 --- a/apps/fistful/src/ff_postings_transfer.erl +++ b/apps/fistful/src/ff_postings_transfer.erl @@ -52,6 +52,7 @@ %% Pipeline +-compile({parse_transform, ff_pipeline}). -import(ff_pipeline, [do/1, unwrap/1, unwrap/2, valid/2]). %% Internal types diff --git a/apps/fistful/src/ff_provider.erl b/apps/fistful/src/ff_provider.erl index 1d1bc322a..4c0641475 100644 --- a/apps/fistful/src/ff_provider.erl +++ b/apps/fistful/src/ff_provider.erl @@ -47,6 +47,7 @@ %% Pipeline +-compile({parse_transform, ff_pipeline}). -import(ff_pipeline, [do/1, unwrap/1]). %% diff --git a/apps/fistful/src/ff_wallet.erl b/apps/fistful/src/ff_wallet.erl index 5fd2c7180..a57845140 100644 --- a/apps/fistful/src/ff_wallet.erl +++ b/apps/fistful/src/ff_wallet.erl @@ -56,6 +56,7 @@ %% Pipeline +-compile({parse_transform, ff_pipeline}). -import(ff_pipeline, [do/1, unwrap/1, unwrap/2]). %% Accessors diff --git a/apps/fistful/src/ff_wallet_machine.erl b/apps/fistful/src/ff_wallet_machine.erl index 90a738b94..8bf648e68 100644 --- a/apps/fistful/src/ff_wallet_machine.erl +++ b/apps/fistful/src/ff_wallet_machine.erl @@ -37,6 +37,7 @@ %% Pipeline +-compile({parse_transform, ff_pipeline}). -import(ff_pipeline, [do/1, unwrap/1]). -define(NS, 'ff/wallet_v2'). diff --git a/apps/fistful/test/ff_identity_SUITE.erl b/apps/fistful/test/ff_identity_SUITE.erl index a0947b111..055679c38 100644 --- a/apps/fistful/test/ff_identity_SUITE.erl +++ b/apps/fistful/test/ff_identity_SUITE.erl @@ -14,7 +14,6 @@ %% -import(ct_helper, [cfg/2]). --import(ff_pipeline, [unwrap/1]). -type config() :: ct_helper:config(). -type test_case_name() :: ct_helper:test_case_name(). @@ -153,7 +152,8 @@ create_ok(C) -> }, ff_ctx:new() ), - I1 = ff_identity_machine:identity(unwrap(ff_identity_machine:get(ID))), + {ok, IdentityMachine} = ff_identity_machine:get(ID), + I1 = ff_identity_machine:identity(IdentityMachine), {ok, accessible} = ff_identity:is_accessible(I1), Party = ff_identity:party(I1), Party = ff_identity:party(I1). diff --git a/apps/fistful/test/ff_wallet_SUITE.erl b/apps/fistful/test/ff_wallet_SUITE.erl index 57d410193..7a087a1ed 100644 --- a/apps/fistful/test/ff_wallet_SUITE.erl +++ b/apps/fistful/test/ff_wallet_SUITE.erl @@ -19,7 +19,6 @@ %% -import(ct_helper, [cfg/2]). --import(ff_pipeline, [unwrap/1]). -type config() :: ct_helper:config(). -type test_case_name() :: ct_helper:test_case_name(). @@ -160,7 +159,8 @@ create_wallet_ok(C) -> }, ff_ctx:new() ), - Wallet = ff_wallet_machine:wallet(unwrap(ff_wallet_machine:get(ID))), + {ok, WalletMachine} = ff_wallet_machine:get(ID), + Wallet = ff_wallet_machine:wallet(WalletMachine), {ok, accessible} = ff_wallet:is_accessible(Wallet), Account = ff_account:accounter_account_id(ff_wallet:account(Wallet)), {ok, {Amount, <<"RUB">>}} = ff_transaction:balance(Account), diff --git a/apps/wapi/src/wapi_wallet_ff_backend.erl b/apps/wapi/src/wapi_wallet_ff_backend.erl index 95741e5e6..62bbfe972 100644 --- a/apps/wapi/src/wapi_wallet_ff_backend.erl +++ b/apps/wapi/src/wapi_wallet_ff_backend.erl @@ -70,6 +70,11 @@ -dialyzer([{nowarn_function, [to_swag/2]}]). +%% Pipeline + +-compile({parse_transform, ff_pipeline}). +-import(ff_pipeline, [do/1, unwrap/1, unwrap/2]). + %% API %% Providers @@ -836,15 +841,6 @@ get_email(AuthContext) -> not_implemented() -> wapi_handler_utils:throw_not_implemented(). -do(Fun) -> - ff_pipeline:do(Fun). - -unwrap(Res) -> - ff_pipeline:unwrap(Res). - -unwrap(Tag, Res) -> - ff_pipeline:unwrap(Tag, Res). - valid(Val1, Val2) -> ff_pipeline:valid(Val1, Val2). diff --git a/rebar.config b/rebar.config index 428a93a91..bc607a9f8 100644 --- a/rebar.config +++ b/rebar.config @@ -99,7 +99,8 @@ race_conditions, unknown ]}, - {plt_apps, all_deps} + {plt_apps, all_deps}, + {plt_extra_apps, [syntax_tools, compiler]} %% for ff_pipeline parse transform ]}. {profiles, [