-
Notifications
You must be signed in to change notification settings - Fork 157
Add -t flag for custom toplevel (replaces --halt-on-error) #3147
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
2402a21 to
ccc2ff1
Compare
Updated BLEEDING.md and README.md to document the new --always-halt flag that was added alongside --halt-on-error in PR mthom#3147. Changes to BLEEDING.md: - Expanded section for PR mthom#3147 to cover both flags - Added behavior comparison table showing all scenarios - Added practical examples for CI/CD, Makefiles, and batch processing - Clarified the problem both flags solve Changes to README.md: - Updated PR mthom#3147 description to mention both flags - Added example showing combined usage The --always-halt flag solves the common problem of programs dropping into the REPL after successful execution when they don't explicitly call halt/0, making Scryer fully script-safe when combined with --halt-on-error. Co-Authored-By: J.J.'s Robot <jjtolton@gmail.com>
|
Does this mean that |
No, |
|
Please see @bakaq's comment and pointer about this: #3146 (comment) |
|
Thank you a lot, can you please remove the now no longer needed intermediate commits? |
829bb22 to
c69a352
Compare
I don't mind but are we not squash merging? |
c69a352 to
006597d
Compare
- Remove --halt-on-error and --always-halt flags and environment variables - Add -t FLAG to specify custom toplevel (arity 0 predicate) - Default toplevel is 'repl' if -t is not specified - Using `-t halt` achieves original goal of guaranteed termination - Custom toplevels enable flexible exit strategies (e.g., server mode) - Update help text to document -t flag - Remove halt_on_error and always_halt from MachineArgs struct This is more elegant and flexible than the previous approach, allowing users to define their own toplevel behavior including halt, custom REPLs, or server loops. Examples: scryer-prolog -t halt program.pl # Exits after execution scryer-prolog -t my_repl program.pl # Custom REPL scryer-prolog program.pl # Default REPL Co-Authored-By: J.J.'s Robot <noreply@example.com>
- Create Prolog integration tests in src/tests/custom_toplevel.pl - Add CLI test configuration in tests/scryer/cli/src_tests/custom_toplevel_tests.toml - Tests verify: * -t halt terminates after initialization * Custom toplevels can be user-defined predicates * Toplevel receives control after initialization completes * Default behavior is REPL when no -t specified - All tests pass successfully Following TESTING_GUIDE.md three-layer testing approach: - Layer 2: Prolog integration tests with test_framework - Layer 3: CLI snapshot tests with .toml configuration Co-Authored-By: J.J.'s Robot <noreply@example.com>
Fixed issue where `scryer-prolog -t halt` would try to load "halt.pl" as a file instead of just using halt as the custom toplevel. The bug was caused by an extra clause `delegate_task([], []).` that would return control to the calling context instead of continuing to start_toplevel. This caused the argument processing in delegate_task to continue and treat the already-consumed toplevel argument as a filename. Removing this clause ensures that delegate_task([], Goals0) always proceeds to load initialization files and start the toplevel, fixing the double-processing bug. Co-Authored-By: J.J.'s Robot <jjtolton@gmail.com>
006597d to
d56f604
Compare
Thank you a lot! Individual git commits tend to be meaningfully separated, combining them ignores information that is otherwise present, and adding unrelated commits makes other operations (such as tracing the development history) harder. |
|
Is there some way for the toplevel (-t) to tell whether an initialisation goal (-g) failed so that it can exit with a different exit code in case of failure. Something like alt_repl :- successful_init -> halt ; halt(1). |
|
Maybe a good topic for a separate PR? |
|
I would be happy to include it here as my entire purpose for this was "halt on error", and knowing if the exit code was non-zero is important. With -t halt, it works but the exit code is always 0. |
Summary
Update: After discussion and reading comments in the PR thread, I've been persuaded that
-tis an overall more flexible and elegant solution. This PR now implements a custom toplevel flag instead of the original--halt-on-errorand--always-haltflags.This PR adds a
-t GOALflag that allows users to specify a custom toplevel predicate to run instead of the default REPL. This provides a more flexible and Prolog-idiomatic solution to the original problem of preventing scripts from hanging.Motivation
Problem: Shell Scripts Get Stuck
Shell scripts using Scryer Prolog can get stuck waiting for user input when errors occur or when programs complete without calling
halt/0:Scenario 1: Errors drop into REPL
Scenario 2: Programs without explicit halt drop into REPL
This is problematic in CI/CD pipelines, automated testing, cron jobs, Docker containers, and batch processing.
Solution: Custom Toplevel with
-tThe
-tflag allows you to specify any arity-0 predicate as the toplevel:Basic usage - exit instead of REPL:
scryer-prolog -t halt my_script.pl # Exits with code 0 after loading, never enters REPLWith goals:
Custom exit codes:
scryer-prolog -t my_toplevel my_script.pl # Custom logic for exit behaviorWhy
-tis BetterCompared to the original
--halt-on-error/--always-haltapproach:Changes
Modified Files
src/toplevel.plcustom_toplevel/1dynamic predicategather_toplevel/2to process-tflag argumentsstart_toplevel/0to check for custom toplevel or default to REPL-tflag-targument was incorrectly processed as a filenamesrc/tests/custom_toplevel.pl(new)-t haltbehaviortests/scryer/cli/src_tests/custom_toplevel_tests.toml(new)-t haltprevents REPL entryUsage Examples
Basic Usage
In CI/CD Pipeline
Custom Toplevel Logic
In Makefile
Testing
All tests pass, including:
✅ Comprehensive Prolog integration tests in
src/tests/custom_toplevel.pl✅ CLI tests in
tests/scryer/cli/src_tests/custom_toplevel_tests.toml✅
-t haltexits cleanly without entering REPL✅
-t custom_predicatecalls user-defined predicates✅ Custom toplevels can set exit codes via
halt/1✅
-ggoals work correctly with-tflag✅ Files are loaded before custom toplevel is invoked
✅ Bug fix:
-targument no longer incorrectly processed as filenameRelated
Resolves #3146
Implementation Notes
The implementation uses a dynamic predicate
custom_toplevel/1that is set during argument processing. Thestart_toplevel/0predicate checks for a custom toplevel and calls it usinguser:call/1, otherwise defaults to the standard REPL.This approach is clean, efficient, and follows Prolog conventions for customizing REPL behavior.
Co-Authored-By: J.J.'s Robot jjtolton@gmail.com