Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,29 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.1.5] - 2025-12-22

### Fixed

- **CutFailure Propagation Through Repetitions**
- Fixed CutFailure not propagating through repetitions (ZeroOrMore, OneOrMore, Optional, Repetition)
- Previously, repetitions would treat CutFailure as "end of repetition" and succeed with partial results
- Now CutFailure correctly propagates up, preventing silent backtracking after commit
- Fixes issue where parse errors were reported at wrong positions (e.g., start of class instead of actual error)

- **CutFailure Propagation Through Choices**
- CutFailure now propagates through Choice rules instead of being converted to regular Failure
- Enables cuts in nested rules to affect parent rule behavior correctly

- **Word Boundary Checks in Grammars with Cuts**
- Added word boundary checks (`![a-zA-Z0-9_$]`) before cuts in type declarations
- Prevents false commits when keyword is prefix of identifier (e.g., `record` in `recordResult`)

- **Error Position Tracking in Generated Parsers (ADVANCED mode)**
- Fixed `trackFailure()` not being called in generated match methods
- Error positions now correctly report the furthest position reached before failure
- Previously, `furthestFailure` was always null causing fallback to current position after backtracking

## [0.1.4] - 2025-12-21

### Added
Expand Down
6 changes: 3 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ Sum <- Number '+' Number { return (Integer)$1 + (Integer)$2; }
- [x] Advanced error recovery with Rust-style diagnostics
- [x] Generated parser ErrorReporting (BASIC/ADVANCED) for optional Rust-style diagnostics
- [x] Cut operator (^/↑) - commits to current choice, prevents backtracking
- [x] 252 passing tests
- [x] 268 passing tests

### Remaining Work
- [ ] Performance optimization
Expand Down Expand Up @@ -280,7 +280,7 @@ error: unexpected input
### Recovery Points
Parser recovers at: `,`, `;`, `}`, `)`, `]`, newline

## Test Coverage (252 tests)
## Test Coverage (268 tests)

### Grammar Parser Tests (14 tests)
- Simple rules, actions, sequences, choices
Expand Down Expand Up @@ -403,6 +403,6 @@ The `Keyword` rule should only include hard keywords. Contextual keywords are ma

```bash
mvn compile # Compile
mvn test # Run tests (252 passing)
mvn test # Run tests (268 passing)
mvn verify # Full verification
```
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ A PEG (Parsing Expression Grammar) parser library for Java, inspired by [cpp-peg
<dependency>
<groupId>org.pragmatica-lite</groupId>
<artifactId>peglib</artifactId>
<version>0.1.4</version>
<version>0.1.5</version>
</dependency>
```

Expand Down Expand Up @@ -330,7 +330,7 @@ public sealed interface CstNode {

```bash
mvn compile # Compile
mvn test # Run tests (252 tests)
mvn test # Run tests (268 tests)
mvn verify # Full verification
```

Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>org.pragmatica-lite</groupId>
<artifactId>peglib</artifactId>
<version>0.1.4</version>
<version>0.1.5</version>
<packaging>jar</packaging>

<name>Peglib</name>
Expand Down
262 changes: 192 additions & 70 deletions src/main/java/org/pragmatica/peg/generator/ParserGenerator.java

Large diffs are not rendered by default.

19 changes: 18 additions & 1 deletion src/main/java/org/pragmatica/peg/parser/PegEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -1039,7 +1039,7 @@ private ParseResult parseChoiceWithMode(ParsingContext ctx, Expression.Choice ch
return result;
}
}
// CutFailure prevents trying other alternatives - return immediately
// CutFailure prevents trying other alternatives - propagate it up
if (result instanceof ParseResult.CutFailure) {
return result;
}
Expand Down Expand Up @@ -1082,6 +1082,10 @@ private ParseResult parseZeroOrMoreWithMode(ParsingContext ctx, Expression.ZeroO
result = parseExpressionWithMode(ctx, zom.expression(), ruleName, mode);
}

// CutFailure must propagate - don't just break
if (result instanceof ParseResult.CutFailure) {
return result;
}
if (result.isFailure()) {
ctx.restoreLocation(beforeLoc);
break;
Expand Down Expand Up @@ -1144,6 +1148,10 @@ private ParseResult parseOneOrMoreWithMode(ParsingContext ctx, Expression.OneOrM
result = parseExpressionWithMode(ctx, oom.expression(), ruleName, mode);
}

// CutFailure must propagate - don't just break
if (result instanceof ParseResult.CutFailure) {
return result;
}
if (result.isFailure()) {
ctx.restoreLocation(beforeLoc);
break;
Expand Down Expand Up @@ -1178,6 +1186,11 @@ private ParseResult parseOptionalWithMode(ParsingContext ctx, Expression.Optiona
return result;
}

// CutFailure must propagate - don't treat as success
if (result instanceof ParseResult.CutFailure) {
return result;
}

// Optional always succeeds - return empty node on no match
ctx.restoreLocation(startLoc);
var span = SourceSpan.at(startLoc);
Expand Down Expand Up @@ -1218,6 +1231,10 @@ private ParseResult parseRepetitionWithMode(ParsingContext ctx, Expression.Repet
result = parseExpressionWithMode(ctx, rep.expression(), ruleName, mode);
}

// CutFailure must propagate - don't just break
if (result instanceof ParseResult.CutFailure) {
return result;
}
if (result.isFailure()) {
ctx.restoreLocation(beforeLoc);
break;
Expand Down
Loading