Skip to content

Commit af38843

Browse files
committed
Fix: Reject list literals before || operator
Addresses feedback from @triska about [_]||Rs being incorrectly accepted. The double bar operator should only work with double-quoted string literals, not arbitrary list constructs. This commit: - Removes Term::Cons validation case (was accepting any list) - Only allows Term::CompleteString and Term::PartialString - Simplifies push_binary_op to handle only string terms - Removes unused replace_list_tail function - Documents invalid cases in test file Invalid cases now correctly rejected: - [1,2,3]||K => syntax_error - [_]||Rs => syntax_error - K||[] => syntax_error (already worked) - ("a")||[] => syntax_error (already worked) All valid string cases still work: - "abc"||K => [a,b,c|K] - "a"||"b"||"c" => [a,b,c] - ""||K => K
1 parent ce86030 commit af38843

File tree

2 files changed

+17
-27
lines changed

2 files changed

+17
-27
lines changed

src/parser/parser.rs

Lines changed: 7 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -314,23 +314,6 @@ impl<'a, R: CharRead> Parser<'a, R> {
314314
}
315315
}
316316

317-
fn replace_list_tail(&self, list: Term, new_tail: Term) -> Term {
318-
match list {
319-
Term::Cons(cell, head, tail) => {
320-
match *tail {
321-
Term::Literal(_, Literal::Atom(atom)) if atom == atom!("[]") => {
322-
Term::Cons(cell, head, Box::new(new_tail))
323-
}
324-
_ => {
325-
let replaced_tail = self.replace_list_tail(*tail, new_tail);
326-
Term::Cons(cell, head, Box::new(replaced_tail))
327-
}
328-
}
329-
}
330-
_ => list,
331-
}
332-
}
333-
334317
fn get_term_name(&mut self, td: TokenDesc) -> Option<Atom> {
335318
match td.tt {
336319
TokenType::HeadTailSeparator => Some(atom!("|")),
@@ -354,20 +337,17 @@ impl<'a, R: CharRead> Parser<'a, R> {
354337
if let Some(arg1) = self.terms.pop() {
355338
let term = if name == atom!("||") {
356339
match arg1 {
357-
Term::CompleteString(_, s) => {
340+
Term::CompleteString(_, s) | Term::PartialString(_, s, _) => {
358341
if s.is_empty() {
342+
// Empty string collapses: ""||K => K
359343
arg2
360344
} else {
345+
// Create/extend partial string: "abc"||K => [a,b,c|K]
361346
Term::PartialString(Cell::default(), s, Box::new(arg2))
362347
}
363348
}
364-
Term::Cons(_, _, _) => {
365-
self.replace_list_tail(arg1, arg2)
366-
}
367-
Term::Literal(_, Literal::Atom(atom)) if atom == atom!("[]") => {
368-
arg2
369-
}
370349
_ => {
350+
// Should never reach here due to validation, but handle gracefully
371351
Term::Clause(Cell::default(), name, vec![arg1, arg2])
372352
}
373353
}
@@ -1098,12 +1078,12 @@ impl<'a, R: CharRead> Parser<'a, R> {
10981078
}
10991079
}
11001080

1101-
// Check that the last term is a string or code list
1081+
// Check that the last term is a string literal (CompleteString or PartialString)
1082+
// NOT arbitrary lists like [1,2,3] or variables
11021083
let is_valid = if let Some(last_term) = self.terms.last() {
11031084
match last_term {
11041085
Term::CompleteString(_, _) => true,
1105-
Term::Cons(_, _, _) => true,
1106-
Term::Literal(_, Literal::Atom(atom)) if *atom == atom!("[]") => true,
1086+
Term::PartialString(_, _, _) => true,
11071087
_ => false,
11081088
}
11091089
} else {

src/tests/double_bar.pl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,13 @@
6363
"c",
6464
L = [a,b,c]
6565
)).
66+
67+
% Note: These invalid cases are tested at parse time, not runtime
68+
% They cannot be included as test/2 predicates because they fail at read_term
69+
% The parser correctly rejects them with syntax_error(incomplete_reduction)
70+
%
71+
% Invalid cases (verified separately):
72+
% - [1,2,3]||K => syntax_error
73+
% - [_]||Rs => syntax_error
74+
% - K||[] => syntax_error
75+
% - ("a")||[] => syntax_error

0 commit comments

Comments
 (0)