1:- module(
    2       da_source,
    3       [
    4           da_source_subterm_span/5,
    5           da_source_layout_span/4,
    6           da_source_clause_cached_reference/2,
    7           da_source_clause_reference/2,
    8           da_clause_decompiled/4,
    9           qualified/3,
   10           da_source_file_offsets_line_column_pairs/3
   11       ]
   12   ).   13
   14:- use_module(library(lists)).   15:- use_module(library(option)).   16:- use_module(library(prolog_clause)).

DAP library module for reasoning about Prolog sources

This module contains predicates for retrieving information about the spans and layouts of Prolog source terms for debugging purposes.

*/

   25:- predicate_options(da_source_subterm_span/5, 5, [pass_to(da_source_layout_span/4, 4)]).
 da_source_subterm_span(+SourceFile, +SourceLayout, +SubTermPositionPath, -SubTermSourceSpan, +Options) is det
   29:- det(da_source_subterm_span/5).   30da_source_subterm_span(File, Layout, SubTermPositionPath, SubTermSpan, Options) :-
   31    da_source_subterm_layout(Layout, SubTermPositionPath, SubTermLayout),
   32    da_source_layout_span(File, SubTermLayout, SubTermSpan, Options).
 da_source_subterm_layout(+Layout, +SubTermLayoutPath, -SubTermLayout) is det
   37:- det(da_source_subterm_layout/3).   38da_source_subterm_layout(Layout, _Path, Layout) :-
   39    var(Layout),
   40    !.
   41da_source_subterm_layout(term_position(_, _, _, _, PosL), [A|T], SPos) :-
   42    nth1(A, PosL, Pos),
   43    !,
   44    da_source_subterm_layout(Pos, T, SPos).
   45da_source_subterm_layout(brace_term_position(_,_,Pos), [1|T], SPos) :-
   46    !,
   47    da_source_subterm_layout(Pos, T, SPos).
   48da_source_subterm_layout(parentheses_term_position(_,_,Pos), Path, SPos) :-
   49    !,
   50    da_source_subterm_layout(Pos, Path, SPos).
   51da_source_subterm_layout(Layout, _Path, Layout).
   52
   53
   54:- predicate_options(da_source_layout_span/4, 4, [port(atom)]).
 da_source_layout_span(+File, +Layout, -SourceSpan, +Options) is det
   58:- det(da_source_layout_span/4).   59da_source_layout_span(File, Layout, SourceSpan, Options) :-
   60    option(port(Port), Options, call),
   61    da_source_layout_port_span(File, Layout, Port, SourceSpan).
 da_source_layout_port_span(+File, +Layout, +Port, -SourceSpan) is det
   66:- det(da_source_layout_port_span/4).   67da_source_layout_port_span(File, Layout, Port, span(File, SL, SC, EL, EC)) :-
   68    entry_port(Port),
   69    !,
   70    arg(1, Layout, SO),
   71    arg(2, Layout, EO),
   72    da_source_file_offsets_line_column_pairs(File, [SO, EO], [SL-SC, EL-EC]).
   73da_source_layout_port_span(File, Layout, Port, span(File, SL, SC, EL, EC)) :-
   74    exit_port(Port),
   75    !,
   76    arg(2, Layout, SO),
   77    succ(SO, EO),
   78    da_source_file_offsets_line_column_pairs(File, [SO, EO], [SL-SC, EL-EC]).
   79da_source_layout_port_span(File, Layout, _Port, SourceSpan) :-
   80    da_source_layout_functor_span(File, Layout, SourceSpan).
   81
   82
   83entry_port(call) :- !.
   84entry_port(cut_call(_)) :- !.
   85entry_port(redo(0)) :- !.
   86
   87exit_port(fail) :- !.
   88exit_port(exit) :- !.
   89exit_port(cut_exit(_)) :- !.
   90exit_port(exception(_)) :- !.
 da_source_layout_functor_span(+File, +Layout, -SourceSpan) is det
   95:- det(da_source_layout_functor_span/3).   96da_source_layout_functor_span(File, SO-EO, span(File, SL, SC, EL, EC)) :-
   97    !,
   98    da_source_file_offsets_line_column_pairs(File, [SO, EO], [SL-SC, EL-EC]).
   99da_source_layout_functor_span(File, term_position(_, _, SO, EO, _), span(File, SL, SC, EL, EC)) :-
  100    da_source_file_offsets_line_column_pairs(File, [SO, EO], [SL-SC, EL-EC]).
 da_source_file_offsets_line_column_pairs(+File, +Offsets, -LineColumnPairs) is det
  105:- det(da_source_file_offsets_line_column_pairs/3).  106da_source_file_offsets_line_column_pairs(path(File), Offsets, Pairs) :-
  107    !,
  108    setup_call_cleanup(
  109        ( prolog_clause:try_open_source(File, Stream),
  110          set_stream(Stream, newline(detect))
  111        ),
  112        da_source_stream_offsets_line_column_pairs(Stream, Offsets, Pairs),
  113        close(Stream)).
  114da_source_file_offsets_line_column_pairs(reference(0), Offsets, Pairs) :- !, findall(0-0, member(_, Offsets), Pairs).
  115da_source_file_offsets_line_column_pairs(reference(SourceReference), Offsets, Pairs) :-
  116    da_source_clause_cached_reference(ClauseRef, SourceReference),  % TODO - cache newline positions for cached clauses
  117    da_clause_decompiled(ClauseRef, Module, DecompiledClause, _),
  118    setup_call_cleanup(new_memory_file(MemFile),
  119                       ( setup_call_cleanup(open_memory_file(MemFile, write, MemOut),
  120                                            portray_clause(MemOut, DecompiledClause, [module(Module)]),
  121                                            close(MemOut)),
  122                         setup_call_cleanup(open_memory_file(MemFile, read, MemIn),
  123                                            da_source_stream_offsets_line_column_pairs(MemIn, Offsets, Pairs),
  124                                            close(MemIn))),
  125                       free_memory_file(MemFile)).
 da_source_stream_offsets_line_column_pairs(+Stream, +Offsets, -LineColumnPairs) is det
  130da_source_stream_offsets_line_column_pairs(_Stream, [], []) :- !.
  131da_source_stream_offsets_line_column_pairs(Stream, [H0|T0], [Line-Column|T]) :-
  132    da_source_stream_offset_line_column(Stream, H0, Line, Column),
  133    da_source_stream_offsets_line_column_pairs(Stream, T0, T).
 da_source_stream_offset_line_column(+File, +Offset, -Line, -Column) is det
da_source_stream_offset_line_column(+File, -Offset, +Line, +Column) is det
  139da_source_stream_offset_line_column(Stream, Offset, Line, Column) :-
  140    var(Offset),
  141    !,
  142    line_count(Stream, CurrentLine),
  143    (   CurrentLine == Line
  144    ->  character_count(Stream, CurrentOffset),
  145        Offset is CurrentOffset + Column
  146    ;   skip_line(Stream),
  147        da_source_stream_offset_line_column(Stream, Offset, Line, Column)
  148    ).
  149da_source_stream_offset_line_column(Stream, Offset, Line, Column) :-
  150    character_count(Stream, CurrentOffset),
  151    (   CurrentOffset == Offset
  152    ->  line_count(Stream, Line),
  153        line_position(Stream, Column)
  154    ;   get_code(Stream, _),
  155        da_source_stream_offset_line_column(Stream, Offset, Line, Column)
  156    ).
 da_source_clause_reference(+ClauseRef, -SourceReference) is det
  161:- det(da_source_clause_reference/2).  162da_source_clause_reference(ClauseRef, SourceReference) :-
  163    (   da_source_clause_cached_reference(ClauseRef, LastReference)
  164    ->  succ(LastReference, SourceReference)
  165    ;   random_between(0, 16777216, SourceReference)
  166    ),
  167    asserta(da_source_clause_cached_reference(ClauseRef, SourceReference)).
 da_source_clause_cached_reference(+ClauseRef, +SourceReference) is semidet
  172:- dynamic da_source_clause_cached_reference/2.
 da_clause_decompiled(+ClauseRef, -Module, -DecompiledClause, -VariablesOffset) is det
  177:- det(da_clause_decompiled/4).  178da_clause_decompiled(ClauseRef, Module, DecompiledClause, VariablesOffset) :-
  179    '$clause'(Head0, Body, ClauseRef, VariablesOffset),
  180    qualified(Head0, Module, Head),
  181    (   Body == true
  182    ->  DecompiledClause = Head
  183    ;   DecompiledClause = (Head :- Body)
  184    ).
  185
  186
  187qualified(Module:UnqualifiedGoal, Module, UnqualifiedGoal) :-
  188    !.
  189qualified('<meta-call>'(_Module0:Goal), Module, UnqualifiedGoal) :-
  190    qualified(Goal, Module, UnqualifiedGoal),
  191    !.
  192qualified('<meta-call>'(Goal), Module, UnqualifiedGoal) :-
  193    qualified(Goal, Module, UnqualifiedGoal),
  194    !.
  195
  196qualified(UnqualifiedGoal, user, UnqualifiedGoal)