:load clause-splitting (review #5): #9
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "clause-splitting-and-list"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
boundaries — a bare . end-token, mapped back to a byte offset via the
tokenizer's line/(byte-)col. So floats (3.14), quoted-atom dots ('a.b'),
comments, and 0'. never cause a false split. Comment/whitespace-only spans are
dropped; comments ride with the clause that follows.
file), then appends each clause as an individual ordered entry. load_file uses
it and reports loaded (N clause(s)).
dot, quoted-atom dot, multi-line clauses, comment-only spans).
:list:
continuation lines aligned:
1 parent(tom, bob).
2 parent(bob, ann).
3 :- dynamic(extra/1).
4 ancestor(X, Y) :- parent(X, Y).
5 ancestor(X, Y) :-
parent(X, Z),
ancestor(Z, Y).
The verification compiled exactly that kind of file (facts + :- dynamic
directive + multi-line rule) and ?- ancestor(tom, X) returned X = bob / X = ann
— confirming the split entries recompile faithfully.
Net effect: the session buffer is now a genuinely ordered clause buffer as the
design intended, which is the shared groundwork the remaining : commands
(per-clause edit/retract, and the session-predicate completion follow-up #3)
will build on.
- New session::split_clauses reuses the real tokenizer to find clause boundaries — a bare . end-token, mapped back to a byte offset via the tokenizer's line/(byte-)col. So floats (3.14), quoted-atom dots ('a.b'), comments, and 0'. never cause a false split. Comment/whitespace-only spans are dropped; comments ride with the clause that follows. - Session::load_source validates the whole file once (one clean error for a bad file), then appends each clause as an individual ordered entry. load_file uses it and reports loaded <path> (N clause(s)). - 6 unit tests pin the tricky cases (ordering, directives as own clauses, float dot, quoted-atom dot, multi-line clauses, comment-only spans). :list: - Now that the buffer holds individual clauses, it renders them numbered, with continuation lines aligned: 1 parent(tom, bob). 2 parent(bob, ann). 3 :- dynamic(extra/1). 4 ancestor(X, Y) :- parent(X, Y). 5 ancestor(X, Y) :- parent(X, Z), ancestor(Z, Y). The verification compiled exactly that kind of file (facts + :- dynamic directive + multi-line rule) and ?- ancestor(tom, X) returned X = bob / X = ann — confirming the split entries recompile faithfully. Net effect: the session buffer is now a genuinely ordered clause buffer as the design intended, which is the shared groundwork the remaining : commands (per-clause edit/retract, and the session-predicate completion follow-up #3) will build on.Review —
:loadclause splittingClean targeted fix for issue #5 from the earlier review. Reusing the real tokenizer (instead of regex/string-split) is the right call: floats, quoted-atom dots, line comments, and
0'.all fall out for free because the tokenizer already handled them.:listrendering is now genuinely useful. Tests pin the tricky cases.Correctness
The
byte_offsettranslation works because the tokenizer is byte-indexed:colbumps once per byte (mod.rs:76) and resets to 1 on\n(mod.rs:74), which matches the byte-walk inbyte_offset. The+ 1after the dot's byte offset (to include the.in the slice) is correct —Dotis one byte.Whole-file validation before append is the right semantics: a malformed file leaves the buffer untouched and reports one error.
Small observations
1.
add_clausenow diverges fromload_sourcefor multi-clause single entries. If a user pastesfoo. bar.at the prompt and presses Enter,add_clauseparses it (the program parser accepts many clauses) and pushes one entry containing both.:listwill show one numbered line spanning two clauses — the same shape this PR fixed for:load. Not in scope here; obvious follow-up is to routeadd_clausethroughsplit_clausestoo.2. Missing test for block comments. The tokenizer handles
/* ... */inskip_whitespace, but the tests only cover%line comments. Worth one test thatp. /* between */ q.splits cleanly into["p.", "/* between */ q."](block comment rides with the following clause), and especially thatp(/* . */ x).does NOT split on the inner dot. Defends against a future tokenizer change that drops comment handling.3. Missing test for
0'.The doc comment explicitly calls this out as safe, but nothing asserts it. A one-line test (foo(X) :- X = 0'..) keeps the claim honest.4. Unreachable tokenize-fail fallback.
split_clausesreturnsvec![src.trim().to_string()]ifTokenizer::tokenizefails — butload_sourcecallsparse_program_with_directivesfirst, which would have errored out. The path is dead in the only caller. Eithervec![]orunreachable!("validated before split")would document the invariant.5.
:listwidth caps at 3 digits."{:>3}"misaligns past 999 clauses. Pedantic; fine in practice.What's good
:loadReady to merge once the block-comment /
0'.tests are added (1-2 lines each). Theadd_clausefollow-up is a natural next slice.