From bbfa35ee7cfb6b23a089467a117c26528900b0c5 Mon Sep 17 00:00:00 2001 From: MikeArchbold Date: Mon, 30 Dec 2024 19:57:14 -0800 Subject: [PATCH 1/5] updates --- examples/games/GreedyChess.metta | 102 ++++++++++++++++++++++--------- 1 file changed, 73 insertions(+), 29 deletions(-) diff --git a/examples/games/GreedyChess.metta b/examples/games/GreedyChess.metta index b7587f373..0adbf6557 100644 --- a/examples/games/GreedyChess.metta +++ b/examples/games/GreedyChess.metta @@ -203,41 +203,47 @@ ; ; The reset command will start the game over. -(= (reset) +(: R (-> command)) +(= (R) (chess)) ; The "commands" command just lists the available commands. -(= (commands) +(: C (-> command)) +(= (C) (progn (println! " ") (println! " ") (println! " ") (println! " ") (println! (format-args '-------- C o m m a n d s -----------' ())) - (println! (format-args '1) TO MOVE YOUR PIECE USE (example) -> m 1 2 1 3' ())) + (println! (format-args '1) TO MOVE YOUR PIECE USE (example) -> M 1 2 1 3' ())) (println! (format-args ' Result: YOUR pawn in 1,2 moved to location 1,3 based on standard cartesian x/y.' ())) - (println! (format-args '2) Move MeTTa Greedy Chess -> g' ())) - (println! (format-args '3) Reset -> reset' ())) - (println! (format-args '4) Commands List -> commands' ())) - (println! (format-args '5) Display Board -> display' ())) - (println! (format-args 'You may now enter your move m x1 y1 x2 y2 command.' ())))) + (println! (format-args '2) Move MeTTa Greedy Chess -> G' ())) + (println! (format-args '3) Reset -> R' ())) + (println! (format-args '4) Commands List -> C' ())) + (println! (format-args '5) Display Board -> D' ())) + (println! (format-args '6) Quit -> Q' ())) + (println! (format-args 'You may now enter your move M x1 y1 x2 y2 command.' ())))) ; ; The display command shows the present board. -(= (display) (display_board (match &self (board-state $board) $board))) +(: D (-> command)) +(= (D) (display_board (match &self (board-state $board) $board))) ;******************************************************* ; Code invoked by the basic commands (above) or elsewhere follow ;******************************************************* -; Get next move -;(: get-player-move (-> Expression)) ; Function to get a move from the player. -;(= (get-player-move) -; (progn -; ( -; (flush-output!) -; (let $char get-single-char! $char) ; Convert the input character to an integer (1-9). -; ))) -(= (get-player-move) (progn ((flush-output) (get-single-char!) ))) - write welcome banner to console and call display_board to print the pieces +; Invoke with empty list, will return characters input from console until ENTER. +(: (get-player-command (-> list list))) +(= (get-player-command $input_list) + (let $cmd (get-single-char!) + (progn + (if (== (size-atom $input_list) 0) (flush-output!) ()) + (if (== $cmd 13) + $input_list + (let $new_list (cons-atom $cmd $input_list) (get-player-command $new_list)))))) + + +; write welcome banner to console and call display_board to print the pieces (= (welcome) (progn ((println! " ") (println! " ") (println! " ") (println! " ") @@ -251,13 +257,14 @@ (println! (format-args '- Your pieces are marked with an asterisk.' ())) (println! (format-args '- Please take note of the following simple commands:' ())) (println! (format-args '-------- C o m m a n d s -----------' ())) - (println! (format-args '1) TO MOVE YOUR PIECE USE (example) -> m 1 2 1 3' ())) + (println! (format-args '1) TO MOVE YOUR PIECE USE (example) -> M 1 2 1 3' ())) (println! (format-args ' Result: YOUR pawn in 1,2 moved to location 1,3 based on standard cartesian x/y.' ())) - (println! (format-args '2) Move MeTTa Greedy Chess -> g' ())) - (println! (format-args '3) Reset -> reset' ())) - (println! (format-args '4) Commands List -> commands' ())) - (println! (format-args '5) Display Board -> display' ())) - (println! (format-args 'You may now enter your move m x1 y1 x2 y2 command.' ())) + (println! (format-args '2) Move MeTTa Greedy Chess -> G' ())) + (println! (format-args '3) Reset -> R' ())) + (println! (format-args '4) Commands List -> C' ())) + (println! (format-args '5) Display Board -> D' ())) + (println! (format-args '6) Quit -> Q' ())) + (println! (format-args 'You may now enter your move M x1 y1 x2 y2 command.' ())) ))) ; identify_piece inputs an expression of a piece, eg: "(2 1 s n)," and outputs a shorted two character string @@ -283,7 +290,7 @@ ; if on last piece, return a one element list of this form eg.: (*k). Extra parens are needed to create list. ( (identify_piece (car-atom $brd)) ) ; otherwise convert all pieces to shorter description for display. - (let $i (display_filter (cdr-atom $brd)) (cons-atom (identify_piece (car-atom $brd)) $i)))) + (let $rest (display_filter (cdr-atom $brd)) (cons-atom (identify_piece (car-atom $brd)) $rest)))) (= (display_board $board) ( @@ -309,10 +316,47 @@ $a))))) -!(chess) -!(get-player-move) +;******************************************************* +; M A I N C O M M A N D L O O P +;******************************************************* +(= (command-loop) + (do + (println! "Please enter your command.") + (let $command (get-player-command ()) + (if (== $command 77) + (do + (println! "running command M") ; Run valid command + (command-loop)) ; Get next command, stay in loop. + (if (== $command 71) + (do + (println! "running command G") ; Run valid command + (command-loop)) ; Get next command, stay in loop. + (if (== $command 82) + (do + (R) ; Reset = "R" + (command-loop)) ; Get next command, stay in loop. + (if (== $command 67) + (do + (C) ; List valid commands = "C" + (command-loop)) ; Get next command, stay in loop. + (if (== $command 68) + (do + (D) ; Display board "D" + (command-loop)) ; Get next command, stay in loop. + (if (== $command 81) + (println! "Quitting MeTTa Greedy Chess.") + ; otherwise + (do + (println! " ") (println! "Invalid command, please try again or enter C for a list of commands.") + (command-loop))))))))))) -; +;-----------; +(= (main_loop) + (do + (chess) ; Start the chess game + (command-loop))) ; Enter the recursive command-processing loop +!(main_loop) +;-----------; ; ; From dc708b4e52540452d2122c22cd7e5eeaaeebdd36 Mon Sep 17 00:00:00 2001 From: MikeArchbold Date: Tue, 31 Dec 2024 10:30:13 -0800 Subject: [PATCH 2/5] incrementally added comments --- prolog/metta_lang/metta_interp.pl | 242 ++++++++++++++++++++++++------ 1 file changed, 197 insertions(+), 45 deletions(-) diff --git a/prolog/metta_lang/metta_interp.pl b/prolog/metta_lang/metta_interp.pl index c0f20cfc6..da5dc5ef7 100755 --- a/prolog/metta_lang/metta_interp.pl +++ b/prolog/metta_lang/metta_interp.pl @@ -382,60 +382,212 @@ :- multifile(metta_compiled_predicate/3). :- dynamic(metta_compiled_predicate/3). +%! once_writeq_nl(+P) is det. +% +% Ensures that the given term `P` is printed exactly once in the current session. +% +% This predicate prevents duplicate printing of the same term using a global +% non-backtrackable variable (`$once_writeq_ln`). It utilizes `numbervars/4` +% to standardize variable names for comparison and `ansi_format/3` to provide +% colored output. +% +% @arg P The term to be printed. It will be printed once per invocation with +% `ansi_format` using cyan foreground text. +% +% @example Print a term only once: +% ?- once_writeq_nl(foo(bar)). +% foo(bar). +% +once_writeq_nl(_) :- + % If the predicate `pfcTraceExecution` is not defined, succeed immediately. + \+ clause(pfcTraceExecution, true), !. +once_writeq_nl(P) :- + % If `$once_writeq_ln` is already set to the current term `P`, succeed silently. + nb_current('$once_writeq_ln', W), + W=@=P,!. +once_writeq_nl(P) :- + % Standardize variable names in `P` and print it using `ansi_format`. + % Use `nb_setval` to store the printed term in `$once_writeq_ln`. + \+ \+ (numbervars(P, 444, _, [attvar(skip), singletons(true)]), + ansi_format([fg(cyan)], '~N~q.~n', [P])), + nb_setval('$once_writeq_ln', P),!. -once_writeq_nl(_):- \+ clause(pfcTraceExecution,true),!. -once_writeq_nl(P):- nb_current('$once_writeq_ln',W),W=@=P,!. -once_writeq_nl(P):- - \+ \+ (numbervars(P,444,_,[attvar(skip),singletons(true)]), - ansi_format([fg(cyan)],'~N~q.~n',[P])),nb_setval('$once_writeq_ln',P),!. -% TODO uncomment this next line but it is breaking the curried chainer +%! pfcAdd_Now(+P) is det. +% +% Adds a clause or fact `P` to the database using `pfcAdd/1` or `assert/1`. +% +% This predicate checks whether the predicate `pfcAdd/1` exists in the database. +% If it exists, it calls `pfcAdd/1` after printing the term using `once_writeq_nl`. +% If not, it defaults to using `assert/1` after printing the term. +% +% @arg P The clause or fact to be added to the database. +% +% @example Add a fact to the database: +% ?- pfcAdd_Now(foo(bar)). +% foo(bar). +% +% @see once_writeq_nl/1 +% +% TODO: Uncomment the following line if the `pfcAdd` predicate is stable and +% does not interfere with the curried chainer logic. % pfcAdd_Now(P):- pfcAdd(P),!. -pfcAdd_Now(P):- current_predicate(pfcAdd/1),!, once_writeq_nl(pfcAdd(P)),pfcAdd(P). -pfcAdd_Now(P):- once_writeq_nl(asssert(P)),assert(P). +pfcAdd_Now(P) :- + % If `pfcAdd/1` is defined, print the term using `once_writeq_nl` and call `pfcAdd/1`. + current_predicate(pfcAdd/1),!, + once_writeq_nl(pfcAdd(P)), + pfcAdd(P). +pfcAdd_Now(P) :- + % If `pfcAdd/1` is not defined, print the term using `once_writeq_nl` and assert it. + once_writeq_nl(asssert(P)), + assert(P). %:- endif. -system:copy_term_g(I,O):- ground(I),!,I=O. -system:copy_term_g(I,O):- copy_term(I,O). +%! system:copy_term_g(+I, -O) is det. +% +% Optimized version of `copy_term/2` for ground terms. +% +% If `I` is ground, it unifies `I` directly with `O`. Otherwise, it behaves +% like `copy_term/2`, creating a fresh copy of `I`. +% +% @arg I The input term (ground or non-ground). +% @arg O The output term, a copy of `I`. +% +system:copy_term_g(I, O) :- + % Directly unify if the input is ground. + ground(I),!,I = O. +system:copy_term_g(I, O) :- + % Otherwise, use `copy_term/2`. + copy_term(I, O). :- ensure_loaded(metta_debug). -is_metta_flag(What):- notrace(is_flag0(What)). +%! is_metta_flag(+What) is nondet. +% +% Checks if a specific flag `What` is enabled in the current configuration. +% +% This predicate uses `is_flag0/1` to verify the status of the given flag, +% while suppressing tracing for performance reasons. +% +% @arg What The name of the flag to check. +% +is_metta_flag(What) :- + % Check the flag without enabling tracing. + notrace(is_flag0(What)). +% +% Always succeeds, representing a logical flag that evaluates to true. +% true_flag. -false_flag:- fail. - -is_tRuE(TF):- TF=='True',!. -is_tRuE(TF):- TF=='true',!. -is_fAlSe(TF):- TF=='False',!. -is_fAlSe(TF):- TF=='false',!. -is_flag0(What):- nb_current(What,TF),is_tRuE(TF), !. -is_flag0(What):- nb_current(What,TF),is_fAlSe(TF), !, fail. -is_flag0(What):- current_prolog_flag(What,TF),is_tRuE(TF),!. -is_flag0(What):- current_prolog_flag(What,TF),is_fAlSe(TF),!. -is_flag0(What):- - symbol_concat('--',What,FWhat),symbol_concat(FWhat,'=true',FWhatTrue), - symbol_concat('--no-',What,NoWhat),symbol_concat(FWhat,'=false',FWhatFalse), - is_flag0(What,[FWhat,FWhatTrue],[NoWhat,FWhatFalse]). - -is_flag0(What,_FWhatTrue,FWhatFalse):- - current_prolog_flag(os_argv,ArgV), - member(FWhat,FWhatFalse),member(FWhat,ArgV),!, - %notrace(catch(set_prolog_flag(What,false),_,true)), - set_option_value(What,'False'),!,fail. -is_flag0(What,FWhatTrue,_FWhatFalse):- - current_prolog_flag(os_argv,ArgV), - member(FWhat,FWhatTrue),member(FWhat,ArgV),!, - %notrace(catch(set_prolog_flag(What,true),_,true)), - set_option_value(What,'True'),!. -is_flag0(What,_FWhatTrue,_FWhatFalse):- - current_prolog_flag(os_argv,ArgV), - symbolic_list_concat(['--',What,'='],Starts), - member(FWhat,ArgV),symbol_concat(Starts,Rest,FWhat), - set_option_value_interp(What,Rest),!. - -is_compiling:- current_prolog_flag(os_argv,ArgV),member(E,ArgV), (E==qcompile_mettalog;E==qsave_program),!. -is_compiled:- current_prolog_flag(os_argv,ArgV), member('-x',ArgV),!. -is_compiled:- current_prolog_flag(os_argv,ArgV),\+ member('swipl',ArgV),!. + +% +% Always fails, representing a logical flag that evaluates to false. +% +false_flag :- fail. + +%! is_tRuE(+TF) is det. +% +% Checks if the given term `TF` represents a logical "true" value. +% +% @arg TF A term expected to be either `'True'` or `'true'`. +% +is_tRuE(TF) :- + % Match 'True' exactly. + TF == 'True',!. +is_tRuE(TF) :- + % Match 'true' exactly. + TF == 'true',!. + +%! is_fAlSe(+TF) is det. +% +% Checks if the given term `TF` represents a logical "false" value. +% +% @arg TF A term expected to be either `'False'` or `'false'`. +% +is_fAlSe(TF) :- + % Match 'False' exactly. + TF == 'False',!. +is_fAlSe(TF) :- + % Match 'false' exactly. + TF == 'false',!. + +%! is_flag0(+What) is nondet. +% +% Checks if a flag `What` is logically true in the current environment. +% +% @arg What The flag to check. +% +is_flag0(What) :- + % Check if the flag exists as a non-backtrackable global variable and is true. + nb_current(What, TF),is_tRuE(TF),!. +is_flag0(What) :- + % Check if the flag exists as a non-backtrackable global variable and is false. + nb_current(What, TF),is_fAlSe(TF),!,fail. +is_flag0(What) :- + % Check if the flag exists as a Prolog configuration flag and is true. + current_prolog_flag(What, TF),is_tRuE(TF),!. +is_flag0(What) :- + % Check if the flag exists as a Prolog configuration flag and is false. + current_prolog_flag(What, TF),is_fAlSe(TF),!. +is_flag0(What) :- + % Build flag strings for parsing command-line arguments. + symbol_concat('--', What, FWhat), + symbol_concat(FWhat, '=true', FWhatTrue), + symbol_concat('--no-', What, NoWhat), + symbol_concat(FWhat, '=false', FWhatFalse), + is_flag0(What, [FWhat, FWhatTrue], [NoWhat, FWhatFalse]). + +%! is_flag0(+What, +FWhatTrue, +FWhatFalse) is nondet. +% +% Checks command-line arguments (`os_argv`) to determine the status of a flag. +% +% @arg What The flag being checked. +% @arg FWhatTrue A list of patterns representing a "true" status for the flag. +% @arg FWhatFalse A list of patterns representing a "false" status for the flag. +% +is_flag0(What, _FWhatTrue, FWhatFalse) :- + % Check if the flag is explicitly set to false in command-line arguments. + current_prolog_flag(os_argv, ArgV),member(FWhat, FWhatFalse),member(FWhat, ArgV),!, + % notrace(catch(set_prolog_flag(What, false), _, true)), + set_option_value(What, 'False'),!,fail. +is_flag0(What, FWhatTrue, _FWhatFalse) :- + % Check if the flag is explicitly set to true in command-line arguments. + current_prolog_flag(os_argv, ArgV),member(FWhat, FWhatTrue),member(FWhat, ArgV),!, + % notrace(catch(set_prolog_flag(What, true), _, true)), + set_option_value(What, 'True'),!. +is_flag0(What, _FWhatTrue, _FWhatFalse) :- + % Parse flags with specific key-value pair syntax in command-line arguments. + current_prolog_flag(os_argv, ArgV),symbolic_list_concat(['--', What, '='], Starts), + member(FWhat, ArgV),symbol_concat(Starts, Rest, FWhat),set_option_value_interp(What, Rest),!. + +%! is_compiling is nondet. +% +% Succeeds if the program is currently in a compilation phase. +% +% This predicate checks the Prolog runtime arguments (`os_argv`) to determine if +% the system is performing specific compilation tasks, such as `qcompile_mettalog` +% or `qsave_program`. +% +is_compiling :- + current_prolog_flag(os_argv, ArgV),member(E, ArgV), + % Check if compilation-specific arguments are present. + (E == qcompile_mettalog; E == qsave_program),!. + +%! is_compiled is nondet. +% +% Succeeds if the program has been compiled into an executable. +% +% This predicate verifies whether Prolog is running a precompiled executable by +% checking for the `-x` flag in `os_argv` or ensuring `swipl` is not present in the +% argument list. +% +is_compiled :- + current_prolog_flag(os_argv, ArgV), + % Check if the `-x` flag is present, indicating an executable was started. + member('-x', ArgV),!. +is_compiled :- + current_prolog_flag(os_argv, ArgV), + % If 'swipl' is absent from the arguments, assume it is a compiled binary. + \+ member('swipl', ArgV),!. is_converting:- is_metta_flag('convert'). From 4d156b3212f09d70536950587851b650ba4092c0 Mon Sep 17 00:00:00 2001 From: MikeArchbold Date: Tue, 31 Dec 2024 10:32:44 -0800 Subject: [PATCH 3/5] main loop working --- examples/games/GreedyChess.metta | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/examples/games/GreedyChess.metta b/examples/games/GreedyChess.metta index 0adbf6557..a2c36aa1d 100644 --- a/examples/games/GreedyChess.metta +++ b/examples/games/GreedyChess.metta @@ -3,8 +3,8 @@ ; Mettalog Project 2024 ; Function: Play chess (human vs MeTTa program) using a fairly simple "greedy" approach -; with moves that do not project possible boards beyond the present board. -; Input: User's moves from console. +; with moves that do not project possible boards beyond the present board. +; Input: User's commands and moves from console. ; Output: Chess board displayed to console with computer's move. ; ;********************************************************************** @@ -237,10 +237,13 @@ (= (get-player-command $input_list) (let $cmd (get-single-char!) (progn + ; if initial execution flush output (if (== (size-atom $input_list) 0) (flush-output!) ()) - (if (== $cmd 13) - $input_list - (let $new_list (cons-atom $cmd $input_list) (get-player-command $new_list)))))) + (if (== $cmd 13) ; if user hit + ;return all input + $input_list + ;else gather more input + (let $new_list (cons-atom $cmd $input_list) (get-player-command $new_list)))))) ; write welcome banner to console and call display_board to print the pieces @@ -276,12 +279,10 @@ (let* ( ; assign either * or " " ($player (if (== (contains_symbol $p s) True) * " ")) + ; identify piece ($piece (nth 4 $p)) ) - (format-args "{}{}" ($player $piece)) - ) - ) -) + (format-args "{}{}" ($player $piece))))) ; Input the board, output a list of the board easier to read with an identifier for each piece, eg., human king is "*k." (: display_filter (-> list list)) @@ -322,6 +323,7 @@ (= (command-loop) (do (println! "Please enter your command.") + ; case statement for commands (let $command (get-player-command ()) (if (== $command 77) (do From 07e0e58cf3519f9510b6a34eb3dda5c0c4a56707 Mon Sep 17 00:00:00 2001 From: MikeArchbold Date: Tue, 31 Dec 2024 10:40:02 -0800 Subject: [PATCH 4/5] incrementally added comments --- prolog/metta_lang/metta_interp.pl | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/prolog/metta_lang/metta_interp.pl b/prolog/metta_lang/metta_interp.pl index da5dc5ef7..abf5e32d3 100755 --- a/prolog/metta_lang/metta_interp.pl +++ b/prolog/metta_lang/metta_interp.pl @@ -428,6 +428,7 @@ % % @see once_writeq_nl/1 % + % TODO: Uncomment the following line if the `pfcAdd` predicate is stable and % does not interfere with the curried chainer logic. % pfcAdd_Now(P):- pfcAdd(P),!. @@ -474,14 +475,7 @@ % Check the flag without enabling tracing. notrace(is_flag0(What)). -% -% Always succeeds, representing a logical flag that evaluates to true. -% true_flag. - -% -% Always fails, representing a logical flag that evaluates to false. -% false_flag :- fail. %! is_tRuE(+TF) is det. From 909be91854cd336ab25879eb05a0692c171d7f29 Mon Sep 17 00:00:00 2001 From: MikeArchbold Date: Wed, 1 Jan 2025 12:55:08 -0800 Subject: [PATCH 5/5] more comments --- prolog/metta_lang/metta_interp.pl | 358 +++++++++++++++++++++++++----- 1 file changed, 297 insertions(+), 61 deletions(-) diff --git a/prolog/metta_lang/metta_interp.pl b/prolog/metta_lang/metta_interp.pl index abf5e32d3..882195117 100755 --- a/prolog/metta_lang/metta_interp.pl +++ b/prolog/metta_lang/metta_interp.pl @@ -583,94 +583,330 @@ % If 'swipl' is absent from the arguments, assume it is a compiled binary. \+ member('swipl', ArgV),!. -is_converting:- is_metta_flag('convert'). +%! is_converting is nondet. +% +% Succeeds if the 'convert' flag is set using is_metta_flag/1. +% +% @see is_metta_flag/1 +% +% @example +% ?- is_converting. +% true. +is_converting :- is_metta_flag('convert'). + +%! is_compat is nondet. +% +% Succeeds if the 'compat' flag is set using is_metta_flag/1. +% +% @see is_metta_flag/1 +% +% @example +% ?- is_compat. +% true. +is_compat :- is_metta_flag('compat'). + +%! is_mettalog is nondet. +% +% Succeeds if the 'log' flag is set using is_metta_flag/1. +% +% @see is_metta_flag/1 +% +% @example +% ?- is_mettalog. +% true. -is_compat:- is_metta_flag('compat'). +% is_mettalog :- is_win64,!. +is_mettalog :- is_metta_flag('log'). + +%! is_devel is nondet. +% +% Succeeds if the 'devel' flag is set using is_metta_flag/1. +% +% @see is_metta_flag/1 +% +% @example +% ?- is_devel. +% true. +is_devel :- is_metta_flag('devel'). -%is_mettalog:- is_win64,!. -is_mettalog:- is_metta_flag('log'). -is_devel:- is_metta_flag('devel'). +%! is_synthing_unit_tests is nondet. +% +% Wrapper around is_synthing_unit_tests0/0, executed without tracing. +% +% @see is_synthing_unit_tests0/0 +% +% @example +% ?- is_synthing_unit_tests. +% true. +is_synthing_unit_tests :- notrace(is_synthing_unit_tests0). + +%! is_synthing_unit_tests0 is nondet. +% +% Succeeds if is_testing/0 is true. +% +% @see is_testing/0 +% +% @example +% ?- is_synthing_unit_tests0. +% true. +is_synthing_unit_tests0 :- is_testing. +% is_synthing_unit_tests0 :- is_html. +% is_synthing_unit_tests0 :- is_compatio,!,fail. -is_synthing_unit_tests:- notrace(is_synthing_unit_tests0). -is_synthing_unit_tests0:- is_testing. -%is_synthing_unit_tests0:- is_html. -% is_synthing_unit_tests0:- is_compatio,!,fail. +%! is_testing is nondet. +% +% Succeeds if the 'test' flag is set using is_metta_flag/1. +% +% @see is_metta_flag/1 +% +% @example +% ?- is_testing. +% true. +is_testing :- is_metta_flag('test'). -is_testing:- is_metta_flag('test'). -is_html:- is_metta_flag('html'). +%! is_html is nondet. +% +% Succeeds if the 'html' flag is set using is_metta_flag/1. +% +% @see is_metta_flag/1 +% +% @example +% ?- is_html. +% true. +is_html :- is_metta_flag('html'). +% If the file is not already loaded, this is equivalent to consult/1. Otherwise, if the file defines a module, +% import all public predicates. Finally, if the file is already loaded, is not a module file, and the context +% module is not the global user module, ensure_loaded/1 will call consult/1. :- ensure_loaded(metta_printer). :- ensure_loaded(metta_loader). - +% This directive ensures that debugging messages or tracing for +% `'trace-on-eval'` are suppressed, reducing console output during evaluation. :- nodebug(metta('trace-on-eval')). -is_compatio:- notrace(is_compatio0). -%is_compatio0:- is_win64,!,fail. -is_compatio0:- is_testing,!,fail. -is_compatio0:- is_flag0('compatio'). -is_compatio0:- is_mettalog,!,fail. -%is_compatio0:- is_html,!,fail. -is_compatio0:- !. +%! is_compatio is nondet. +% +% Succeeds if `is_compatio0/0` succeeds, executed without tracing. +% +% This predicate wraps around `is_compatio0/0`, using `notrace/1` +% to suppress tracing during its execution. +% +% @example +% ?- is_compatio. +% true. +is_compatio :- notrace(is_compatio0). -keep_output:- !. -keep_output:- dont_change_streams,!. -keep_output:- is_win64,!. -keep_output:- is_mettalog,!. -keep_output:- is_testing,!. +%! is_compatio0 is nondet. +% +% Base predicate for determining compatibility conditions. +% +% This predicate evaluates several conditions, each possibly +% succeeding or failing based on system flags or runtime conditions. +% +% @example +% ?- is_compatio0. +% true. -keep_output:- is_compatio,!,fail. +%is_compatio0 :- is_win64,!,fail. +is_compatio0 :- is_testing, !, fail. +is_compatio0 :- is_flag0('compatio'). +is_compatio0 :- is_mettalog, !, fail. +%is_compatio0 :- is_html,!,fail. +is_compatio0 :- !. +%! keep_output is nondet. +% +% Determines if output should be preserved based on several conditions. +% +% This predicate evaluates multiple conditions in sequence to decide +% whether output streams should remain unchanged or suppressed. +% +% @example +% ?- keep_output. +% true. +keep_output :- !. +keep_output :- dont_change_streams, !. +keep_output :- is_win64, !. +keep_output :- is_mettalog, !. +keep_output :- is_testing, !. +% fail condition +keep_output :- is_compatio, !, fail. +% +% The `volatile/1` directive indicates that the predicate should not +% be saved in a saved state of the program (e.g., when using `qsave_program/2`). +% It ensures that `original_user_output/1` is only meaningful during runtime +% and is not preserved across sessions. +% +% @example +% ?- volatile(original_user_output/1). +% true. :- volatile(original_user_output/1). + +% This directive allows the predicate `original_user_output/1` to be modified during runtime. :- dynamic(original_user_output/1). -original_user_output(X):- stream_property(X,file_no(1)). -original_user_error(X):- stream_property(X,file_no(2)). + +%! original_user_output(-X) is nondet. +% +% Retrieves the stream associated with the standard output (file descriptor 1). +% +% This predicate succeeds if `X` unifies with a stream that corresponds to the +% standard output stream, as determined by the stream property `file_no(1)`. +% +% @arg X The stream associated with standard output. +% +% @example +% ?- original_user_output(Stream). +% Stream = . +original_user_output(X) :- stream_property(X, file_no(1)). + +%! original_user_error(-X) is nondet. +% +% Retrieves the stream associated with the standard error (file descriptor 2). +% +% This predicate succeeds if `X` unifies with a stream that corresponds to the +% standard error stream, as determined by the stream property `file_no(2)`. +% +% @arg X The stream associated with standard error. +% +% @example +% ?- original_user_error(Stream). +% Stream = . +original_user_error(X) :- stream_property(X, file_no(2)). + +% Ensure that the original output stream is set if not already defined. :- original_user_output(_)->true;(current_output(Out),asserta(original_user_output(Out))). -unnullify_output:- current_output(MFS), original_user_output(OUT), MFS==OUT, !. -unnullify_output:- original_user_output(MFS), set_prolog_IO(user_input,MFS,user_error). -null_output(MFS):- dont_change_streams,!, original_user_output(MFS),!. -null_output(MFS):- use_module(library(memfile)), - new_memory_file(MF),open_memory_file(MF,append,MFS). +%! unnullify_output is det. +% +% Restores the output stream to its original state. +% +% If the current output stream matches the original user output, the predicate +% succeeds immediately. Otherwise, it restores the output stream to the value +% stored in `original_user_output/1`. +% +% @example +% ?- unnullify_output. +% true. +unnullify_output :- + current_output(MFS), + original_user_output(OUT), + MFS == OUT, + !. +unnullify_output :- + original_user_output(MFS), + set_prolog_IO(user_input, MFS, user_error). + +%! null_output(-MFS) is det. +% +% Sets the output stream to a memory file stream. +% +% If `dont_change_streams/0` succeeds, the original user output is preserved. +% Otherwise, a new memory file is created and used as the output stream. +% +% @arg MFS The memory file stream set as the output. +% +% @example +% ?- null_output(Stream). +% Stream = . +null_output(MFS) :- dont_change_streams, !, original_user_output(MFS), !. +null_output(MFS) :- use_module(library(memfile)),new_memory_file(MF),open_memory_file(MF, append, MFS). + +% Ensure `null_user_output/1` is not preserved in saved states (e.g., with qsave_program/2). :- volatile(null_user_output/1). + +% Allow `null_user_output/1` to be modified dynamically at runtime. :- dynamic(null_user_output/1). -:- null_user_output(_)->true;(null_output(MFS), - asserta(null_user_output(MFS))). +% Initialize `null_user_output/1` with a memory file stream if it is not already defined. +:- null_user_output(_) -> true ; (null_output(MFS), asserta(null_user_output(MFS))). + +%! nullify_output is det. +% +% Redirects the output stream to a memory file. +% +% If `keep_output/0` or `dont_change_streams/0` succeed, the predicate does nothing. +% Otherwise, it calls `nullify_output_really/0` to set up the memory file stream. +% +% @example +% ?- nullify_output. +% true. +nullify_output :- keep_output, !. +nullify_output :- dont_change_streams, !. +nullify_output :- nullify_output_really. -nullify_output:- keep_output,!. -nullify_output:- dont_change_streams,!. -nullify_output:- nullify_output_really. -nullify_output_really:- current_output(MFS), null_user_output(OUT), MFS==OUT, !. -nullify_output_really:- null_user_output(MFS), set_prolog_IO(user_input,MFS,MFS). +%! nullify_output_really is det. +% +% Forces the output stream to be redirected to a memory file. +% +% If the current output matches `null_user_output/1`, the predicate succeeds. +% Otherwise, it switches to the memory file stream defined in `null_user_output/1`. +% +% @example +% ?- nullify_output_really. +% true. +nullify_output_really :- current_output(MFS), null_user_output(OUT), MFS == OUT, !. +nullify_output_really :- null_user_output(MFS), set_prolog_IO(user_input, MFS, MFS). + +%! set_output_stream is det. +% +% Configures the output stream based on current conditions. +% +% If `dont_change_streams/0` is true, no changes are made. +% Otherwise, the stream is either nullified or restored, depending on `keep_output/0`. +% +% @example +% ?- set_output_stream. +% true. +set_output_stream :- dont_change_streams, !. +set_output_stream :- \+ keep_output -> nullify_output; unnullify_output. -set_output_stream :- dont_change_streams,!. -set_output_stream :- \+ keep_output -> nullify_output; unnullify_output. +% Initialize the output stream configuration at startup. :- set_output_stream. % :- nullify_output. -switch_to_mettalog:- - unnullify_output, - set_option_value('compatio',false), - set_option_value('compat',false), - set_option_value('load',show), - set_option_value('load',verbose), - set_option_value('log',true), - %set_option_value('test',true), - forall(mettalog_option_value_def(Name, DefaultValue),set_option_value(Name, DefaultValue)), - set_output_stream. - -switch_to_mettarust:- - nullify_output, - set_option_value('compatio',true), - set_option_value('compat',true), - set_option_value('log',false), - set_option_value('test',false), - forall(rust_option_value_def(Name, DefaultValue),set_option_value(Name, DefaultValue)), - set_output_stream. - +%! switch_to_mettalog is det. +% +% Switches the system configuration to the `mettalog` mode. +% +% This predicate adjusts several runtime options specific to the +% `mettalog` mode, including output stream configuration and option values. +% It ensures the system behaves according to the `mettalog` runtime settings. +% +% @example +% ?- switch_to_mettalog. +% true. +switch_to_mettalog :- + unnullify_output, + set_option_value('compatio', false), + set_option_value('compat', false), + set_option_value('load', show), + set_option_value('load', verbose), + set_option_value('log', true), + %set_option_value('test', true), + forall(mettalog_option_value_def(Name, DefaultValue), set_option_value(Name, DefaultValue)), + set_output_stream. +%! switch_to_mettarust is det. +% +% Switches the system configuration to the `mettarust` mode. +% +% This predicate adjusts several runtime options specific to the +% `mettarust` mode, including output stream configuration and option values. +% It ensures the system behaves according to the `mettarust` runtime settings. +% +% @example +% ?- switch_to_mettarust. +% true. +switch_to_mettarust :- + nullify_output, + set_option_value('compatio', true), + set_option_value('compat', true), + set_option_value('log', false), + set_option_value('test', false), + forall(rust_option_value_def(Name, DefaultValue), set_option_value(Name, DefaultValue)), + set_output_stream. show_os_argv:- is_compatio,!. show_os_argv:- current_prolog_flag(os_argv,ArgV),write('; libswipl: '),writeln(ArgV).