sophia/src/aeso_smt.erl
2021-08-02 13:06:33 +02:00

95 lines
2.4 KiB
Erlang

-module(aeso_smt).
-compile([export_all]).
-type formula() :: {var, string()}
| {param, string()}
| {int, integer()}
| {list, [formula()]}
| {app, string(), [formula()]}
.
-define(TIMEOUT, 10000).
start_z3() ->
PortOpts = [exit_status, {line, 100000}],
Port = open_port({spawn, "z3 -in -t:" ++ integer_to_list(?TIMEOUT)}, PortOpts),
persistent_term:put(z3_connection, Port),
send_z3_success({app, "set-option", [{param, "print-success"}, {var, "true"}]}),
ok.
stop_z3() ->
port_close(persistent_term:get(z3_connection)),
persistent_term:erase(z3_connection).
get_z3() ->
Z3 = persistent_term:get(z3_connection, undefined),
if Z3 =:= undefined -> throw(z3_disconnected);
true -> ok
end,
Z3.
send_z3(Query) ->
Z3 = get_z3(),
QueryStr = pp_formula(Query),
%% io:format("~s\n", [QueryStr]),
port_command(Z3, binary:list_to_bin(QueryStr ++ "\n")).
check_sat() ->
send_z3({app, "check-sat", []}),
receive
{_, {data, {eol, Resp}}} ->
%% io:format("Z3: " ++ Resp ++ "\n"),
case string:trim(Resp) of
"sat" -> true;
"unsat" -> false;
X -> throw({smt_error, X})
end
after ?TIMEOUT * 2 -> {error, timeout}
end.
send_z3_success(Query) ->
send_z3(Query),
receive
{_, {data, {eol, Resp}}} ->
%% io:format("Z3: " ++ Resp ++ "\n"),
case string:trim(Resp) of
"success" -> success;
X -> error({smt_error, X})
end
after 5000 -> {error, timeout}
end.
assert(Form) ->
send_z3_success({app, "assert", [Form]}).
declare_const(Var, Type) ->
send_z3_success({app, "declare-const", [Var, Type]}).
push() ->
send_z3_success({app, "push", []}).
pop() ->
send_z3_success({app, "pop", []}).
scoped(Fun) ->
push(),
R = Fun(),
pop(),
R.
pp_formula({var, Name}) -> Name;
pp_formula({param, Name}) -> [$:, Name];
pp_formula({int, I}) -> integer_to_list(I);
pp_formula({app, Fun, Args}) ->
io_lib:format("(~s)", [pp_formulae([{var, Fun}|Args])]);
pp_formula({list, Xs}) ->
io_lib:format("(~s)", [pp_formulae(Xs)]).
pp_formulae([]) ->
"";
pp_formulae([H]) ->
pp_formula(H);
pp_formulae([H|T]) ->
io_lib:format("~s ~s", [pp_formula(H), pp_formulae(T)]).