Current section
Files
Jump to
Current section
Files
src/datalog_q.erl
%%
%% Copyright 2014 - 2018 Dmitry Kolesnikov, All Rights Reserved
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% @doc
%% the library parser uses leex / yeec to convert query (datalog syntax) to
%% abstract syntax tree (set of horn classes). The abstract syntax is not optimal
%% for evaluation. It has to be adapted to `-type datalog:q()`.
-module(datalog_q).
-export([
native/1
]).
%%
%%
-spec native([{_, _, _}]) -> datalog:q().
native(Horns) ->
lists:foldr(
fun({Horn, Head, Body}, Datalog) ->
% datalog complaint body consists of predicates and built-in filters.
% predicate is converted to `-type pattern()`. The filters are interleaved
% into pattern so that sigma function can construct stream of ground facts.
{Pattern, Filter} = lists:partition(fun(X) -> size(X) =:= 2 end, Body),
[{Horn, [Head | ast_to_body(Pattern, Filter)]} | Datalog];
({Horn, Head}, Datalog) ->
[{'?', #{'@' => Horn, '_' => Head}} | Datalog]
end,
[],
Horns
).
%%
%%
ast_to_body(Pattern, Filter) ->
[ast_to_pattern(X, Filter) || X <- Pattern].
%%
%%
ast_to_pattern({Id, Pattern}, Filter) ->
%% check each pattern variable for BIF constrains
lists:foldl(
fun(X, Acc) -> ast_to_filter(X, Filter, Acc) end,
#{'@' => Id, '_' => Pattern},
Pattern
).
%%
%% interleave pattern variable with filters
ast_to_filter(Variable, Filter, Pattern) ->
case
lists:filter(
fun(X) ->
erlang:element(2, X) =:= Variable
end,
Filter
)
of
%% no BIF constrain
[] ->
Pattern;
%% BIF constrain variable
Fs ->
case lists:keyfind('=:=', 1, Fs) of
false ->
maps:put(Variable, [{P, F} || {P, _, F} <- Fs], Pattern);
{'=:=', _, F} ->
maps:put(Variable, F, Pattern)
end
end.