Skip to content

Commit 96711df

Browse files
committed
Initial refactoring for term_expansion/4; add valid_termpos/2 for debugging
1 parent 2ffa7d9 commit 96711df

File tree

3 files changed

+146
-35
lines changed

3 files changed

+146
-35
lines changed

prolog/edcg.pl

+129-33
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
:- endif.
1515

1616
:- use_module(library(debug), [debug/3]).
17-
:- use_module(library(lists), [member/2]).
17+
:- use_module(library(lists), [member/2, selectchk/3]).
18+
:- use_module(library(apply), [maplist/3, maplist/4, foldl/4]).
1819

1920
% These predicates define extra arguments and are defined in the
2021
% modules that use the edcg module.
@@ -25,10 +26,16 @@
2526
pass_info/1,
2627
pass_info/2.
2728

29+
:- multifile
30+
prolog_clause:make_varnames_hook/5,
31+
prolog_clause:unify_clause_hook/5.
2832

2933
% True if the module being read has opted-in to EDCG macro expansion.
3034
wants_edcg_expansion :-
3135
prolog_load_context(module, Module),
36+
wants_edcg_expansion(Module).
37+
38+
wants_edcg_expansion(Module) :-
3239
Module \== edcg, % don't expand macros in our own library
3340
predicate_property(Module:edcg_import_sentinel, imported_from(edcg)).
3441

@@ -43,56 +50,85 @@
4350

4451
% Returning a variable for _Layout2 means "I don't know".
4552
% See https://swi-prolog.discourse.group/t/strange-warning-message-from-compile-or-listing/3774
53+
user:term_expansion(Term, Layout0, Expansion, Layout) :-
54+
wants_edcg_expansion,
55+
edcg_expand_clause(Term, Expansion, Layout0, Layout).
4656

47-
% TODO: support ((H,PB-->>B) [same as regular DCG]
48-
user:term_expansion((H-->>B), _Layout1, Expansion, _Layout2) :-
49-
edcg_term_expansion((H-->>B), Expansion).
50-
user:term_expansion((H,PB==>>B), _Layout1, Expansion, _Layout2) :-
51-
edcg_term_expansion((H,PB==>>B), Expansion).
52-
user:term_expansion((H==>>B), _Layout1, Expansion, _Layout2) :-
53-
edcg_term_expansion((H==>>B), Expansion).
57+
% TODO:
58+
% prolog_clause:unify_clause_hook(Read, Decompiled, Module, TermPos0, TermPos) :-
59+
% wants_edcg_expansion(Module),
60+
% edcg_expand_clause(Read, Decompiled, TermPos0, TermPos).
5461

62+
% TODO:
63+
% prolog_clause:make_varnames_hook(ReadClause, DecompiledClause, Offsets, Names, Term) :- ...
5564

56-
:- det(edcg_term_expansion/2).
65+
% TODO: support ((H,PB-->>B) [same as regular DCG]
66+
edcg_expand_clause((H-->>B), Expansion, TermPos0, _) :-
67+
edcg_expand_clause_wrap((H-->>B), Expansion, TermPos0, _).
68+
edcg_expand_clause((H,PB==>>B), Expansion, TermPos0, _) :-
69+
edcg_expand_clause_wrap((H,PB==>>B), Expansion, TermPos0, _).
70+
edcg_expand_clause((H==>>B), Expansion, TermPos0, _) :-
71+
edcg_expand_clause_wrap((H==>>B), Expansion, TermPos0, _).
72+
73+
edcg_expand_clause_wrap(Term, Expansion, TermPos0, TermPos) :-
74+
% ( valid_termpos(Term, TermPos0) % for debugging
75+
% -> true
76+
% ; throw(error(invalid_termpos_read(Term,TermPos0), _))
77+
% ),
78+
( '_expand_clause'(Term, Expansion, TermPos0, TermPos)
79+
-> true
80+
; throw(error('FAILED_expand_clause'(Term, Expansion, TermPos0, TermPos), _))
81+
),
82+
% ( valid_termpos(Expansion, TermPos) % for debugging
83+
% -> true
84+
% ; throw(error(invalid_termpos_expansion(Expansion, TermPos), _))
85+
% ).
86+
true.
87+
88+
% :- det('_expand_clause'/4).
5789
% Perform EDCG macro expansion
5890
% TODO: support ((H,PB-->>B) [same as regular DCG]
59-
edcg_term_expansion((H-->>B), Expansion) =>
91+
'_expand_clause'((H-->>B), Expansion, TermPos0, TermPos) =>
92+
TermPos0 = term_position(From,To,ArrowFrom,ArrowTo,[H_pos,B_pos]),
93+
TermPos = term_position(From,To,ArrowFrom,ArrowTo,[Hx_pos,Bx_pos]),
6094
Expansion = (TH:-TB),
61-
term_expansion_(H, B, TH, TB, NewAcc),
95+
'_expand_head_body'(H, B, TH, TB, NewAcc, H_pos,B_pos, Hx_pos,Bx_pos),
6296
'_finish_acc'(NewAcc),
6397
!.
64-
edcg_term_expansion((H,PB==>>B), Expansion) =>
98+
'_expand_clause'((H,PB==>>B), Expansion, _TermPos0, _) => % TODO TermPos
99+
% '==>>'(',',(H,PB),B)
65100
Expansion = (TH,Guards=>TB2),
66-
'_guard_expansion_'(PB, Guards),
67-
term_expansion_(H, B, TH, TB, NewAcc),
101+
'_expand_guard'(PB, Guards),
102+
'_expand_head_body'(H, B, TH, TB, NewAcc, _H_pos,_B_pos, _Hx_pos,_Bx_pos),
68103
'_finish_acc_ssu'(NewAcc, TB, TB2),
69104
!.
70-
edcg_term_expansion((H==>>B), Expansion) =>
105+
'_expand_clause'((H==>>B), Expansion, TermPos0, TermPos) =>
106+
TermPos0 = term_position(From,To,ArrowFrom,ArrowTo,[H_pos,B_pos]),
107+
TermPos = term_position(From,To,ArrowFrom,ArrowTo,[Hx_pos,Bx_pos]),
71108
Expansion = (TH=>TB2),
72-
term_expansion_(H, B, TH, TB, NewAcc),
109+
'_expand_head_body'(H, B, TH, TB, NewAcc, H_pos,B_pos, Hx_pos,Bx_pos),
73110
'_finish_acc_ssu'(NewAcc, TB, TB2),
74111
!.
75112

76-
:- det('_guard_expansion_'/2).
113+
:- det('_expand_guard'/2).
77114
% TODO: Do we want to expand the guards?
78115
% For now, just verify that they all start with '?'
79-
'_guard_expansion_'((?G0,G2), Expansion) =>
116+
'_expand_guard'((?G0,G2), Expansion) =>
80117
Expansion = (G, GE2),
81-
'_guard_expansion_curly_'(G0, G),
82-
'_guard_expansion_'(G2, GE2).
83-
'_guard_expansion_'(?G0, G) =>
84-
'_guard_expansion_curly_'(G0, G).
85-
'_guard_expansion_'(G, _) =>
118+
'_expand_guard_curly'(G0, G),
119+
'_expand_guard'(G2, GE2).
120+
'_expand_guard'(?G0, G) =>
121+
'_expand_guard_curly'(G0, G).
122+
'_expand_guard'(G, _) =>
86123
throw(error(type_error(guard,G),_)).
87124

88-
:- det('_guard_expansion_curly_'/2).
89-
'_guard_expansion_curly_'({G}, G) :- !.
90-
'_guard_expansion_curly_'(G, G).
125+
:- det('_expand_guard_curly'/2).
126+
'_expand_guard_curly'({G}, G) :- !.
127+
'_expand_guard_curly'(G, G).
91128

92129

93-
:- det(term_expansion_/5).
94-
term_expansion_(H, B, TH, TB, NewAcc) :-
95-
wants_edcg_expansion,
130+
:- det('_expand_head_body'/9).
131+
'_expand_head_body'(H, B, TH, TB, NewAcc, _H_pos,_B_pos, _Hx_pos,_Bx_pos) :-
96132
functor(H, Na, Ar),
97133
'_has_hidden'(H, HList), % TODO: can backtrack - should it?
98134
debug(edcg,'Expanding ~w',[H]),
@@ -363,10 +399,10 @@
363399
% Give a list of G's hidden parameters:
364400
'_has_hidden'(G, GList) :-
365401
functor(G, GName, GArity),
366-
pred_info(GName, GArity, GList).
367-
'_has_hidden'(G, []) :-
368-
functor(G, GName, GArity),
369-
\+pred_info(GName, GArity, _).
402+
( pred_info(GName, GArity, GList)
403+
-> true
404+
; GList = []
405+
).
370406

371407
% Succeeds if A is an accumulator:
372408
'_is_acc'(A), atomic(A) => '_acc_info'(A, _, _, _, _, _, _).
@@ -439,5 +475,65 @@
439475
['In ~w the term ''~w'' uses a non-existent hidden parameter.'-[Predicate,Term]].
440476
prolog:message(not_a_hidden_param(Name)) -->
441477
['~w is not a hidden parameter'-[Name]].
478+
% === The following are for debugging term_expansion/4
479+
480+
% :- det(valid_termpos/2). % DO NOT SUBMIT
481+
%! valid_termpos(+Term, ?TermPos) is semidet.
482+
% Checks that a Term has an appropriate TermPos.
483+
% This should always succeed:
484+
% read_term(Term, [subterm_positions(TermPos)]),
485+
% valid_termpos(Term, TermPos)
486+
% Note that this can create a TermPos. Each clause ends with
487+
% a cut, to avoid unneeded backtracking.
488+
valid_termpos(Term, TermPos) :-
489+
( valid_termpos_(Term, TermPos)
490+
-> true
491+
; fail % throw(error(invalid_termpos(Term,TermPos), _)) % DO NOT SUBMIT
492+
).
493+
494+
valid_termpos_(Var, _From-_To) :- var(Var).
495+
valid_termpos_(Atom, _From-_To) :- atom(Atom), !.
496+
valid_termpos_(Number, _From-_To) :- number(Number), !.
497+
valid_termpos_(String, string_position(_From,_To)) :- string(String), !.
498+
valid_termpos_([], _From-_To) :- !.
499+
valid_termpos_({Arg}, brace_term_position(_From,_To,ArgPos)) :-
500+
valid_termpos(Arg, ArgPos), !.
501+
% TODO: combine the two list_position clauses
502+
valid_termpos_([Hd|Tl], list_position(_From,_To, ElemsPos, none)) :-
503+
maplist(valid_termpos, [Hd|Tl], ElemsPos),
504+
list_tail([Hd|Tl], _, []), !.
505+
valid_termpos_([Hd|Tl], list_position(_From,_To, ElemsPos, TailPos)) :-
506+
list_tail([Hd|Tl], HdPart, Tail),
507+
tailPos \= none, Tail \= [],
508+
maplist(valid_termpos, HdPart, ElemsPos),
509+
valid_termpos(Tail, TailPos), !.
510+
valid_termpos_(Term, term_position(_From,_To, FFrom,FTo,SubPos)) :-
511+
compound_name_arguments(Term, Name, Arguments),
512+
valid_termpos(Name, FFrom-FTo),
513+
maplist(valid_termpos, Arguments, SubPos), !.
514+
valid_termpos_(Dict, dict_position(_From,_To,TagFrom,TagTo,KeyValuePosList)) :-
515+
dict_pairs(Dict, Tag, Pairs),
516+
valid_termpos(Tag, TagFrom-TagTo),
517+
foldl(valid_termpos_dict, Pairs, KeyValuePosList, []), !.
518+
% key_value_position(From, To, SepFrom, SepTo, Key, KeyPos, ValuePos) is handled
519+
% in valid_termpos_dict.
520+
valid_termpos_(Term, parentheses_term_position(_From,_To,ContentPos)) :-
521+
valid_termpos(Term, ContentPos), !.
522+
% TODO: documentation for quasi_quotation_position is wrong (SyntaxTo,SyntaxFrom should be SYntaxTerm,SyntaxPos).
523+
valid_termpos_(_Term, quasi_quotation_position(_From,_To,SyntaxTerm,SyntaxPos,_ContentPos)) :-
524+
valid_termpos(SyntaxTerm, SyntaxPos), !.
525+
526+
:- det(valid_termpos_dict/3).
527+
valid_termpos_dict(Key-Value, KeyValuePosList0, KeyValuePosList1) :-
528+
selectchk(key_value_position(_From,_To,_SepFrom,_SepTo,Key,KeyPos,ValuePos),
529+
KeyValuePosList0, KeyValuePosList1),
530+
valid_termpos(Key, KeyPos),
531+
valid_termpos(Value, ValuePos).
532+
533+
:- det(list_tail/3).
534+
list_tail([X|Xs], HdPart, Tail) =>
535+
HdPart = [X|HdPart2],
536+
list_tail(Xs, HdPart2, Tail).
537+
list_tail(Tail0, HdPart, Tail) => HdPart = [], Tail0 = Tail.
442538

443539
end_of_file.

t/examples.pl

+10
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
edcg:pred_info(sum,0,[adder,dcg]).
2828
edcg:pred_info(expr_code,1,[size,code]).
2929
edcg:pred_info(expr_code_ssu,1,[size,code]).
30+
edcg:pred_info(maplist_x,2,[pollux,castor]).
3031

3132

3233
% flist(N,[],List) creates the list [1,2,...,N]
@@ -139,6 +140,15 @@
139140
[push(I)]:code,
140141
[1]:size.
141142

143+
% Example of maplist-like predicate that has explicit accumulators.
144+
% TODO: verify the generated code in unit tests.
145+
146+
maplist_x([], _Pred) ==>> [ ].
147+
maplist_x([X|Xs], Pred) ==>>
148+
call(Pred, X):[pollux,castor],
149+
maplist_x(Xs, Pred).
150+
151+
142152

143153
:- use_module(library(plunit)).
144154

t/synopsis.pl

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
1-
:- use_module('../prolog/edcg.pl'). % :- use_module(library(edcg)).
1+
:- use_module('../prolog/edcg.pl').
2+
% :- use_module(library(edcg)).
23

34
% Declare accumulators
45
edcg:acc_info(adder, X, In, Out, plus(X,In,Out)).
56

67
% Declare predicates using these hidden arguments
78
edcg:pred_info(len,0,[adder,dcg]).
89
edcg:pred_info(increment,0,[adder]).
10+
edcg:pred_info(increment,1,[adder]).
911

1012
increment -->>
11-
[1]:adder.
13+
increment(1).
14+
15+
increment(I) -->>
16+
[I]:adder.
1217

1318

1419
len(Xs,N) :-

0 commit comments

Comments
 (0)