% NTI 6.

%Implication
:- op(800,xfy, =>).
%Conjunction
:- op(500,xfy, ^).
%Disjunction
:- op(600,xfy, v).
:- op(400, fx, ~).

:- dynamic(referent/1).
:- dynamic(discourse/1).

go :-
	retractall(discourse(_)),
	retractall(referent(_)),
	ex([mary,kicked,john]),
	ex([he,didnt,like,that]),
	ex([he,kicked,the,ball,to,her]).

ex(S) :-
	write('Sentence: '), write(S), nl,
	s(Sem, S,[]),
	asserta(discourse(Sem)), !,
	write('Discourse: '), nl,
	%forall(discourse(X), eventprint(X)), nl.
	%only print newest addition to the discourse
	eventprint(Sem), !.

s(isa(E, V) ^ subject(E, S) ^ VPconjuncts ^ Tense) -->
	np(S, [N, _G, subject, RID1:RT1]), vp(V, VPlist, [N, T, RID2:RT2]),
	{ newid(ID),
	atom_concat(e, ID, E), atom_concat(E, '_i', I),
	atom_concat(I, b, B), atom_concat(I, '_end', End),
	reverse(VPlist, RVPlist),
	parsevp(RVPlist, E, _, VPconjuncts),
	%select either a subject or object occurrence of a "that"-referrer:
	(nonvar(RT2) ->
		RT=RT2, RID=RID2
	;	RT=RT1,	RID=RID1),
	(nonvar(RT) ->	atom_concat(RT, '_b', RB) ; true),
	(T = present ->
		(var(RT) ->
			Tense = intervalOf(E, I)  ^ memborOf(now, I) ^ beginOf(I, B)
		; 	Tense = intervalOf(E, I)  ^ memberOf(now, I) ^ beginOf(I, B) ^ beginOf(RID, RT) ^ before(RT, I))
		; (var(RT) ->
			Tense = intervalOf(E, I) ^ endOf(I, End) ^ before(End, now) ^ beginOf(I, B) 
			; Tense = intervalOf(E, I) ^ endOf(I, End) ^ before(End, now) ^ beginOf(RID, RT) ^ beginOf(I, B) ^ ~before(B, RB) 
		))
	
	}.

% the ball --> ce(ball)
np(NP, [N, G, _F, _RT]) --> det(DET), noun(NOUN, [N, G]),
	{ NP =.. [DET, NOUN], asserta(referent(NP, [N,G,_])) ; retract(referent(NP, [N,G,_])) }.
np(PN, [singular, G, _F, _RT]) --> pn(PN, G).
np(PN, Attr) --> pronoun(PN, Attr).
np(PN, Attr) --> eventpronoun(PN, Attr).

vp(VP, [], Attr) --> vp1(VP, Attr).
vp(VP, [Obj], Attr) --> vp1(VP, Obj, Attr). 
vp(VP, PP, Attr) --> vp1(VP, Attr), pp(PP).
vp(VP, ObjPP, Attr) --> vp1(VP, Obj, Attr), pp(PP), { append([Obj], PP, ObjPP) }.

vp1(TV, Attr) --> iv(TV, Attr).
vp1(TV, object(NP), [N, T, RT]) --> tv(TV, [N, T]), np(NP, [_N, _G, object, RT]).


%in de tafel --> in(ce(tafel))
pp(PP) --> pp1(PP).
pp(PP) --> pp1(PP1), pp(PP2), { append(PP1, PP2, PP) }.
pp1([PP]) --> pre(PRE), np(NP, _), { PP =.. [PRE, NP] }.

%lexicon
det(ce) --> [the].
noun(ball, [singular, neuter]) --> [ball].

pronoun(X, [singular, male, subject, _]) --> [he], { referent(X, [singular, male, _]) }.
pronoun(X, [singular, male, object, _]) --> [him], { referent(X, [singular, male, _]) }.
pronoun(X, [singular, female, subject, _]) --> [she], { referent(X, [singular, female, _]) }.
pronoun(X, [singular, female, object, _]) --> [her], { referent(X, [singular, female, _]) }.

eventpronoun(ID, [singular, neuter, _, RID:RT]) --> [that], 
		{ discourse(isa(ID,_)^Rest),
		last(Rest, beginOf(RID, RT)) }.

pn(Name, male) --> [john], 
	{ Name = john, asserta(referent(Name, [singular, male, _])) ; retract(referent(Name, _)) }.
pn(Name, female) --> [mary], 
	{ Name = mary, asserta(referent(Name, [singular, female, _])) ; retract(referent(Name, _)) }.

tv(like, [singular, present]) --> [likes].
tv(like, [plural, present]) --> [like].
tv(dontlike, [_, past]) --> [didnt,like].
tv(like, [_N, past]) --> [liked].
tv(kick, [_N, past]) --> [kicked].
iv(walk, [singular, present, _]) --> [walks].

pre(in) --> [in].
pre(to) --> [to].

cat(like, line).
cat(give, point).

%[geven] aan jan --> receiver(e, john).
cat(schoppen, tegen, slachtoffer).
cat(schoppen, naar, richting).

%Unify Last with the last conjunct in an expression by traversing it from begin to end.
last(_Penultimate^Last, Last).
last(_Head^Tail, Last) :-
	last(Tail, Last).

%generate a new event id, based on the last one plus one.
newid(ID) :-
	(discourse( isa(OldE, _V) ^ _ ) ->
		atom_concat(e, OldID, OldE),
		name(X, [OldID]),
		ID is X + 1
	;	ID = 1).

%Take a list of conjuncts, add the event ID to them, 
%and return in the form of a conjunction.
parsevp([], _ID, Result, Result).
%Initial conjunct should be treated differently,
%to avoid ending up with eg., a^b^c^_G347.
parsevp([H|Rest], ID, Acc, Result) :-
	var(Acc),
	H =.. [P, Arg], Conjunct =.. [P, ID, Arg],
	parsevp(Rest, ID, Conjunct, Result).
parsevp([H|Rest], ID, Acc, Result) :-
	H =.. [P, Arg], Conjunct =.. [P, ID, Arg],
	parsevp(Rest, ID, Conjunct^Acc, Result).

%Pretty-printer for events
eventprint(isa(A, B) ^ Tail) :-
	write(isa(A, B)), nl,
	eventprint(Tail).
eventprint(Conjunct^Tail) :-
	(Conjunct =.. [^|_CTail] ->
		eventprint(Conjunct)
	;	tab(8), write('^ '), 
		write(Conjunct), nl),
	eventprint(Tail).
eventprint(LastConjunct) :-
	tab(8), write('^ '), write(LastConjunct), nl.
