Skip to content

Follow gawk's backslash rules in sub()/gsub() replacement text - #616

Merged
bertysentry merged 3 commits into
mainfrom
fix/614-gsub-gawk-backslash-rules
Oct 8, 2026
Merged

bertysentry merged 3 commits into
mainfrom
fix/614-gsub-gawk-backslash-rules

Conversation

@bertysentry

Copy link
Copy Markdown
Contributor

Closes #614

Problem

In the replacement text of sub() and gsub(), Jawk applied the POSIX backslash rules (\\ is a single literal backslash) in every mode. gawk's default mode follows its own documented rules ("Gory details" in the gawk manual): \\\& is a literal \&, \\\\ a literal \\, \\& a literal backslash followed by the match, and any other backslash is kept as is, so \\ stays \\. The gawk backgsub compatibility test encodes that rule and failed in mvn verify.

Verified against gawk 5, gawk --posix and mawk in WSL on 15 replacement strings; gawk --posix and mawk agree with each other and with Jawk's previous behavior.

Change

  • sub() and gsub() follow gawk's rules by default and the POSIX ones under --posix, in line with the project policy of emulating gawk's documented behavior.
  • The switch reaches the runtime through a new JRT.setPosix(), set by AVM from the settings, next to the existing sink and stream setters.
  • JRT.prepareReplacement() is split into prepareSubReplacement(String, boolean posix) and prepareGensubReplacement(String, int maxGroup): the old boolean and int overloads meant different things. gensub() keeps gawk's own rules (\N group, \\ backslash, \& ampersand, any other \c a plain c).
  • backgsub now passes; the failsafe baseline is otherwise unchanged.

Tests

  • PrepareReplacementTest: full gawk table, POSIX table, and gensub table.
  • AwkTest: one replacement string exercising all five gawk cases, run through AwkTestSupport in default mode and with --posix.
  • mvn verify: 889 unit tests pass; checkstyle, PMD and SpotBugs clean.

Docs

  • compatibility.md.vm: new bullet under "Where Jawk follows gawk".
  • cli-reference.md: --posix now mentions the replacement-text rules.
  • behavior-changes.md: two bullets under Unreleased (behavior, and the JRT API rename for embedders).

🤖 Generated with Claude Code

In the replacement text of sub() and gsub(), Jawk applied the POSIX
backslash rules (\\ is a literal backslash) in every mode. gawk's
default mode follows its own documented rules instead: \\\& is a
literal \&, \\\\ a literal \\, \\& a literal backslash followed by the
match, and any other backslash is kept as is, so \\ stays \\.

sub() and gsub() now follow gawk's rules by default and the POSIX ones
under --posix, which is what gawk --posix, mawk and One True Awk do.
The POSIX switch reaches the runtime through JRT.setPosix(), set by AVM
from the settings. gensub() keeps its own gawk rules.

JRT.prepareReplacement() is split into prepareSubReplacement(), which
takes the POSIX switch, and prepareGensubReplacement(), which takes the
highest capture group number, instead of one method whose boolean and
int overloads meant different things. The gawk backgsub compatibility
test now passes.

Closes #614

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-08T13:12:11.033931Z 6796339 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0b5425b8d2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/main/java/io/jawk/backend/AVM.java Outdated
The runtime took the sub()/gsub() backslash rules from the settings of
the AVM that runs the program. A program compiled with --posix -K and
loaded with -L, which cannot be combined with --posix, would therefore
silently switch to gawk's rules. AwkProgram now records whether it was
compiled in POSIX mode, and AVM takes the rules from the program when
it executes it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@bertysentry

Copy link
Copy Markdown
Contributor Author

@codex please review again

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4229382713

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/main/java/io/jawk/backend/AVM.java
Comment thread src/test/java/io/jawk/AwkTest.java Outdated
Expressions compiled with POSIX settings and evaluated through
Awk.eval() never reached the execute() paths that set the runtime
mode, so sub()/gsub() in them used gawk's rules. The mode now lives on
AwkTuples, the base of both AwkProgram and AwkExpression, is recorded
by both compile paths, and is applied by AVM.eval() as well.

The loaded-program test now runs through AwkTestSupport.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@bertysentry

Copy link
Copy Markdown
Contributor Author

@codex please review again

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Nice work!

Reviewed commit: 6796339fe8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@bertysentry
bertysentry merged commit d47101e into main Oct 8, 2026
5 checks passed
@bertysentry
bertysentry deleted the fix/614-gsub-gawk-backslash-rules branch October 8, 2026 18:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

sub()/gsub(): \\ in the replacement follows POSIX, not gawk's default rule

1 participant