|
14 | 14 | :- endif.
|
15 | 15 |
|
16 | 16 | :- 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]). |
18 | 19 |
|
19 | 20 | % These predicates define extra arguments and are defined in the
|
20 | 21 | % modules that use the edcg module.
|
|
25 | 26 | pass_info/1,
|
26 | 27 | pass_info/2.
|
27 | 28 |
|
| 29 | +:- multifile |
| 30 | + prolog_clause:make_varnames_hook/5, |
| 31 | + prolog_clause:unify_clause_hook/5. |
28 | 32 |
|
29 | 33 | % True if the module being read has opted-in to EDCG macro expansion.
|
30 | 34 | wants_edcg_expansion :-
|
31 | 35 | prolog_load_context(module, Module),
|
| 36 | + wants_edcg_expansion(Module). |
| 37 | + |
| 38 | +wants_edcg_expansion(Module) :- |
32 | 39 | Module \== edcg, % don't expand macros in our own library
|
33 | 40 | predicate_property(Module:edcg_import_sentinel, imported_from(edcg)).
|
34 | 41 |
|
|
43 | 50 |
|
44 | 51 | % Returning a variable for _Layout2 means "I don't know".
|
45 | 52 | % 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). |
46 | 56 |
|
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). |
54 | 61 |
|
| 62 | +% TODO: |
| 63 | +% prolog_clause:make_varnames_hook(ReadClause, DecompiledClause, Offsets, Names, Term) :- ... |
55 | 64 |
|
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). |
57 | 89 | % Perform EDCG macro expansion
|
58 | 90 | % 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]), |
60 | 94 | 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), |
62 | 96 | '_finish_acc'(NewAcc),
|
63 | 97 | !.
|
64 |
| -edcg_term_expansion((H,PB==>>B), Expansion) => |
| 98 | +'_expand_clause'((H,PB==>>B), Expansion, _TermPos0, _) => % TODO TermPos |
| 99 | + % '==>>'(',',(H,PB),B) |
65 | 100 | 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), |
68 | 103 | '_finish_acc_ssu'(NewAcc, TB, TB2),
|
69 | 104 | !.
|
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]), |
71 | 108 | 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), |
73 | 110 | '_finish_acc_ssu'(NewAcc, TB, TB2),
|
74 | 111 | !.
|
75 | 112 |
|
76 |
| -:- det('_guard_expansion_'/2). |
| 113 | +:- det('_expand_guard'/2). |
77 | 114 | % TODO: Do we want to expand the guards?
|
78 | 115 | % For now, just verify that they all start with '?'
|
79 |
| -'_guard_expansion_'((?G0,G2), Expansion) => |
| 116 | +'_expand_guard'((?G0,G2), Expansion) => |
80 | 117 | 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, _) => |
86 | 123 | throw(error(type_error(guard,G),_)).
|
87 | 124 |
|
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). |
91 | 128 |
|
92 | 129 |
|
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) :- |
96 | 132 | functor(H, Na, Ar),
|
97 | 133 | '_has_hidden'(H, HList), % TODO: can backtrack - should it?
|
98 | 134 | debug(edcg,'Expanding ~w',[H]),
|
|
363 | 399 | % Give a list of G's hidden parameters:
|
364 | 400 | '_has_hidden'(G, GList) :-
|
365 | 401 | 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 | + ). |
370 | 406 |
|
371 | 407 | % Succeeds if A is an accumulator:
|
372 | 408 | '_is_acc'(A), atomic(A) => '_acc_info'(A, _, _, _, _, _, _).
|
|
439 | 475 | ['In ~w the term ''~w'' uses a non-existent hidden parameter.'-[Predicate,Term]].
|
440 | 476 | prolog:message(not_a_hidden_param(Name)) -->
|
441 | 477 | ['~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. |
442 | 538 |
|
443 | 539 | end_of_file.
|
0 commit comments