224 lines
5.5 KiB
Prolog
224 lines
5.5 KiB
Prolog
:- module(meld_compiler,
|
|
[
|
|
mcompile/1,
|
|
input_graph/1,
|
|
run/1
|
|
]).
|
|
|
|
:- use_module(meldi,
|
|
[
|
|
push/1,
|
|
first/2,
|
|
min/3,
|
|
max/3
|
|
]).
|
|
|
|
:- use_module(library(meld)).
|
|
|
|
:- use_module(meldtd,
|
|
[
|
|
meld_top_down_compile/2,
|
|
meld_top_down_aggregate/3
|
|
]).
|
|
|
|
:- use_module(library(terms), [
|
|
variable_in_term/2
|
|
]).
|
|
|
|
mcompile(Program) :-
|
|
open(Program, read, P),
|
|
init_mcompile(Program),
|
|
repeat,
|
|
read_term(P, Term, [variable_names(Vars), module(meld_compiler)]),
|
|
(
|
|
Term == end_of_file
|
|
->
|
|
!,
|
|
close(P)
|
|
;
|
|
mcompile(Term, Program, Vars),
|
|
fail
|
|
).
|
|
|
|
init_mcompile(Program) :-
|
|
retractall(type(_, _, Program, _)).
|
|
|
|
mcompile(type(T), Program, Vars) :-
|
|
ground_term(T, Vars),
|
|
type_declaration(T, Program), !.
|
|
mcompile((Head :- Body), _, _Vars) :-
|
|
rule(Head, Body).
|
|
|
|
type_declaration(extensional(T), Program) :- !,
|
|
functor(T, Na, Arity),
|
|
functor(NT, Na, Arity),
|
|
assert(meld_topdown:extensional(NT, Na, Arity)),
|
|
type_declaration(T, Program).
|
|
type_declaration(logical_neighbor(T), Program) :- !,
|
|
type_declaration(T, Program).
|
|
type_declaration(T, _) :-
|
|
functor(T, N, A),
|
|
dynamic(meld_program:N/A),
|
|
fail.
|
|
type_declaration(T, Program) :-
|
|
T =.. [P|Args],
|
|
check_aggregate(Args, 1, NewArgs, Aggregation, Arg),
|
|
!,
|
|
NT =.. [P|NewArgs],
|
|
meld_top_down_aggregate(T, Aggregation, Arg),
|
|
assert_type(NT, Program, aggregation(Aggregation, Arg)).
|
|
type_declaration(T, Program) :-
|
|
meld_top_down_aggregate(T, horn, _),
|
|
assert_type(T, Program, horn).
|
|
|
|
assert_type(NT, Program, Agg) :-
|
|
functor(NT, Na, Ar),
|
|
functor(Spec, Na, Ar),
|
|
assert(type(Spec, NT, Program, Agg)).
|
|
|
|
check_aggregate([first(Type)|Args], I, [Type|Args], first, I) :- !.
|
|
check_aggregate([max(Type)|Args], I, [Type|Args], max, I) :- !.
|
|
check_aggregate([min(Type)|Args], I, [Type|Args], min, I) :- !.
|
|
check_aggregate([Type|Args], I, [Type|NewArgs], Agg, Arg) :-
|
|
atom(Type),
|
|
I1 is I+1,
|
|
check_aggregate(Args, I1, NewArgs, Agg, Arg).
|
|
|
|
ground_term(_, []).
|
|
|
|
rule(Head, Body) :-
|
|
bodytolist(Body, L, []),
|
|
compile_goals(L, [], Head),
|
|
meld_top_down_compile(Head, Body).
|
|
|
|
compile_goals([], _, _).
|
|
compile_goals([Goal|Goals], Gs, Head) :-
|
|
compile_goal(Goal, Goals, Gs, Head),
|
|
compile_goals(Goals, [Goal|Gs], Head).
|
|
|
|
compile_goal((forall G then Do), Goals, Gs, Head) :- !,
|
|
% make sure quantified variables are not seen outside
|
|
quantified_vars(G,Gs+Goals,NG),
|
|
%
|
|
% just collect the body into a number of goals
|
|
%
|
|
collect_body(Gs, [(forall G then Do)|Goals], BLF, BL1),
|
|
% make a backup copy for deletion
|
|
copy_term(h(Head,BLF,BL1,NG), h(Head,DelBLF,DelBL1,DelNG)),
|
|
% add the operation, usually push
|
|
extra_head(Head, BL1, []),
|
|
% add the delete operation
|
|
extra_delete(Head, DelBL1, []),
|
|
% create the body as a conjunction
|
|
listtobody(BLF, Body),
|
|
listtobody(DelBLF, DelBody),
|
|
% done
|
|
assert(meld_program:(run(NG) :- Body)),
|
|
assert(meld_program:(run(delete(DelNG)) :- DelBody)).
|
|
compile_goal(Goal, Goals, Gs, Head) :-
|
|
collect_body(Gs, Goals, BLF, BL1),
|
|
copy_term(h(Head,BLF,BL1,Goal), h(Head,DelBLF,DelBL1,DelGoal)),
|
|
extra_head(Head, BL1, []),
|
|
extra_delete(Head, DelBL1, []),
|
|
listtobody(BLF, Body),
|
|
listtobody(DelBLF, DelBody),
|
|
assert(meld_program:(run(Goal) :- Body)),
|
|
assert(meld_program:(run(deleted(DelGoal)) :- DelBody)).
|
|
|
|
% quantified variables should not leave the scope of the forall.
|
|
quantified_vars(G,Extern,NG) :-
|
|
term_variables(G, TVs),
|
|
copy_term(G+TVs,NG+NTVs),
|
|
bind_external(TVs, NTVs, Extern).
|
|
|
|
bind_external([], [], _).
|
|
bind_external(V.TVs, NV.NTVs, Extern) :-
|
|
variable_in_term(Extern, V), !,
|
|
V = NV,
|
|
bind_external(TVs, NTVs, Extern).
|
|
bind_external(_.TVs, _.NTVs, Extern) :-
|
|
bind_external(TVs, NTVs, Extern).
|
|
|
|
% a very simple version
|
|
%
|
|
collect_body([], []) --> [].
|
|
collect_body([G|Gs], MGs) -->
|
|
process_goal(G),
|
|
collect_body(Gs, MGs).
|
|
collect_body([], [G|Gs]) -->
|
|
process_goal(G),
|
|
collect_body([], Gs).
|
|
|
|
process_goal((forall Goal then Conj)) --> !,
|
|
[(Goal, \+ Conj -> fail ; true)].
|
|
process_goal( G ) -->
|
|
[G].
|
|
|
|
|
|
|
|
extra_head(Head) -->
|
|
{ type(Head, _, _, horn) },
|
|
[push(Head)].
|
|
extra_head(Head) -->
|
|
{ type(Head, _, _, aggregation(first, Arg)), freshen(Head, Arg, VHead) },
|
|
[ meld_interpreter:first(VHead, Head)].
|
|
extra_head(Head) -->
|
|
{ type(Head, _, _, aggregation(max, Arg)), freshen(Head, Arg, VHead) },
|
|
[ meld_interpreter:max(VHead, Arg, Head)].
|
|
extra_head(Head) -->
|
|
{ type(Head, _, _, aggregation(min, Arg)), freshen(Head, Arg, VHead) },
|
|
[ meld_interpreter:min(VHead, Arg, Head)].
|
|
|
|
extra_delete(Head) -->
|
|
{ type(Head, _, _, horn) },
|
|
[meld_interpreter:deleted(Head)].
|
|
extra_delete(Head) -->
|
|
{ type(Head, _, _, aggregation(first, Arg)), freshen(Head, Arg, VHead) },
|
|
[ meld_interpreter:delete_from_first(VHead, Head)].
|
|
extra_delete(Head) -->
|
|
{ type(Head, _, _, aggregation(max, Arg)), freshen(Head, Arg, VHead) },
|
|
[ meld_interpreter:delete_from_max(VHead, Arg, Head)].
|
|
extra_delete(Head) -->
|
|
{ type(Head, _, _, aggregation(min, Arg)), freshen(Head, Arg, VHead) },
|
|
[ meld_interpreter:delete_from_min(VHead, Arg, Head)].
|
|
|
|
freshen(Head, Arg, VHead) :-
|
|
Head =.. [N|Args],
|
|
freshen_arg(Arg, Args, VArgs),
|
|
VHead =.. [N|VArgs].
|
|
|
|
freshen_arg(1, [_|Args], [_|Args]) :- !.
|
|
freshen_arg(N, A.Args, A.VArgs) :-
|
|
N1 is N-1,
|
|
freshen_arg(N1, Args, VArgs).
|
|
|
|
input_graph(Program) :-
|
|
open(Program, read, P),
|
|
repeat,
|
|
read_term(P, Term, [variable_names(_Vars), module(meld_compiler)]),
|
|
(
|
|
Term == end_of_file
|
|
->
|
|
!,
|
|
close(P)
|
|
;
|
|
add_graph_fact(Term),
|
|
fail
|
|
).
|
|
|
|
add_graph_fact(Term) :-
|
|
push(Term).
|
|
|
|
bodytolist((G1,G2)) -->
|
|
!,
|
|
bodytolist(G1),
|
|
bodytolist(G2).
|
|
bodytolist(G) -->
|
|
[G].
|
|
|
|
listtobody([G], G) :- !.
|
|
listtobody([G|GL], (G,Gs)) :-
|
|
listtobody(GL, Gs).
|
|
|
|
|