Skip to content

feat(octal escapes): add support for octal escapes in quoted literals; update parsing, tests, and docs#323

Closed
nlothian wants to merge 27 commits into
mainfrom
306-support-octal-escape-sequences-in-quoted-literals
Closed

feat(octal escapes): add support for octal escapes in quoted literals; update parsing, tests, and docs#323
nlothian wants to merge 27 commits into
mainfrom
306-support-octal-escape-sequences-in-quoted-literals

Conversation

@nlothian

@nlothian nlothian commented Dec 5, 2025

Copy link
Copy Markdown
Owner

Closes #306

  • Implement octal escape parsing in PrologTransformer:

    • Add _parse_octal_escape to validate and convert octal sequences like \101\ to the corresponding character.
    • Raise syntax errors on invalid digits or overflow (>255).
  • Update string unescaping:

    • Process octal escapes before standard escapes in _unescape_string.
    • Use a placeholder for handling backslashes to preserve intent.
  • Adjust grammar/parsing cache:

    • Change grammar key construction to cache by the built grammar object (grammar = self._build_grammar(operators); key = grammar) instead of using operators tuple.
  • Extend string regex to support octal escapes:

    • Update STRING rules to allow octal escapes inside both single- and double-quoted literals.
  • Tests added for octal escapes:

    • New TestOctalEscapes with cases for single/double quotes, 1- to 3-digit octals, embedded octals, max value 377 (255), invalid digits, missing terminator, overflow, and empty escapes.
  • Documentation updates:

    • docs/FEATURES.md: note octal escapes in quoted strings.
    • docs/GRAMMAR_COMPARISON.md: reflect compatibility and behavior of octal escapes.
    • docs/SYNTAX_NOTES.md: document octal escapes in Vibe-Prolog syntax notes.
  • Overall effect:

    • Enables proper parsing and representation of octal escapes within quoted literals, aligns tests and docs with new capability, and fixes grammar caching behavior to avoid inconsistencies.

nlothian and others added 12 commits December 5, 2025 17:10
… and ellipsis ... support; update tokenizer, tests, and docs

- Relax dot-as-atom rule: stop rejecting a bare '.' as an atom inside expressions; rely on clause-terminator handling for syntax
- Improve tokenizer: introduce ends_with_range_and_dot heuristic to correctly distinguish range expressions (e.g., 1..9) from decimal points
- Add tests: new TestDotAndRangeOperator suite covering dot-as-atom, quoted dot, range operator parsing in various contexts (lists, parentheses, CLP(Z)-style constraints, tokenizer behavior)
- Update docs: document new features (dot as atom in expressions, range operator .., ellipsis ...) in FEATURES.md
- Ensure parsing preserves range/ellipsis patterns in tokenization and AST construction
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
…ly-handles-after-numbers' of github.com:nlothian/Vibe-Prolog into 311-parser-fails-on-19-range-syntax-tokenizer-incorrectly-handles-after-numbers
…ly-handles-after-numbers' of github.com:nlothian/Vibe-Prolog into 311-parser-fails-on-19-range-syntax-tokenizer-incorrectly-handles-after-numbers
…; update parsing, tests, and docs

- Implement octal escape parsing in PrologTransformer:
  - Add _parse_octal_escape to validate and convert octal sequences like \101\ to the corresponding character.
  - Raise syntax errors on invalid digits or overflow (>255).

- Update string unescaping:
  - Process octal escapes before standard escapes in _unescape_string.
  - Use a placeholder for handling backslashes to preserve intent.

- Adjust grammar/parsing cache:
  - Change grammar key construction to cache by the built grammar object (grammar = self._build_grammar(operators); key = grammar) instead of using operators tuple.

- Extend string regex to support octal escapes:
  - Update STRING rules to allow octal escapes inside both single- and double-quoted literals.

- Tests added for octal escapes:
  - New TestOctalEscapes with cases for single/double quotes, 1- to 3-digit octals, embedded octals, max value 377 (255), invalid digits, missing terminator, overflow, and empty escapes.

- Documentation updates:
  - docs/FEATURES.md: note octal escapes in quoted strings.
  - docs/GRAMMAR_COMPARISON.md: reflect compatibility and behavior of octal escapes.
  - docs/SYNTAX_NOTES.md: document octal escapes in Vibe-Prolog syntax notes.

- Overall effect:
  - Enables proper parsing and representation of octal escapes within quoted literals, aligns tests and docs with new capability, and fixes grammar caching behavior to avoid inconsistencies.
@nlothian nlothian linked an issue Dec 5, 2025 that may be closed by this pull request
@nlothian nlothian added nac Nick's Autocoder used: https://github.com/nlothian/autocoder kilocode labels Dec 5, 2025

@kilo-code-bot kilo-code-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No Issues Found

5 files reviewed | Confidence: 95% | Recommendation: Merge

Review Details

Files: parser.py (core implementation), test_parser_strings.py (comprehensive tests), docs/FEATURES.md, docs/GRAMMAR_COMPARISON.md, docs/SYNTAX_NOTES.md (documentation updates)

Checked: Security, correctness, error handling, test coverage, documentation

Implementation Notes:

  • Octal escape parsing correctly validates digits, range (≤255), and termination
  • Grammar updated to support octal escapes in quoted literals
  • String unescaping processes octal escapes before standard escapes
  • Comprehensive test coverage including edge cases (invalid digits, overflow, missing terminator)
  • Documentation properly updated across all relevant files

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces excellent support for octal escapes in quoted literals, complete with thorough tests and documentation updates. The change to improve grammar caching is also a valuable fix. I've identified a critical issue in the updated regex for strings that could break existing functionality, along with a few medium-severity suggestions to improve code style, clarity, and test specificity. Overall, this is a great contribution.

Comment thread vibeprolog/parser.py Outdated
CHAR_CODE.5: /0'(\\x[0-9a-zA-Z]+\\?|\\\\|\\\\['tnr]|''|[^'\\])'?/ | /[1-9]\d*'.'/

STRING: /"([^"\\]|\\.)*"/ | /'(\\.|''|[^'\\])*'/
STRING: /"([^"\\]|\\[^"]*)*"/ | /'([^'\\]|\\[^']*|'' )*'/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

There appears to be a typo in the updated STRING regex for single-quoted atoms. The '' (with a space) requires a space after a doubled single-quote escape, which is not standard Prolog syntax and will break atom quoting like 'it''s'. This should be '' without the trailing space.

Suggested change
STRING: /"([^"\\]|\\[^"]*)*"/ | /'([^'\\]|\\[^']*|'' )*'/
STRING: /"([^"\\]|\\[^"]*)*"/ | /'([^'\\]|\\[^']*|'')*'/

Comment thread vibeprolog/parser.py Outdated
Comment on lines +594 to +602
if not all(c in '01234567' for c in inner):
raise PrologThrow(PrologError.syntax_error("invalid octal escape", "escape_sequence/1"))
try:
value = int(inner, 8)
if value > 255:
raise PrologThrow(PrologError.syntax_error("octal escape overflow", "escape_sequence/1"))
return chr(value)
except ValueError:
raise PrologThrow(PrologError.syntax_error("invalid octal escape", "escape_sequence/1"))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The explicit check if not all(c in '01234567' for c in inner): is redundant. The int(inner, 8) call within the try block will raise a ValueError if inner contains non-octal digits, which is already handled by the except block. You can simplify the code by removing the explicit if check and relying on the try...except to handle invalid digits.

Suggested change
if not all(c in '01234567' for c in inner):
raise PrologThrow(PrologError.syntax_error("invalid octal escape", "escape_sequence/1"))
try:
value = int(inner, 8)
if value > 255:
raise PrologThrow(PrologError.syntax_error("octal escape overflow", "escape_sequence/1"))
return chr(value)
except ValueError:
raise PrologThrow(PrologError.syntax_error("invalid octal escape", "escape_sequence/1"))
try:
value = int(inner, 8)
if value > 255:
raise PrologThrow(PrologError.syntax_error("octal escape overflow", "escape_sequence/1"))
return chr(value)
except ValueError:
raise PrologThrow(PrologError.syntax_error("invalid octal escape", "escape_sequence/1"))

Comment thread vibeprolog/parser.py Outdated

# First, temporarily replace \\ with a placeholder
# First, handle octal escapes
import re

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This import re is redundant as re is already imported at the top of the file (line 3). According to PEP 8, imports should be at the top of the file. Please remove this line.

References
  1. PEP 8 recommends that imports are always put at the top of the file, just after any module comments and docstrings, and before module globals and constants. (link)

Comment thread tests/test_parser_strings.py Outdated
Comment on lines +384 to +385
with pytest.raises(Exception): # Should raise PrologThrow with syntax_error
parser.parse(r"test('\8\').")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Catching the generic Exception is too broad and can mask other unexpected errors. The test should be more specific by catching PrologThrow, which is the exception type raised by the parser for syntax errors. You will need to add from vibeprolog.exceptions import PrologThrow to the imports at the top of the file.

Suggested change
with pytest.raises(Exception): # Should raise PrologThrow with syntax_error
parser.parse(r"test('\8\').")
with pytest.raises(PrologThrow): # Should raise PrologThrow with syntax_error
parser.parse(r"test('\8\').")

Comment thread tests/test_parser_strings.py Outdated
Comment on lines +397 to +398
with pytest.raises(Exception): # Should raise PrologThrow with syntax_error
parser.parse(r"test('\400\').")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Similar to the other test, catching Exception is too broad. Please catch the more specific PrologThrow to make the test more robust. You will need to add from vibeprolog.exceptions import PrologThrow to the imports at the top of the file.

Suggested change
with pytest.raises(Exception): # Should raise PrologThrow with syntax_error
parser.parse(r"test('\400\').")
with pytest.raises(PrologThrow): # Should raise PrologThrow with syntax_error
parser.parse(r"test('\400\').")

…rovements

- Tests
  - Change tests to expect PrologThrow for syntax errors instead of a generic Exception.
  - Add explicit import from vibeprolog.exceptions import PrologThrow at test file tops.
  - Update invalid/octal cases to use pytest.raises(PrologThrow).
  - Retain tests asserting correct behavior for valid octal escapes and edge cases.

- Parser
  - Correct single-quoted atom STRING regex to /'([^'\\]|\\[^']*|'')*'/ so that it handles embedded quotes properly.
  - Implement _parse_octal_escape(match) to parse octal escapes, raising PrologThrow on invalid digits or overflow (>255).
  - Simplify octal parsing by removing the redundant explicit digit-check and relying on ValueError for invalid digits.
  - Integrate _parse_octal_escape into the string unescaping flow to properly handle octal escapes.
  - Remove the redundant local import re line (re is already imported at the top); ensure imports remain at the top of the file.
  - Ensure PrologThrow is imported from vibeprolog.exceptions where needed.

@kilo-code-bot kilo-code-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewing the octal escapes implementation.

@kilo-code-bot kilo-code-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ 2 Issues Found

Severity Issue Location
WARNING Test exception catching too broad in invalid digit test tests/test_parser_strings.py:385
WARNING Test exception catching too broad in overflow test tests/test_parser_strings.py:398

Recommendation: Address warning issues for better test specificity

Review Details (2 files)

Files: parser.py, tests/test_parser_strings.py (2 issues)

Previous critical issue (regex typo) resolved.
Previous medium issues (redundant check, import) resolved.
Remaining: Test exception handling should catch PrologThrow specifically instead of generic Exception.

nlothian and others added 7 commits December 6, 2025 17:26
Keep helpful comment from HEAD about dots being valid atoms in expression context,
while maintaining all functional code from both branches.

Amp-Thread-ID: https://ampcode.com/threads/T-753fe86b-c448-47a9-914d-c40db2805ebb
Co-authored-by: Amp <amp@ampcode.com>
…ntax-tokenizer-incorrectly-handles-after-numbers

feat(parser): allow dot as atom in expressions; add range operator .. and ellipsis ... support; update tokenizer, tests, and docs
Parse statements individually to prevent parser hangs
…e tests to expect PrologThrow

- vibeprolog/parser.py
  - Change STRING regex to:
    STRING: /"([^"\\]|\\[^"]*)*"/ | /'([^'\\]|\\[^']*|'')*'/
  - Add _parse_octal_escape(self, match) to parse octal escapes and raise PrologThrow on syntax_error or overflow
  - Use _parse_octal_escape within _unescape_string; remove redundant explicit octal-digit check
  - Remove redundant local import re; ensure re is imported at the top
  - Process octal escapes before other escapes

- tests/test_parser_strings.py
  - Add: from vibeprolog.exceptions import PrologThrow
  - Update tests to catch PrologThrow instead of Exception for octal-escape errors:
    - test_octal_escape_invalid_digit
    - test_octal_escape_overflow

@kilo-code-bot kilo-code-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No New Issues

Changes since last review look good.

…; update parsing, tests, and docs

- Implement octal escape parsing in PrologTransformer:
  - Add _parse_octal_escape to validate and convert octal sequences like \101\ to the corresponding character.
  - Raise syntax errors on invalid digits or overflow (>255).

- Update string unescaping:
  - Process octal escapes before standard escapes in _unescape_string.
  - Use a placeholder for handling backslashes to preserve intent.

- Adjust grammar/parsing cache:
  - Change grammar key construction to cache by the built grammar object (grammar = self._build_grammar(operators); key = grammar) instead of using operators tuple.

- Extend string regex to support octal escapes:
  - Update STRING rules to allow octal escapes inside both single- and double-quoted literals.

- Tests added for octal escapes:
  - New TestOctalEscapes with cases for single/double quotes, 1- to 3-digit octals, embedded octals, max value 377 (255), invalid digits, missing terminator, overflow, and empty escapes.

- Documentation updates:
  - docs/FEATURES.md: note octal escapes in quoted strings.
  - docs/GRAMMAR_COMPARISON.md: reflect compatibility and behavior of octal escapes.
  - docs/SYNTAX_NOTES.md: document octal escapes in Vibe-Prolog syntax notes.

- Overall effect:
  - Enables proper parsing and representation of octal escapes within quoted literals, aligns tests and docs with new capability, and fixes grammar caching behavior to avoid inconsistencies.
…rovements

- Tests
  - Change tests to expect PrologThrow for syntax errors instead of a generic Exception.
  - Add explicit import from vibeprolog.exceptions import PrologThrow at test file tops.
  - Update invalid/octal cases to use pytest.raises(PrologThrow).
  - Retain tests asserting correct behavior for valid octal escapes and edge cases.

- Parser
  - Correct single-quoted atom STRING regex to /'([^'\\]|\\[^']*|'')*'/ so that it handles embedded quotes properly.
  - Implement _parse_octal_escape(match) to parse octal escapes, raising PrologThrow on invalid digits or overflow (>255).
  - Simplify octal parsing by removing the redundant explicit digit-check and relying on ValueError for invalid digits.
  - Integrate _parse_octal_escape into the string unescaping flow to properly handle octal escapes.
  - Remove the redundant local import re line (re is already imported at the top); ensure imports remain at the top of the file.
  - Ensure PrologThrow is imported from vibeprolog.exceptions where needed.
…e tests to expect PrologThrow

- vibeprolog/parser.py
  - Change STRING regex to:
    STRING: /"([^"\\]|\\[^"]*)*"/ | /'([^'\\]|\\[^']*|'')*'/
  - Add _parse_octal_escape(self, match) to parse octal escapes and raise PrologThrow on syntax_error or overflow
  - Use _parse_octal_escape within _unescape_string; remove redundant explicit octal-digit check
  - Remove redundant local import re; ensure re is imported at the top
  - Process octal escapes before other escapes

- tests/test_parser_strings.py
  - Add: from vibeprolog.exceptions import PrologThrow
  - Update tests to catch PrologThrow instead of Exception for octal-escape errors:
    - test_octal_escape_invalid_digit
    - test_octal_escape_overflow
…of github.com:nlothian/Vibe-Prolog into 306-support-octal-escape-sequences-in-quoted-literals

@kilo-code-bot kilo-code-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No New Issues

Changes since last review look good.

@nlothian

Copy link
Copy Markdown
Owner Author

Fixed in #335

@nlothian nlothian closed this Dec 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kilocode nac Nick's Autocoder used: https://github.com/nlothian/autocoder

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support octal escape sequences in quoted literals

1 participant