Skip to content

feat(parse): accept explicit + sign in e-notation exponent#248

Open
thedavidmeister wants to merge 3 commits into
mainfrom
feat/issue-214-positive-exponent-sign
Open

feat(parse): accept explicit + sign in e-notation exponent#248
thedavidmeister wants to merge 3 commits into
mainfrom
feat/issue-214-positive-exponent-sign

Conversation

@thedavidmeister

@thedavidmeister thedavidmeister commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Summary

  • LibParseDecimalFloat.parseDecimalFloatInline now accepts an optional explicit + sign after e/E (e.g. 1e+2, 1.0e+2), treating it identically to the implicit positive case (1e2)
  • + with no following digits still rejects with MalformedExponentDigits (same as 1e-)
  • Adds CMASK_PLUS_SIGN import from rain-string

Addresses rainlanguage/rainlang#214.

Deploy required: source change moves the decimal-float bytecode → testDeployAddress, testExpectedCodeHashDecimalFloat, and testArtifactsCommitted are red pending a manual-sol-artifacts.yaml run on this branch with suite=decimal-float.

Test plan

  • New testParseLiteralDecimalFloatPositiveExponentSign — 9 positive cases
  • New testParseLiteralDecimalFloatPositiveENoDigits1e+ and 0.0e+ still reject
  • Existing testParseLiteralDecimalFloatExponents — 505 total tests pass (8 expected failures: 5 fork/RPC, 3 bytecode-pin pre-deploy)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Decimal float parsing now accepts an explicit + sign in exponents, so values like 1e+2 are handled correctly.
    • Inputs with a + but no exponent digits still fail with the expected error.
  • Tests
    • Added coverage for positive exponent signs and malformed exponent cases, including cursor-position checks.

`1e+2`, `1.0e+2`, `1E+2` etc. now parse identically to `1e2`.
`1e+` with no digits still rejects with MalformedExponentDigits.

Fixes rainlanguage/rainlang#214.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@thedavidmeister thedavidmeister self-assigned this Jul 3, 2026
@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@thedavidmeister, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 29 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 643ac03f-96b8-4474-b837-9b786095a446

📥 Commits

Reviewing files that changed from the base of the PR and between 6429749 and bef4e86.

📒 Files selected for processing (2)
  • crates/float/abi/DecimalFloat.json
  • src/lib/deploy/LibDecimalFloatDeploy.sol

Walkthrough

This PR extends LibParseDecimalFloat to accept an optional explicit + sign immediately after the exponent marker (e/E) in decimal float literals, mirroring existing support for -. Tests are added covering acceptance of e+ variants and the MalformedExponentDigits failure when no digits follow.

Changes

Positive Exponent Sign Support

Layer / File(s) Summary
Exponent sign parsing
src/lib/parse/LibParseDecimalFloat.sol
Imports CMASK_PLUS_SIGN and updates exponent parsing to detect and skip an optional + after e/E, adjusting eStart so digit parsing starts correctly.
Exponent sign tests
test/src/lib/parse/LibParseDecimalFloat.t.sol
Adds tests confirming e+ parses equivalently to e across several inputs, and that + without following digits reverts with MalformedExponentDigits.

Estimated code review effort: 1 (Trivial) | ~5 minutes

Related PRs: None identified.

Suggested labels: enhancement, tests

Suggested reviewers: None identified.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: accepting an explicit plus sign in exponent notation.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/issue-214-positive-exponent-sign

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/lib/parse/LibParseDecimalFloat.sol (1)

141-151: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Mixed -/+ exponent signs silently mis-parsed instead of rejected.

The new + check runs unconditionally after the - skip, without verifying that no negative sign was already consumed. For input like "1e-+2":

  • Line 145 skips the -, advancing cursor to point at +.
  • Line 148 then matches + at that position, advances cursor past it, and overwrites eStart to point at 2 — discarding the previously consumed - entirely.
  • The exponent parses as +2 instead of being rejected, silently dropping the sign that was present in the input.

Previously (before this PR) "1e-+2" failed with MalformedExponentDigits because + is not a digit. Now it succeeds with an incorrect (wrong-sign) exponent value. This is a real regression for a decimal-float parser that presumably feeds downstream numeric/financial logic.

🐛 Proposed fix: only accept `+` when no `-` was already consumed
                 uint256 eStart = cursor;
-                cursor = LibParseChar.skipMask(cursor, end, CMASK_NEGATIVE_SIGN);
-                // Skip an optional explicit positive sign (e.g. 1e+2). Advance
-                // eStart past it so the int parser only sees the digit string.
-                if (LibParseChar.isMask(cursor, end, CMASK_PLUS_SIGN) == 1) {
-                    cursor++;
-                    eStart = cursor;
-                }
+                uint256 cursorBeforeSign = cursor;
+                cursor = LibParseChar.skipMask(cursor, end, CMASK_NEGATIVE_SIGN);
+                // Skip an optional explicit positive sign (e.g. 1e+2), but only
+                // if a negative sign was not already consumed above. Advance
+                // eStart past it so the int parser only sees the digit string.
+                if (cursor == cursorBeforeSign && LibParseChar.isMask(cursor, end, CMASK_PLUS_SIGN) == 1) {
+                    cursor++;
+                    eStart = cursor;
+                }

Please add test cases for "1e-+2" and "0.0e-+1" asserting MalformedExponentDigits (or another rejection), to lock in the correct behavior.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/parse/LibParseDecimalFloat.sol` around lines 141 - 151, The
exponent-sign handling in LibParseDecimalFloat.parseDecimalFloat currently
accepts a plus sign even after a minus has already been consumed, which lets
mixed signs like 1e-+2 slip through. Update the exponent parsing logic around
the eValue/cursor/eStart block so the optional CMASK_PLUS_SIGN is only
recognized when no CMASK_NEGATIVE_SIGN was skipped, and otherwise leave the
parser to fail with MalformedExponentDigits. Add regression tests covering 1e-+2
and 0.0e-+1 to ensure mixed signs are rejected.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/lib/parse/LibParseDecimalFloat.sol`:
- Around line 141-151: The exponent-sign handling in
LibParseDecimalFloat.parseDecimalFloat currently accepts a plus sign even after
a minus has already been consumed, which lets mixed signs like 1e-+2 slip
through. Update the exponent parsing logic around the eValue/cursor/eStart block
so the optional CMASK_PLUS_SIGN is only recognized when no CMASK_NEGATIVE_SIGN
was skipped, and otherwise leave the parser to fail with
MalformedExponentDigits. Add regression tests covering 1e-+2 and 0.0e-+1 to
ensure mixed signs are rejected.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 12c3e737-fa22-481d-a6a1-9aceddbfddd3

📥 Commits

Reviewing files that changed from the base of the PR and between 774ed07 and 6429749.

📒 Files selected for processing (2)
  • src/lib/parse/LibParseDecimalFloat.sol
  • test/src/lib/parse/LibParseDecimalFloat.t.sol

thedavidmeister and others added 2 commits July 3, 2026 17:05
Regenerate DecimalFloat.json artifact after adding explicit + sign
support in e-notation exponent parsing.

Co-Authored-By: Claude <noreply@anthropic.com>
…[3b-attempt]

ZOLTU_DEPLOYED_DECIMAL_FLOAT_ADDRESS and DECIMAL_FLOAT_CONTRACT_HASH are
now set to the values computed from this PR's bytecode (explicit + sign
in e-notation exponent changes source). Computed by testDeployAddress
and testExpectedCodeHashDecimalFloat failure output:
address: 0x9b0eF7FbDF04b3A58989860Dea0534C978d64464
hash: 0x369ac78d686dfdf1d41771dc7bf321dcd339b0a454dc9cf6c37eff579c3a0c3a

Co-Authored-By: Claude <noreply@anthropic.com>
@thedavidmeister

Copy link
Copy Markdown
Contributor Author

Producer note: WAITING-DEPLOY. Deploy constants now regenerated to this PR's bytecode (testDeployAddress/testExpectedCodeHash pass); the remaining red is the 5 testProdDeployment* network pins ('DecimalFloat not deployed') — same condition as main, needs the routine interactive pre-merge Zoltu deploy from this branch, not a code fix.

@thedavidmeister

Copy link
Copy Markdown
Contributor Author

🤖 ai:producer
Producer note: state change on the reds. Beyond the 5 WAITING-DEPLOY prod pins (unchanged), rainix-sol/static and rs-static now fail on the no-skips gate: test/src/lib/deploy/LibDecimalFloatDeployTaggedConstants.t.sol:24 vm.skip(true). That line is IDENTICAL on current main (774ed07) — a pre-existing main red from the newly tightened rainix no-skip rule, not this PR's diff, so no fix belongs here. Org-level collision, also hitting raindex (#2779, same pattern on raindex main): the no-skip gate vs the established SKIP-on-registry-unreachable FFI pattern needs a human ruling (allowlist the pattern in the gate, or restructure the tagged-constants tests org-wide).

@thedavidmeister thedavidmeister added the ai:reject AI vetter: needs rework (code issue) label Jul 6, 2026
@thedavidmeister

thedavidmeister commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

🤖 ai:vetter
Reviewed bef4e86: reject — missing/false QA evidence: no QA-GUIDE section-8 block in body or comments; plus-sign exponent parse
cost 420 — exponent-sign parse change plus artifact regen

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai:reject AI vetter: needs rework (code issue)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant