Repository navigation
Conversation
The REPL's incomplete-input scanner tracked quotes and bracket depth but had no notion of regex literals or comments, so a quote, backtick, or bracket inside a regex body (x = /hello "world/;) was counted as code and forced a bogus continuation prompt. Skip regex bodies (using the previous significant token to tell a regex start from division, with character-class and escape handling) and // and /* */ comments. An unterminated /* */ comment now continues instead of erroring. Fixes #37326
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughThe REPL continuation scanner now recognizes regex literals and ignores comments when checking for incomplete input. Regression tests cover regex syntax, division, JSX, invalid patterns, and comment handling. ChangesREPL continuation detection
Suggested reviewers: Pre-merge checks:
|
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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.
Inline comments:
In `@src/runtime/cli/repl.rs`:
- Around line 2612-2623: Update the regex scan loop around the escape handling
in the REPL parser so a backslash immediately before a newline cannot advance
past the newline and continue scanning. Guard the b'\\' case against the
end-of-line boundary, while preserving escaped-character handling for
non-newline bytes and the existing in_class delimiter logic.
In `@test/js/bun/repl/repl.test.ts`:
- Around line 720-724: Add two REPL tests alongside the existing regex
character-class case: one covering an escaped slash inside the regex body and
another covering an unbalanced “{” or “(” inside the regex body. Assert each
evaluates successfully with the expected result and exits cleanly, exercising
the scanner’s escaped-character and delimiter-counter branches.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 6ca3794d-e5c1-4eff-b025-ff801798ec43
📒 Files selected for processing (2)
src/runtime/cli/repl.rstest/js/bun/repl/repl.test.ts
Also cover escaped slashes and unbalanced braces/parens inside regex bodies in the tests.
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/runtime/cli/repl.rs (1)
2579-2606: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy liftTrack token context instead of only the previous byte.
is_incomplete_codemisclassifies valid JavaScript. It treats regex delimiters as ordinary code inconst value = 10 / /[(]/.test("(");andif (true) /[(]/.test("(");, counts the(inside[(], and requests continuation. Inobj.in / {, it treats propertyinas a keyword, skips{, and evaluates incomplete input.Track token kinds and syntactic context. Distinguish division from regex, property names from keywords, and control-statement closers from expression closers. Add regression cases in
test/js/bun/repl/repl.test.ts, then runbun bd test test/js/bun/repl/repl.test.ts.🤖 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/runtime/cli/repl.rs` around lines 2579 - 2606, Update is_incomplete_code to track token kinds and syntactic context rather than only the previous byte, distinguishing regex literals from division, property names from REGEX_KEYWORDS, and control-statement closers from expression closers. Ensure regex contents such as [(] are skipped without affecting delimiter balance, and obj.in / { is treated as valid input rather than incomplete. Add regression cases to repl.test.ts and run the specified test command.
🤖 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/runtime/cli/repl.rs`:
- Around line 2579-2606: Update is_incomplete_code to track token kinds and
syntactic context rather than only the previous byte, distinguishing regex
literals from division, property names from REGEX_KEYWORDS, and
control-statement closers from expression closers. Ensure regex contents such as
[(] are skipped without affecting delimiter balance, and obj.in / { is treated
as valid input rather than incomplete. Add regression cases to repl.test.ts and
run the specified test command.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 893f513c-2cc8-413d-acb0-7e9814ebb0e2
📒 Files selected for processing (2)
src/runtime/cli/repl.rstest/js/bun/repl/repl.test.ts
…, and division operands A / right after an if/for/while/with condition's closing paren now reads as a regex, a property access like obj.in no longer counts as the in keyword, and a regex can follow a division operator.
|
Addressed the review's misclassification cases in 9a67d3a: a / right after an if/for/while/with condition's closing paren now starts a regex (tracked with a small paren stack), a property access like obj.in no longer matches the keyword list, and a regex can follow a division operator (10 / /[(]/.test("(")). Tests added for all three. I stopped short of a full token tracker: this function is a continuation hint, not a parser, and the remaining ambiguities (for example postfix ++ before /) degrade to the pre-existing behavior rather than breaking evaluation. |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/runtime/cli/repl.rs (2)
2581-2606: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy liftTrack postfix operators in regex detection.
x++ / "unterminatedis reported as complete becauseb'+'starts regex scanning. Track token kind and expression-start context instead of only the previous byte. Add regression tests for postfix++and--followed by division and an unterminated string.🤖 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/runtime/cli/repl.rs` around lines 2581 - 2606, Update the regex-detection logic around starts_regex to track token kind and whether the current expression context permits a regex, so postfix ++ and -- are treated as operators on the preceding expression rather than regex-starting bytes. Ensure division after postfix operators is parsed correctly and add regression coverage for ++/-- followed by division containing an unterminated string.
2559-2570: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winHandle ECMAScript whitespace and line terminators in
is_incomplete_code.
LineEditorpreserves raw UTF-8 input. The scanner recognizes only ASCII whitespace and LF. Therefore// comment\u2028{hides{, andreturn\u00A0/hello "world/is not recognized as a complete regex literal. Decode UTF-8 before classification and recognize the complete ECMAScript whitespace and line-terminator sets. Add regression tests.🤖 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/runtime/cli/repl.rs` around lines 2559 - 2570, Update is_incomplete_code to decode the raw UTF-8 input before scanning, and classify the full ECMAScript whitespace and line-terminator sets rather than only ASCII whitespace and LF; ensure line comments terminate on all recognized ECMAScript line terminators so hidden syntax such as U+2028 is scanned correctly, and add regression tests covering these cases.Source: Coding guidelines
🤖 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/runtime/cli/repl.rs`:
- Around line 2581-2606: Update the regex-detection logic around starts_regex to
track token kind and whether the current expression context permits a regex, so
postfix ++ and -- are treated as operators on the preceding expression rather
than regex-starting bytes. Ensure division after postfix operators is parsed
correctly and add regression coverage for ++/-- followed by division containing
an unterminated string.
- Around line 2559-2570: Update is_incomplete_code to decode the raw UTF-8 input
before scanning, and classify the full ECMAScript whitespace and line-terminator
sets rather than only ASCII whitespace and LF; ensure line comments terminate on
all recognized ECMAScript line terminators so hidden syntax such as U+2028 is
scanned correctly, and add regression tests covering these cases.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: bf39b0ab-4d20-4b38-b06f-36b66221a641
📒 Files selected for processing (1)
src/runtime/cli/repl.rs
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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.
Inline comments:
In `@test/js/bun/repl/repl.test.ts`:
- Around line 767-770: Update the test “regex after a conditional's closing
paren” so the first REPL input contains the observable expression itself, then
submit “.exit” as the next input instead of “x”. Assert that the stripped output
does not contain “SyntaxError”, ensuring the test distinguishes correct one-line
evaluation from unintended multiline continuation.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 999fca0c-623d-4cd6-8c9b-a8be45eb3059
📒 Files selected for processing (2)
src/runtime/cli/repl.rstest/js/bun/repl/repl.test.ts
… context A / after doubled +/- (postfix operator) or after a } inside parens or brackets (object literal) is division, not a regex start.
|
Latest round addressed in ef1f3ae: a / after postfix ++/-- or after a } inside parens/brackets (object literal) now reads as division, with tests for both. On the full ECMAScript whitespace and line-terminator sets (U+2028, U+00A0, etc.): declining for this heuristic. The scanner is a byte-level continuation hint over terminal input, the pre-existing code was ASCII-only in the same way, and a miss degrades to an extra continuation prompt or an immediate syntax error from the real parser, both recoverable. Decoding UTF-8 here would add complexity out of proportion to inputs a terminal user can realistically type. |
…literals as division context An adjacent </ is a JSX closing tag (the REPL parses TSX), x! ends an expression, } inside a brace body is an object literal, and a method named if/for/while/with does not make its call parens a regex context.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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.
Inline comments:
In `@src/runtime/cli/repl.rs`:
- Around line 2597-2603: Update the scanner’s brace handling around starts_regex
to maintain a stack recording whether each `{` begins a statement block or
object literal, and classify `}` using its matching entry. Set after_block only
for closing statement blocks, so division after an assigned object literal is
not treated as a regex; add a continuation regression covering `q = {} / ({`.
In `@test/js/bun/repl/repl.test.ts`:
- Around line 767-775: Ensure each affected REPL test proves one-line evaluation
by including its observable expression in the initial input and submitting only
.exit afterward: in test/js/bun/repl/repl.test.ts lines 767-775, include q for
both increment/decrement cases; lines 777-781, include q for the object-literal
division; lines 783-787, include g(); lines 789-793, include q; and lines
803-807, include q for the method-call case. Preserve the existing assertions
while preventing multiline continuation from producing the expected value.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 543149cb-90ef-4f86-97c7-278d8e220cfd
📒 Files selected for processing (2)
src/runtime/cli/repl.rstest/js/bun/repl/repl.test.ts
Track whether each { opens in statement or expression position, so a /
after an object literal's } is division while a / after a block's } can
still start a regex.
(84 as void / 2) is division; void /re/ keeps its regex operand.
Map<Array<T>, string> and Record<K, V[]> walk their argument run, including inner closers and brackets, back to a word-adjacent <.
(x as string | void / 2) and (x as void! / 2) are division; | void /re/ and void /re/ keep their regex operands.
|
CI status: 189 of 190 jobs pass. The one red lane (debian 13 x64-asan) fails only on test/js/node/worker_threads/worker-transfer-list.test.ts, an unchecked-exception assert in the module loader that this PR's REPL-only diff does not touch; it has been reported separately as a main-side break. Everything else that flaked passed on retry. The diff is ready for review. |
Record<string, A & B> walks & like |.
|
#39622 proposed a second fix for #37326 in the same function. It is now closed in favor of this PR. Both branches merge cleanly into current main. One difference for the record: #39622 also made |
…inal Each new case feeds complete lines and stops at the end of the input. A line that the continuation scan takes for an open string or bracket swallows every line after it, so each case asserts the output of every line. - An apostrophe in a line comment, a brace in a block comment, and a paren in a regex character class do not hold back the lines after them. - On a terminal, the prompt stays "> " after a comment with an apostrophe. - .load and .editor evaluate their text whole. Two guards pin that. - Five shapes that the scan still misjudges are todo tests. Each has a comment with the output it gives now. The division tests with several cases now feed all of their cases to one REPL session. The debug build ran up to seven sessions in sequence for one test and exceeded the 5 s timeout.
|
I measured this branch against main and Node 26.3, and added the measured rows as tests in fb553e4. Setup
Fed by a pipe, then end of input
On a terminal
Every row above is right on this branch. Shapes that are still wrong
The first three never worked. The last two are the limits that the description names: they work on main, and this change breaks them. A quote or a bracket in JSX text, for example Tests in fb553e4 (
What the real parser says
If that direction is preferred to the byte scan, I can rework this PR to it. The tests here carry over. |
|
Relation to #46105 (JSX in The test A form that holds on both sides: run those rows in a temp directory with a stand-in runtime (as Two JSX shapes of the continuation check that show once JSX evaluates. Both are the same on 1.4.3:
|
…ers are words The nested is_word_char duplicated is_word_byte without its >= 0x80 arm, so (café! / 2) read the bang as a prefix and swallowed the closing paren.
Fixes #37326
Problem
bun replshows...for a complete line when a regex or a comment holds a quote or a bracket (x = /hello "world/;,// don't). Fed by a pipe, it swallows every later line and exits 0.is_incomplete_code(src/runtime/cli/repl.rs:3010). It counts quotes and brackets by bytes and does not know regex literals or comments.Fix
/decides between a regex and a division./hello (world/reports its SyntaxError at once.test/js/bun/repl/repl.test.ts. Main fails 23 of 167 tests, this branch passes all. The measured table matches Node 26.3 in every row.Background
is_incomplete_code. On true, it shows...and waits for more lines.transform_for_replalready runs on every input. "Wait when the first parse error is at the end of the input" is right for 27 of 29 buffers. A maintainer decides.Downsides
//in JSX text ((<a>https://x</a>)) waits for more input, andfunction () {} / (runs before its next line.foo(]. All five are todo tests.(or a{costs 1 or 2 heap allocations (main: 0). The function grows from 691 to 8228 bytes.Notes
What decides regex or division. The scan keeps the last significant byte and the identifier that ends at it, plus small context trackers:
if/for/while/with, andfor await), so a/after their)starts a regex/after a block}starts a regex and a/after an object}divides++,--and!obj.in,this.#in)</a.b>,</my-el>,</a >)A<B<T>>) andas/satisfiestype positionsAn unclosed block comment continues to the next line.
Tests. The continuation block of
test/js/bun/repl/repl.test.tshas 38 tests and 5 todo tests. Two more tests run on a terminal. On main (release build 367d939, whoserepl.rsis identical to c1df64b), 22 of the 38 fail, and so does the terminal test for the prompt. The.loadand.editortests are guards: they pass on main and here.The five todo shapes, and what each prints now.
var t = `${'`'}`; t: no output. The backtick in the string ends the template for the scan. Wrong on main too.var u = "abc: no output. Node reports the SyntaxError at once. Wrong on main too.foo(]: no output. Node reports the SyntaxError at once. Wrong on main too.(<a>https://x</a>): no output.//x</a>)reads as a line comment. Main evaluates the line.q = function () {} / (then2): two SyntaxErrors. The/after the function body reads as a regex start. Main printsNaN.A quote or a bracket in JSX text, for example
(<a>don't</a>), is wrong on main and here.Parser probe.
new Bun.Transpiler({ loader: "tsx" }).transformSync(code)on 29 buffers. The rule: wait for more input when the parse fails and the offset of the first error is the end of the input. For 26 plain JS buffers, the rule makes the same choice as Node 26.3 in 24. The 3 JSX and TypeScript buffers also come out right. The two misses are an unterminated template and a string that ends with a backslash. Both reportUnterminated string literalat the start of the token.How the costs were measured.
rustc -C opt-level=3 -C codegen-units=1 -C panic=abort --emit=obj, thensize. Main: 691 bytes. This branch: 8228 bytes (text 7820, data 408).(and no{, 1 for a line with one of them, 2 for a line with both. More than 8 open levels of one kind add a reallocation.perfandvalgrindare not installed in the build container.no test proof · iteration 5 · Platform-specific test(s) that do not run on this machine. Deferring to CI, which covers all platforms: test/js/bun/repl/repl.test.ts