ISO: Implement the include/1 directive

Quoting from the standard:

    7.4.2.7 include/1

    If F is an implementation defined ground term designating
    a Prolog text unit, then Prolog text P1 which contains
    a directive include(F) is identical to a Prolog text P2
    obtained by replacing the directive include(F) in P1 by
    the Prolog text denoted by F.

Example:

    :- include("hello.pl").

This addresses #583 and #634.
This commit is contained in:
Markus Triska
2026-02-28 14:23:44 +01:00
parent 453a88f03e
commit 8f39bee463

View File

@@ -220,6 +220,46 @@ expand_op_list([Op | OtherOps], Pri, Spec, [(:- op(Pri, Spec, Op)) | OtherResult
expand_op_list(OtherOps, Pri, Spec, OtherResults).
% Implement the include/1 directive via term expansion.
user:term_expansion((:- include(File0)), Clauses) :-
( si:atom_si(File0) ->
atom_chars(File0, File),
format("% Warning: include/1: atom arguments are deprecated. Use chars for file paths:~n", []),
format("% :- include(\"~s\").~n", [File])
; error:must_be(chars, File0),
File = File0
),
'$toplevel':gather_clauses_from_file(File, Clauses).
gather_clauses_from_file(File, Clauses) :-
( file_exists(File) ->
setup_call_cleanup(open(File, read, Stream),
gather_clauses_(Stream, File, Clauses),
close(Stream))
; format("include/1: ~s does not exist.", [File]),
Clauses = []
).
gather_clauses_(Stream, _, []) :- at_end_of_stream(Stream), !.
gather_clauses_(Stream, File, Clauses) :-
catch((read(Stream, Clause),
Continue = true),
Error,
( Error = error(syntax_error(incomplete_reduction),_),
at_end_of_stream(Stream) ->
true
; format("~s: ~q", [File,Error])
)),
( Continue == true ->
Clauses = [Clause|Rest],
gather_clauses_(Stream, File, Rest)
; Clauses = []
).
read_and_match :-
'$read_query_term'(_, Term, _, _, VarList),
instruction_match(Term, VarList).