Comparing addresses of function pointers is brittle.
Functions may be duplicated resulting in function pointers to the same function to compare !=.
Functions may be merged/de-duplicated resulting in function pointers to different function to compare ==.
The later shouldn't be relevant here as the function differ in behavior, but mentioning it for completeness.
With it when using multiple Machine in one process only the first would store the pre-allocated error.
Instead Heap.resource_err_loc is now Option<NonZero<usize>> instead of usize using None for uninitialized.
The cell at index 0 should alredy be used by a runtime reserved interstitial cell that is allocated prior. So requiring the offset to be non zero should be fine.
- reserve the complete required length at the beginning to reduce reallocations
- use u8 instead of char so that we can re-use the allocation for the string
The -t flag is not limited to arity 0 predicates - it accepts any
goal including goals with arguments (e.g., -t 'halt(1)'). Updated
the help text to remove the incorrect "(arity 0 predicate)" constraint.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Per maintainer feedback, switches must come before files to follow
the convention: switches before files are Scryer-specific, switches
after files are application-specific.
The custom_toplevel.pl unit tests were trivial and didn't actually test
the functionality. All real testing is done via comprehensive CLI tests
in tests/scryer/cli/src_tests/custom_toplevel.md
- Add dynamic directive in toplevel.pl with other module-level directives
- Update test files to reference it as '':g_caused_exception/2
- Remove redundant dynamic directives from test files
- All tests passing
Following TESTING_GUIDE.md, added tests at layers 2 and 3:
Layer 2 - Prolog Integration Tests (src/tests/custom_toplevel.pl):
- Test that g_caused_exception/2 is not asserted when no exception occurs
- Test that g_caused_exception/2 can be checked from custom toplevel
- Added check_for_exception/0 helper predicate for testing
Layer 3 - CLI Tests (tests/scryer/cli/src_tests/custom_toplevel.md):
- Test g_caused_exception/2 with exception thrown
- Test g_caused_exception/2 with no exception
- Test g_caused_exception/2 with error/2 terms
- Added test helper predicates in fixtures/toplevel_test_helper.pl
All tests pass successfully.
Co-Authored-By: J.J.'s Robot <jjtolton@gmail.com>
When a goal throws an exception during initialization (-g flag), the
system now asserts g_caused_exception(Goal, Exception) in the user
module. This allows custom toplevels (-t flag) to check if an error
occurred and handle it appropriately.
Example usage:
scryer-prolog -g "throw(error)" -t check_error
Where check_error can be:
:- dynamic(g_caused_exception/2).
check_error :-
( g_caused_exception(_, E) ->
write('Error: '), write(E), nl, halt(1)
; halt(0)
).
This enables scripts to use custom toplevels for sophisticated error
handling and exit code logic.
Addresses: https://github.com/mthom/scryer-prolog/pull/3147#issuecomment-3503875719
Co-Authored-By: J.J.'s Robot <jjtolton@gmail.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>
- 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>
- 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
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>