Skip to content

Ignore leading shebang lines in the lexer#191

Merged
frostney merged 2 commits into
mainfrom
t3code/ignore-shebang-passthrough
Apr 6, 2026
Merged

Ignore leading shebang lines in the lexer#191
frostney merged 2 commits into
mainfrom
t3code/ignore-shebang-passthrough

Conversation

@frostney
Copy link
Copy Markdown
Owner

@frostney frostney commented Apr 6, 2026

Summary

  • Teach the lexer to skip an initial Unix shebang line (#!...) before tokenization starts.
  • Preserve line and column tracking so subsequent tokens still report the correct source location.
  • Add regression coverage in both JavaScript end-to-end tests and native lexer tests.
  • Document the shebang behavior in the README and build-system guide.

Testing

  • Added tests/language/shebang.js to verify scripts with a leading shebang execute normally.
  • Added units/Goccia.Lexer.Test.pas coverage for skipping the hashbang and preserving line numbers.

Summary by CodeRabbit

  • New Features

    • GocciaScript now accepts Unix shebang lines (e.g., #!/usr/bin/env goccia) at the start of source files; they are ignored during parsing so scripts can be executable.
  • Documentation

    • README and build docs updated to explain shebang handling and runtime behavior for executable scripts.
  • Tests

    • Added tests verifying shebangs are ignored and that line/column tracking remains correct after a shebang.

- Treat Unix hashbangs as comments at the start of source files
- Add lexer and end-to-end regression coverage
- Document direct script execution with shebangs
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 6, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 98ab6089-a639-4ceb-ab05-acdd5c40530a

📥 Commits

Reviewing files that changed from the base of the PR and between e2b58f7 and 32de174.

📒 Files selected for processing (1)
  • units/Goccia.Lexer.Test.pas
🚧 Files skipped from review as they are similar to previous changes (1)
  • units/Goccia.Lexer.Test.pas

📝 Walkthrough

Walkthrough

GocciaScript now accepts Unix shebang lines (e.g., #!/usr/bin/env goccia) at the start of source files. The lexer skips a leading #! line via a new SkipHashbang routine invoked before tokenization. Documentation and tests were added to reflect and verify this behavior.

Changes

Cohort / File(s) Summary
Documentation
README.md, docs/build-system.md
Documented that leading Unix shebang (#!) lines are skipped by the lexer and can be used to make scripts executable.
Lexer Implementation
units/Goccia.Lexer.pas
Added private TGocciaLexer.SkipHashbang and call to it at the start of ScanTokens, which advances past a leading #! line until a line terminator or EOF.
Tests
tests/language/shebang.js, units/Goccia.Lexer.Test.pas
Added JavaScript test asserting evaluation/parsing ignoring shebang; added Delphi lexer test suite validating hashbang skipping and preserved line/column numbering after the hashbang (covers LF and CRLF).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • Inline paths where possible #43: Touches units/Goccia.Lexer.pas and other lexer internals; likely overlaps with changes to scanning and source-line handling.

Poem

I nibbled a hashbang, then hopped away,
The lexer skipped dinner and saved the day.
Scripts run from the shell with a joyful cheer,
Lines stay true — the tokens appear. 🐇✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Ignore leading shebang lines in the lexer' directly and clearly summarizes the main change: adding lexer support to skip Unix shebang lines at the start of files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch t3code/ignore-shebang-passthrough

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 and usage tips.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 6, 2026

Benchmark Results

274 benchmarks

Interpreted: 🟢 53 improved · 🔴 203 regressed · 18 unchanged · avg -7.8%
Bytecode: 🟢 249 improved · 🔴 8 regressed · 17 unchanged · avg +9.2%

arraybuffer.js — Interp: 🟢 10, 🔴 3, 1 unch. · avg +3.6% · Bytecode: 🟢 14 · avg +11.7%
Benchmark Interpreted Δ Bytecode Δ
create ArrayBuffer(0) 456,501 ops/sec [454,722..456,662] → 488,515 ops/sec [478,349..489,690] 🟢 +7.0% 501,635 ops/sec [495,220..502,383] → 578,147 ops/sec [563,126..579,462] 🟢 +15.3%
create ArrayBuffer(64) 436,479 ops/sec [433,711..439,022] → 464,741 ops/sec [462,917..466,561] 🟢 +6.5% 478,400 ops/sec [475,443..479,173] → 552,180 ops/sec [550,678..554,726] 🟢 +15.4%
create ArrayBuffer(1024) 340,661 ops/sec [340,097..345,036] → 365,725 ops/sec [364,967..366,333] 🟢 +7.4% 368,550 ops/sec [359,349..370,642] → 428,666 ops/sec [426,997..429,061] 🟢 +16.3%
create ArrayBuffer(8192) 152,447 ops/sec [151,817..153,062] → 161,003 ops/sec [160,512..161,250] 🟢 +5.6% 159,604 ops/sec [157,599..160,330] → 185,893 ops/sec [185,762..186,032] 🟢 +16.5%
slice full buffer (64 bytes) 533,677 ops/sec [532,713..534,840] → 530,034 ops/sec [514,442..541,543] ~ overlap (-0.7%) 620,982 ops/sec [616,490..624,245] → 677,212 ops/sec [647,232..682,052] 🟢 +9.1%
slice half buffer (512 of 1024 bytes) 447,750 ops/sec [446,465..449,651] → 461,714 ops/sec [457,106..464,094] 🟢 +3.1% 525,360 ops/sec [522,160..526,478] → 579,465 ops/sec [577,769..580,753] 🟢 +10.3%
slice with negative indices 439,228 ops/sec [437,640..440,865] → 454,465 ops/sec [452,969..455,848] 🟢 +3.5% 571,408 ops/sec [566,194..573,331] → 627,698 ops/sec [624,761..630,481] 🟢 +9.9%
slice empty range 500,470 ops/sec [499,627..501,324] → 520,226 ops/sec [519,415..521,406] 🟢 +3.9% 603,002 ops/sec [601,723..604,885] → 660,768 ops/sec [660,425..661,076] 🟢 +9.6%
byteLength access 1,384,083 ops/sec [1,379,999..1,386,041] → 1,341,863 ops/sec [1,340,272..1,345,328] 🔴 -3.1% 1,608,781 ops/sec [1,600,858..1,611,829] → 1,741,614 ops/sec [1,736,438..1,743,923] 🟢 +8.3%
Symbol.toStringTag access 1,057,087 ops/sec [1,046,205..1,062,880] → 970,802 ops/sec [964,988..972,726] 🔴 -8.2% 1,120,691 ops/sec [1,117,080..1,123,166] → 1,157,741 ops/sec [1,156,456..1,158,817] 🟢 +3.3%
ArrayBuffer.isView 786,095 ops/sec [783,441..786,999] → 760,791 ops/sec [758,499..762,178] 🔴 -3.2% 884,949 ops/sec [884,104..888,238] → 942,693 ops/sec [940,601..943,266] 🟢 +6.5%
clone ArrayBuffer(64) 420,857 ops/sec [420,496..422,804] → 455,193 ops/sec [452,715..457,062] 🟢 +8.2% 475,552 ops/sec [473,926..477,500] → 536,594 ops/sec [533,071..538,148] 🟢 +12.8%
clone ArrayBuffer(1024) 326,825 ops/sec [324,212..327,407] → 357,491 ops/sec [354,655..358,030] 🟢 +9.4% 362,598 ops/sec [360,494..366,695] → 421,515 ops/sec [420,041..422,117] 🟢 +16.2%
clone ArrayBuffer inside object 264,490 ops/sec [263,506..265,171] → 292,717 ops/sec [290,101..293,871] 🟢 +10.7% 285,749 ops/sec [283,565..286,108] → 327,355 ops/sec [325,556..328,250] 🟢 +14.6%
arrays.js — Interp: 🟢 14, 🔴 2, 3 unch. · avg +2.0% · Bytecode: 🟢 19 · avg +9.1%
Benchmark Interpreted Δ Bytecode Δ
Array.from length 100 13,284 ops/sec [13,169..13,324] → 13,571 ops/sec [13,564..13,598] 🟢 +2.2% 14,960 ops/sec [14,880..15,057] → 15,879 ops/sec [15,764..16,051] 🟢 +6.1%
Array.from 10 elements 223,209 ops/sec [222,555..223,503] → 238,768 ops/sec [237,908..239,939] 🟢 +7.0% 236,863 ops/sec [236,324..236,985] → 274,421 ops/sec [274,204..274,688] 🟢 +15.9%
Array.of 10 elements 277,687 ops/sec [277,264..279,087] → 301,483 ops/sec [299,992..302,971] 🟢 +8.6% 307,132 ops/sec [305,307..309,294] → 330,204 ops/sec [329,200..331,258] 🟢 +7.5%
spread into new array 328,962 ops/sec [324,458..330,330] → 347,782 ops/sec [347,206..348,100] 🟢 +5.7% 184,029 ops/sec [183,229..185,215] → 210,824 ops/sec [209,710..211,373] 🟢 +14.6%
map over 50 elements 24,900 ops/sec [24,217..25,053] → 24,523 ops/sec [24,404..24,644] ~ overlap (-1.5%) 28,020 ops/sec [27,788..28,172] → 29,758 ops/sec [29,632..29,901] 🟢 +6.2%
filter over 50 elements 22,557 ops/sec [22,505..22,603] → 22,914 ops/sec [22,829..22,952] 🟢 +1.6% 24,350 ops/sec [24,141..24,640] → 26,953 ops/sec [26,782..27,228] 🟢 +10.7%
reduce sum 50 elements 26,097 ops/sec [25,935..26,228] → 26,331 ops/sec [26,131..26,513] ~ overlap (+0.9%) 19,763 ops/sec [19,528..19,894] → 21,128 ops/sec [21,124..21,164] 🟢 +6.9%
forEach over 50 elements 23,280 ops/sec [23,203..23,411] → 22,906 ops/sec [22,500..22,964] 🔴 -1.6% 29,209 ops/sec [29,176..29,268] → 31,147 ops/sec [30,944..31,213] 🟢 +6.6%
find in 50 elements 32,301 ops/sec [31,797..32,459] → 32,807 ops/sec [32,637..32,883] 🟢 +1.6% 32,516 ops/sec [32,399..32,519] → 33,632 ops/sec [33,137..33,681] 🟢 +3.4%
sort 20 elements 12,264 ops/sec [12,230..12,315] → 12,228 ops/sec [12,175..12,262] ~ overlap (-0.3%) 14,174 ops/sec [14,166..14,197] → 14,827 ops/sec [14,795..14,838] 🟢 +4.6%
flat nested array 113,782 ops/sec [113,263..114,228] → 117,221 ops/sec [117,035..117,723] 🟢 +3.0% 123,913 ops/sec [123,275..124,440] → 141,933 ops/sec [141,492..142,195] 🟢 +14.5%
flatMap 73,420 ops/sec [73,295..73,954] → 75,683 ops/sec [74,842..76,194] 🟢 +3.1% 80,682 ops/sec [80,315..81,331] → 90,774 ops/sec [90,432..90,916] 🟢 +12.5%
map inside map (5x5) 20,505 ops/sec [20,444..20,542] → 20,963 ops/sec [20,894..21,016] 🟢 +2.2% 22,767 ops/sec [22,620..22,903] → 25,274 ops/sec [25,120..25,427] 🟢 +11.0%
filter inside map (5x10) 15,658 ops/sec [14,106..15,705] → 15,873 ops/sec [15,867..15,887] 🟢 +1.4% 16,674 ops/sec [16,622..16,794] → 18,774 ops/sec [18,684..18,799] 🟢 +12.6%
reduce inside map (5x10) 19,277 ops/sec [19,086..19,324] → 19,420 ops/sec [19,373..19,468] 🟢 +0.7% 16,802 ops/sec [16,765..16,879] → 17,744 ops/sec [17,624..17,865] 🟢 +5.6%
forEach inside forEach (5x10) 16,810 ops/sec [16,752..16,876] → 16,475 ops/sec [16,426..16,497] 🔴 -2.0% 17,848 ops/sec [17,657..17,876] → 18,715 ops/sec [18,652..18,749] 🟢 +4.9%
find inside some (10x10) 13,239 ops/sec [13,145..13,283] → 13,519 ops/sec [13,458..13,557] 🟢 +2.1% 13,854 ops/sec [13,810..13,876] → 14,512 ops/sec [14,496..14,591] 🟢 +4.8%
map+filter chain nested (5x20) 5,126 ops/sec [5,084..5,158] → 5,195 ops/sec [5,181..5,218] 🟢 +1.3% 5,639 ops/sec [5,618..5,659] → 6,137 ops/sec [6,110..6,178] 🟢 +8.8%
reduce flatten (10x5) 38,839 ops/sec [38,611..38,903] → 39,701 ops/sec [39,629..39,756] 🟢 +2.2% 16,864 ops/sec [16,754..16,990] → 19,593 ops/sec [19,429..19,637] 🟢 +16.2%
async-await.js — Interp: 🟢 6 · avg +3.4% · Bytecode: 🟢 6 · avg +11.6%
Benchmark Interpreted Δ Bytecode Δ
single await 375,233 ops/sec [372,988..377,289] → 394,813 ops/sec [393,297..396,729] 🟢 +5.2% 400,671 ops/sec [399,501..402,310] → 453,732 ops/sec [451,647..456,784] 🟢 +13.2%
multiple awaits 171,645 ops/sec [171,360..172,300] → 178,927 ops/sec [177,982..179,507] 🟢 +4.2% 175,995 ops/sec [175,354..176,886] → 199,826 ops/sec [199,172..200,553] 🟢 +13.5%
await non-Promise value 832,323 ops/sec [830,719..835,994] → 851,000 ops/sec [848,208..854,033] 🟢 +2.2% 1,074,046 ops/sec [1,067,520..1,077,647] → 1,155,786 ops/sec [1,151,651..1,161,864] 🟢 +7.6%
await with try/catch 364,399 ops/sec [361,139..366,480] → 380,784 ops/sec [378,039..382,721] 🟢 +4.5% 396,287 ops/sec [393,460..396,870] → 441,551 ops/sec [440,329..444,633] 🟢 +11.4%
await Promise.all 51,505 ops/sec [51,113..51,852] → 52,278 ops/sec [51,988..52,390] 🟢 +1.5% 48,944 ops/sec [48,861..49,010] → 55,708 ops/sec [55,536..55,826] 🟢 +13.8%
nested async function call 192,422 ops/sec [190,811..193,625] → 197,926 ops/sec [197,735..198,985] 🟢 +2.9% 227,415 ops/sec [226,627..227,846] → 250,543 ops/sec [250,247..252,432] 🟢 +10.2%
classes.js — Interp: 🟢 14, 🔴 10, 7 unch. · avg +0.2% · Bytecode: 🟢 27, 4 unch. · avg +12.7%
Benchmark Interpreted Δ Bytecode Δ
simple class new 140,737 ops/sec [139,709..140,848] → 146,084 ops/sec [145,392..147,319] 🟢 +3.8% 204,483 ops/sec [203,490..205,722] → 225,581 ops/sec [224,791..225,886] 🟢 +10.3%
class with defaults 110,616 ops/sec [110,141..111,095] → 114,496 ops/sec [114,129..114,860] 🟢 +3.5% 142,275 ops/sec [140,671..144,778] → 155,974 ops/sec [153,438..156,968] 🟢 +9.6%
50 instances via Array.from 5,711 ops/sec [5,694..5,725] → 6,056 ops/sec [6,027..6,067] 🟢 +6.0% 7,941 ops/sec [7,920..7,943] → 8,784 ops/sec [8,745..8,797] 🟢 +10.6%
instance method call 71,896 ops/sec [71,739..72,140] → 75,452 ops/sec [75,348..75,699] 🟢 +4.9% 92,288 ops/sec [91,022..92,674] → 101,673 ops/sec [101,361..102,373] 🟢 +10.2%
static method call 115,165 ops/sec [114,379..115,263] → 121,105 ops/sec [120,501..121,701] 🟢 +5.2% 186,469 ops/sec [182,854..189,245] → 207,296 ops/sec [204,623..208,628] 🟢 +11.2%
single-level inheritance 56,507 ops/sec [56,355..56,777] → 59,941 ops/sec [59,833..60,127] 🟢 +6.1% 73,819 ops/sec [73,109..74,157] → 82,642 ops/sec [82,495..82,711] 🟢 +12.0%
two-level inheritance 48,385 ops/sec [42,005..48,606] → 52,174 ops/sec [51,782..52,392] 🟢 +7.8% 59,734 ops/sec [58,132..60,478] → 67,348 ops/sec [65,721..68,357] 🟢 +12.7%
private field access 71,781 ops/sec [71,557..72,201] → 77,373 ops/sec [77,013..77,474] 🟢 +7.8% 86,121 ops/sec [84,686..87,745] → 99,971 ops/sec [99,761..100,063] 🟢 +16.1%
private methods 80,137 ops/sec [79,652..80,265] → 83,672 ops/sec [83,429..83,852] 🟢 +4.4% 94,637 ops/sec [93,911..95,131] → 111,402 ops/sec [111,241..111,485] 🟢 +17.7%
getter/setter access 77,206 ops/sec [76,891..77,326] → 79,863 ops/sec [79,763..79,871] 🟢 +3.4% 96,222 ops/sec [95,294..97,798] → 115,296 ops/sec [115,203..115,304] 🟢 +19.8%
class decorator (identity) 94,855 ops/sec [93,752..95,068] → 96,882 ops/sec [96,025..97,212] 🟢 +2.1% 103,956 ops/sec [101,605..106,177] → 115,976 ops/sec [113,885..118,538] 🟢 +11.6%
class decorator (wrapping) 55,545 ops/sec [55,315..56,039] → 57,003 ops/sec [56,354..57,600] 🟢 +2.6% 59,223 ops/sec [56,987..60,857] → 64,663 ops/sec [62,878..67,114] 🟢 +9.2%
identity method decorator 66,320 ops/sec [65,988..66,852] → 68,632 ops/sec [67,725..69,309] 🟢 +3.5% 81,523 ops/sec [78,960..86,465] → 96,572 ops/sec [92,141..102,388] 🟢 +18.5%
wrapping method decorator 53,712 ops/sec [53,583..53,968] → 53,726 ops/sec [53,508..54,285] ~ overlap (+0.0%) 57,557 ops/sec [54,754..65,375] → 68,990 ops/sec [65,924..73,047] 🟢 +19.9%
stacked method decorators (x3) 36,003 ops/sec [35,725..36,329] → 36,795 ops/sec [36,305..37,106] ~ overlap (+2.2%) 39,639 ops/sec [38,273..43,547] → 46,210 ops/sec [43,746..48,441] 🟢 +16.6%
identity field decorator 72,444 ops/sec [71,814..72,812] → 68,216 ops/sec [68,007..68,808] 🔴 -5.8% 69,825 ops/sec [68,052..75,336] → 82,580 ops/sec [79,646..86,718] 🟢 +18.3%
field initializer decorator 60,523 ops/sec [60,236..60,590] → 60,468 ops/sec [60,263..60,970] ~ overlap (-0.1%) 66,903 ops/sec [61,919..72,480] → 71,487 ops/sec [67,533..75,270] ~ overlap (+6.9%)
getter decorator (identity) 65,962 ops/sec [65,705..66,383] → 65,715 ops/sec [65,283..66,218] ~ overlap (-0.4%) 71,455 ops/sec [69,738..74,771] → 83,335 ops/sec [81,229..85,648] 🟢 +16.6%
setter decorator (identity) 55,598 ops/sec [55,268..55,766] → 55,128 ops/sec [54,386..55,512] ~ overlap (-0.8%) 58,218 ops/sec [57,567..58,384] → 64,414 ops/sec [63,644..64,867] 🟢 +10.6%
static method decorator 71,569 ops/sec [71,228..72,196] → 71,937 ops/sec [71,251..72,729] ~ overlap (+0.5%) 75,341 ops/sec [73,759..80,341] → 93,651 ops/sec [89,244..96,584] 🟢 +24.3%
static field decorator 83,509 ops/sec [83,075..83,988] → 81,806 ops/sec [81,413..82,352] 🔴 -2.0% 80,558 ops/sec [77,693..84,692] → 88,604 ops/sec [84,754..91,893] 🟢 +10.0%
private method decorator 54,164 ops/sec [53,997..54,194] → 54,465 ops/sec [54,410..54,606] 🟢 +0.6% 67,894 ops/sec [64,749..72,155] → 83,259 ops/sec [78,031..86,840] 🟢 +22.6%
private field decorator 59,677 ops/sec [59,173..59,938] → 58,933 ops/sec [58,848..58,967] 🔴 -1.2% 57,628 ops/sec [56,656..58,047] → 60,994 ops/sec [60,434..61,178] 🟢 +5.8%
plain auto-accessor (no decorator) 103,871 ops/sec [101,698..106,062] → 99,500 ops/sec [98,736..100,535] 🔴 -4.2% 94,094 ops/sec [91,221..99,927] → 113,593 ops/sec [107,859..124,698] 🟢 +20.7%
auto-accessor with decorator 55,145 ops/sec [53,861..56,338] → 54,419 ops/sec [53,163..55,689] ~ overlap (-1.3%) 53,342 ops/sec [51,692..59,882] → 58,346 ops/sec [53,761..61,855] ~ overlap (+9.4%)
decorator writing metadata 45,437 ops/sec [45,324..45,809] → 42,303 ops/sec [41,678..42,970] 🔴 -6.9% 47,926 ops/sec [47,032..52,950] → 52,122 ops/sec [51,952..55,344] ~ overlap (+8.8%)
static getter read 129,028 ops/sec [126,014..129,861] → 117,480 ops/sec [116,886..119,160] 🔴 -9.0% 166,350 ops/sec [163,643..169,207] → 173,922 ops/sec [172,927..176,277] 🟢 +4.6%
static getter/setter pair 100,224 ops/sec [99,749..101,283] → 92,279 ops/sec [91,301..93,069] 🔴 -7.9% 119,721 ops/sec [114,901..128,111] → 128,151 ops/sec [126,860..138,059] ~ overlap (+7.0%)
inherited static getter 77,154 ops/sec [76,874..77,608] → 72,642 ops/sec [72,057..73,040] 🔴 -5.8% 94,880 ops/sec [92,260..95,594] → 100,288 ops/sec [99,512..101,118] 🟢 +5.7%
inherited static setter 83,696 ops/sec [83,141..83,792] → 78,124 ops/sec [77,516..78,385] 🔴 -6.7% 98,188 ops/sec [96,666..100,031] → 108,680 ops/sec [107,307..111,414] 🟢 +10.7%
inherited static getter with this binding 72,108 ops/sec [71,878..72,373] → 67,899 ops/sec [67,536..68,050] 🔴 -5.8% 88,162 ops/sec [87,688..89,117] → 92,748 ops/sec [91,929..94,454] 🟢 +5.2%
closures.js — Interp: 🔴 11 · avg -4.9% · Bytecode: 🟢 10, 1 unch. · avg +8.1%
Benchmark Interpreted Δ Bytecode Δ
closure over single variable 134,107 ops/sec [133,120..134,629] → 126,476 ops/sec [125,172..126,653] 🔴 -5.7% 277,416 ops/sec [276,404..279,107] → 288,579 ops/sec [285,691..291,182] 🟢 +4.0%
closure over multiple variables 119,667 ops/sec [118,662..121,248] → 111,053 ops/sec [110,617..111,528] 🔴 -7.2% 192,267 ops/sec [188,608..200,009] → 209,970 ops/sec [205,182..218,091] 🟢 +9.2%
nested closures 128,256 ops/sec [127,821..129,093] → 119,691 ops/sec [118,941..120,575] 🔴 -6.7% 225,178 ops/sec [220,452..237,711] → 236,107 ops/sec [233,669..239,772] ~ overlap (+4.9%)
function as argument 94,034 ops/sec [93,147..94,617] → 89,318 ops/sec [89,090..89,897] 🔴 -5.0% 248,961 ops/sec [248,324..250,229] → 279,560 ops/sec [279,031..280,393] 🟢 +12.3%
function returning function 118,121 ops/sec [117,477..118,957] → 114,714 ops/sec [114,575..115,007] 🔴 -2.9% 280,940 ops/sec [279,493..282,036] → 295,357 ops/sec [293,427..297,952] 🟢 +5.1%
compose two functions 71,922 ops/sec [71,642..72,280] → 68,545 ops/sec [68,374..68,749] 🔴 -4.7% 148,250 ops/sec [147,456..150,236] → 163,626 ops/sec [162,976..165,299] 🟢 +10.4%
fn.call 153,422 ops/sec [151,954..154,774] → 144,652 ops/sec [144,006..145,903] 🔴 -5.7% 233,211 ops/sec [229,558..236,546] → 240,606 ops/sec [239,789..241,403] 🟢 +3.2%
fn.apply 112,626 ops/sec [112,418..112,880] → 107,035 ops/sec [106,156..107,815] 🔴 -5.0% 156,105 ops/sec [154,613..157,566] → 164,167 ops/sec [163,430..164,900] 🟢 +5.2%
fn.bind 143,954 ops/sec [143,030..144,777] → 139,807 ops/sec [139,203..140,428] 🔴 -2.9% 277,628 ops/sec [276,747..278,477] → 308,093 ops/sec [306,913..309,904] 🟢 +11.0%
recursive sum to 50 12,331 ops/sec [12,259..12,506] → 11,756 ops/sec [11,714..11,780] 🔴 -4.7% 24,176 ops/sec [24,099..24,263] → 26,907 ops/sec [26,863..26,929] 🟢 +11.3%
recursive tree traversal 21,076 ops/sec [20,957..21,295] → 20,439 ops/sec [20,197..20,496] 🔴 -3.0% 35,337 ops/sec [35,056..35,796] → 39,881 ops/sec [39,854..39,887] 🟢 +12.9%
collections.js — Interp: 🔴 10, 2 unch. · avg -7.6% · Bytecode: 🟢 6, 🔴 5, 1 unch. · avg +0.9%
Benchmark Interpreted Δ Bytecode Δ
add 50 elements 7,355 ops/sec [7,295..7,408] → 7,131 ops/sec [7,119..7,140] 🔴 -3.1% 7,521 ops/sec [7,510..7,533] → 7,845 ops/sec [7,839..7,867] 🟢 +4.3%
has lookup (50 elements) 93,511 ops/sec [92,933..93,965] → 93,039 ops/sec [92,729..93,309] ~ overlap (-0.5%) 104,554 ops/sec [104,217..104,917] → 103,431 ops/sec [103,282..103,702] 🔴 -1.1%
delete elements 49,197 ops/sec [49,077..49,334] → 48,963 ops/sec [48,838..49,124] ~ overlap (-0.5%) 51,489 ops/sec [51,143..51,765] → 51,879 ops/sec [51,730..52,015] ~ overlap (+0.8%)
forEach iteration 16,005 ops/sec [15,912..16,116] → 15,282 ops/sec [15,260..15,350] 🔴 -4.5% 15,825 ops/sec [15,757..15,895] → 16,963 ops/sec [16,934..16,984] 🟢 +7.2%
spread to array 29,276 ops/sec [28,850..29,503] → 25,744 ops/sec [25,637..25,751] 🔴 -12.1% 211,238 ops/sec [210,644..212,545] → 241,370 ops/sec [240,567..247,358] 🟢 +14.3%
deduplicate array 39,582 ops/sec [39,424..39,834] → 35,030 ops/sec [34,839..35,142] 🔴 -11.5% 73,201 ops/sec [72,748..73,969] → 75,084 ops/sec [74,486..76,247] 🟢 +2.6%
set 50 entries 5,391 ops/sec [5,361..5,437] → 4,940 ops/sec [4,899..4,976] 🔴 -8.4% 5,932 ops/sec [5,913..5,937] → 5,783 ops/sec [5,774..5,797] 🔴 -2.5%
get lookup (50 entries) 94,624 ops/sec [94,574..94,672] → 83,696 ops/sec [83,486..83,734] 🔴 -11.5% 101,228 ops/sec [101,137..101,395] → 88,465 ops/sec [88,364..88,665] 🔴 -12.6%
has check 141,045 ops/sec [140,749..141,175] → 126,712 ops/sec [126,438..126,953] 🔴 -10.2% 155,193 ops/sec [154,842..155,473] → 138,051 ops/sec [137,950..138,204] 🔴 -11.0%
delete entries 50,522 ops/sec [49,859..50,672] → 43,730 ops/sec [43,598..43,971] 🔴 -13.4% 50,933 ops/sec [50,603..51,140] → 46,039 ops/sec [45,927..46,069] 🔴 -9.6%
forEach iteration 15,637 ops/sec [15,471..15,736] → 15,044 ops/sec [14,969..15,072] 🔴 -3.8% 15,982 ops/sec [15,883..16,138] → 17,252 ops/sec [17,234..17,307] 🟢 +7.9%
keys/values/entries 8,049 ops/sec [8,012..8,063] → 7,120 ops/sec [7,082..7,201] 🔴 -11.5% 25,196 ops/sec [24,956..25,454] → 27,797 ops/sec [27,639..28,034] 🟢 +10.3%
destructuring.js — Interp: 🔴 21, 1 unch. · avg -7.7% · Bytecode: 🟢 20, 2 unch. · avg +10.4%
Benchmark Interpreted Δ Bytecode Δ
simple array destructuring 384,729 ops/sec [383,381..388,521] → 341,738 ops/sec [340,084..342,780] 🔴 -11.2% 253,701 ops/sec [251,692..254,482] → 286,788 ops/sec [285,597..288,653] 🟢 +13.0%
with rest element 242,007 ops/sec [240,155..243,849] → 222,264 ops/sec [220,713..222,723] 🔴 -8.2% 194,394 ops/sec [194,050..195,481] → 228,351 ops/sec [226,796..230,230] 🟢 +17.5%
with defaults 377,149 ops/sec [370,801..381,205] → 334,970 ops/sec [334,428..336,750] 🔴 -11.2% 283,877 ops/sec [280,660..285,552] → 340,532 ops/sec [339,711..341,327] 🟢 +20.0%
skip elements 399,385 ops/sec [387,591..404,683] → 361,409 ops/sec [360,854..362,060] 🔴 -9.5% 266,699 ops/sec [264,078..268,120] → 315,801 ops/sec [314,619..315,987] 🟢 +18.4%
nested array destructuring 163,911 ops/sec [162,446..165,578] → 149,561 ops/sec [148,691..150,219] 🔴 -8.8% 83,349 ops/sec [82,570..84,146] → 96,278 ops/sec [95,516..96,889] 🟢 +15.5%
swap variables 482,106 ops/sec [480,383..485,453] → 451,620 ops/sec [450,147..454,477] 🔴 -6.3% 317,345 ops/sec [311,362..318,118] → 361,799 ops/sec [360,712..362,336] 🟢 +14.0%
simple object destructuring 294,380 ops/sec [293,455..298,660] → 284,574 ops/sec [283,809..285,927] 🔴 -3.3% 417,537 ops/sec [412,295..422,791] → 423,797 ops/sec [420,857..428,654] ~ overlap (+1.5%)
with defaults 339,130 ops/sec [336,078..343,506] → 321,240 ops/sec [321,017..321,625] 🔴 -5.3% 553,343 ops/sec [549,147..561,815] → 592,245 ops/sec [590,361..600,497] 🟢 +7.0%
with renaming 322,774 ops/sec [320,223..323,962] → 297,052 ops/sec [293,622..297,966] 🔴 -8.0% 440,413 ops/sec [438,342..451,594] → 461,156 ops/sec [457,097..461,429] 🟢 +4.7%
nested object destructuring 152,181 ops/sec [150,439..153,171] → 136,000 ops/sec [135,468..136,100] 🔴 -10.6% 197,503 ops/sec [194,606..198,302] → 201,717 ops/sec [200,090..203,852] 🟢 +2.1%
rest properties 179,068 ops/sec [175,498..181,476] → 177,886 ops/sec [177,410..179,078] ~ overlap (-0.7%) 182,937 ops/sec [179,929..183,993] → 201,693 ops/sec [199,932..202,201] 🟢 +10.3%
object parameter 93,031 ops/sec [92,214..93,978] → 90,678 ops/sec [90,581..90,829] 🔴 -2.5% 148,696 ops/sec [147,433..150,170] → 158,839 ops/sec [157,423..160,294] 🟢 +6.8%
array parameter 123,253 ops/sec [121,599..123,467] → 111,762 ops/sec [111,681..112,480] 🔴 -9.3% 102,037 ops/sec [100,866..103,778] → 115,746 ops/sec [115,571..116,041] 🟢 +13.4%
mixed destructuring in map 33,544 ops/sec [33,445..33,622] → 31,991 ops/sec [31,900..32,093] 🔴 -4.6% 36,527 ops/sec [36,400..37,546] → 37,467 ops/sec [37,382..37,672] ~ overlap (+2.6%)
forEach with array destructuring 63,207 ops/sec [62,696..63,570] → 55,250 ops/sec [55,203..55,605] 🔴 -12.6% 39,489 ops/sec [39,075..39,826] → 45,055 ops/sec [45,012..45,059] 🟢 +14.1%
map with array destructuring 62,490 ops/sec [62,422..62,796] → 56,022 ops/sec [55,705..56,325] 🔴 -10.4% 40,752 ops/sec [40,508..41,085] → 44,321 ops/sec [44,219..44,580] 🟢 +8.8%
filter with array destructuring 64,045 ops/sec [62,971..64,824] → 57,525 ops/sec [57,414..57,720] 🔴 -10.2% 45,102 ops/sec [44,985..45,490] → 50,501 ops/sec [50,285..50,553] 🟢 +12.0%
reduce with array destructuring 71,711 ops/sec [71,121..72,034] → 62,642 ops/sec [62,358..63,041] 🔴 -12.6% 45,117 ops/sec [44,816..45,444] → 49,332 ops/sec [49,155..49,408] 🟢 +9.3%
map with object destructuring 73,467 ops/sec [73,015..73,930] → 70,174 ops/sec [69,593..70,292] 🔴 -4.5% 90,143 ops/sec [89,316..90,596] → 96,059 ops/sec [95,248..96,935] 🟢 +6.6%
map with nested destructuring 61,318 ops/sec [61,002..61,578] → 58,883 ops/sec [58,689..59,264] 🔴 -4.0% 87,435 ops/sec [87,125..88,103] → 95,307 ops/sec [95,155..95,366] 🟢 +9.0%
map with rest in destructuring 42,147 ops/sec [41,980..42,291] → 36,738 ops/sec [36,482..37,023] 🔴 -12.8% 22,604 ops/sec [22,523..22,919] → 25,890 ops/sec [25,721..25,932] 🟢 +14.5%
map with defaults in destructuring 56,527 ops/sec [56,033..56,891] → 54,658 ops/sec [54,550..54,970] 🔴 -3.3% 66,470 ops/sec [66,187..67,012] → 71,592 ops/sec [71,429..71,808] 🟢 +7.7%
fibonacci.js — Interp: 🔴 8 · avg -7.4% · Bytecode: 🟢 8 · avg +10.6%
Benchmark Interpreted Δ Bytecode Δ
recursive fib(15) 329 ops/sec [324..331] → 307 ops/sec [307..310] 🔴 -6.5% 834 ops/sec [832..837] → 951 ops/sec [950..952] 🟢 +14.0%
recursive fib(20) 29 ops/sec [29..30] → 29 ops/sec [29..29] 🔴 -2.1% 75 ops/sec [75..75] → 86 ops/sec [86..87] 🟢 +14.7%
recursive fib(15) typed 329 ops/sec [325..331] → 318 ops/sec [315..319] 🔴 -3.4% 879 ops/sec [876..880] → 979 ops/sec [975..983] 🟢 +11.4%
recursive fib(20) typed 30 ops/sec [29..30] → 29 ops/sec [28..29] 🔴 -3.2% 79 ops/sec [79..79] → 90 ops/sec [90..90] 🟢 +13.3%
iterative fib(20) via reduce 11,839 ops/sec [11,625..12,112] → 10,645 ops/sec [10,603..10,693] 🔴 -10.1% 18,163 ops/sec [18,029..18,178] → 18,646 ops/sec [18,637..18,679] 🟢 +2.7%
iterator fib(20) 9,531 ops/sec [9,457..9,595] → 8,291 ops/sec [8,255..8,327] 🔴 -13.0% 17,917 ops/sec [17,579..18,057] → 19,744 ops/sec [19,454..20,002] 🟢 +10.2%
iterator fib(20) via Iterator.from + take 15,304 ops/sec [15,212..15,534] → 13,867 ops/sec [13,813..13,919] 🔴 -9.4% 20,638 ops/sec [20,447..20,830] → 21,301 ops/sec [21,253..21,517] 🟢 +3.2%
iterator fib(20) last value via reduce 11,397 ops/sec [11,302..11,525] → 10,119 ops/sec [10,036..10,150] 🔴 -11.2% 13,798 ops/sec [13,658..13,988] → 15,885 ops/sec [15,758..16,136] 🟢 +15.1%
for-of.js — Interp: 🔴 7 · avg -14.1% · Bytecode: 🟢 6, 1 unch. · avg +7.0%
Benchmark Interpreted Δ Bytecode Δ
for...of with 10-element array 44,665 ops/sec [44,395..44,872] → 38,519 ops/sec [38,263..38,815] 🔴 -13.8% 167,875 ops/sec [165,608..168,195] → 181,279 ops/sec [181,019..181,700] 🟢 +8.0%
for...of with 100-element array 5,146 ops/sec [5,093..5,202] → 4,375 ops/sec [4,298..4,434] 🔴 -15.0% 18,473 ops/sec [18,397..18,763] → 18,536 ops/sec [18,479..18,653] ~ overlap (+0.3%)
for...of with string (10 chars) 32,916 ops/sec [32,622..33,271] → 28,847 ops/sec [28,730..28,966] 🔴 -12.4% 86,333 ops/sec [85,322..87,555] → 92,471 ops/sec [92,314..92,629] 🟢 +7.1%
for...of with Set (10 elements) 44,275 ops/sec [44,058..44,417] → 38,521 ops/sec [38,043..38,824] 🔴 -13.0% 157,508 ops/sec [157,209..159,319] → 165,183 ops/sec [163,851..165,998] 🟢 +4.9%
for...of with Map entries (10 entries) 29,170 ops/sec [28,913..29,421] → 24,362 ops/sec [24,231..24,500] 🔴 -16.5% 26,284 ops/sec [26,075..26,648] → 29,672 ops/sec [29,570..29,766] 🟢 +12.9%
for...of with destructuring 38,895 ops/sec [38,484..39,152] → 33,533 ops/sec [33,218..33,775] 🔴 -13.8% 35,447 ops/sec [35,009..35,550] → 40,354 ops/sec [40,202..40,713] 🟢 +13.8%
for-await-of with sync array 43,277 ops/sec [42,782..43,743] → 37,165 ops/sec [36,942..37,608] 🔴 -14.1% 128,101 ops/sec [127,809..128,510] → 130,240 ops/sec [129,986..131,003] 🟢 +1.7%
helpers/bench-module.js — Interp: 0 · Bytecode: 0
Benchmark Interpreted Δ Bytecode Δ
iterators.js — Interp: 🔴 20 · avg -15.5% · Bytecode: 🟢 20 · avg +10.9%
Benchmark Interpreted Δ Bytecode Δ
Iterator.from({next}).toArray() — 20 elements 15,577 ops/sec [15,302..15,698] → 13,560 ops/sec [13,465..13,712] 🔴 -12.9% 20,134 ops/sec [19,568..20,176] → 21,989 ops/sec [21,793..22,284] 🟢 +9.2%
Iterator.from({next}).toArray() — 50 elements 6,776 ops/sec [6,416..6,835] → 5,932 ops/sec [5,924..5,951] 🔴 -12.5% 9,145 ops/sec [9,062..9,258] → 9,998 ops/sec [9,960..10,030] 🟢 +9.3%
spread pre-wrapped iterator — 20 elements 11,511 ops/sec [11,280..11,629] → 9,596 ops/sec [9,561..9,725] 🔴 -16.6% 19,404 ops/sec [19,231..19,516] → 20,942 ops/sec [20,833..21,282] 🟢 +7.9%
Iterator.from({next}).forEach — 50 elements 4,647 ops/sec [4,600..4,677] → 4,003 ops/sec [3,994..4,030] 🔴 -13.9% 5,670 ops/sec [5,659..5,702] → 6,007 ops/sec [5,989..6,028] 🟢 +5.9%
Iterator.from({next}).reduce — 50 elements 4,618 ops/sec [4,595..4,677] → 4,038 ops/sec [3,980..4,055] 🔴 -12.6% 5,509 ops/sec [5,457..5,545] → 5,919 ops/sec [5,906..5,926] 🟢 +7.4%
wrap array iterator 162,009 ops/sec [160,395..163,715] → 137,689 ops/sec [134,609..138,666] 🔴 -15.0% 173,942 ops/sec [169,190..175,680] → 205,511 ops/sec [205,292..205,650] 🟢 +18.1%
wrap plain {next()} object 10,716 ops/sec [10,642..10,894] → 9,212 ops/sec [9,158..9,228] 🔴 -14.0% 14,574 ops/sec [14,487..14,608] → 15,901 ops/sec [15,847..15,957] 🟢 +9.1%
map + toArray (50 elements) 4,658 ops/sec [4,595..4,713] → 3,969 ops/sec [3,955..4,004] 🔴 -14.8% 6,073 ops/sec [6,061..6,111] → 6,526 ops/sec [6,485..6,581] 🟢 +7.5%
filter + toArray (50 elements) 4,564 ops/sec [4,364..4,686] → 3,863 ops/sec [3,847..3,883] 🔴 -15.4% 5,775 ops/sec [5,752..5,787] → 6,619 ops/sec [6,593..6,681] 🟢 +14.6%
take(10) + toArray (50 element source) 28,010 ops/sec [27,882..28,061] → 23,761 ops/sec [23,638..23,924] 🔴 -15.2% 36,790 ops/sec [36,302..36,812] → 38,895 ops/sec [38,402..39,745] 🟢 +5.7%
drop(40) + toArray (50 element source) 6,763 ops/sec [6,705..6,821] → 5,655 ops/sec [5,628..5,737] 🔴 -16.4% 8,807 ops/sec [8,699..8,865] → 9,780 ops/sec [9,716..9,814] 🟢 +11.1%
chained map + filter + take (100 element source) 8,406 ops/sec [8,275..8,493] → 7,018 ops/sec [6,997..7,081] 🔴 -16.5% 10,310 ops/sec [10,252..10,394] → 11,377 ops/sec [11,353..11,447] 🟢 +10.4%
some + every (50 elements) 2,668 ops/sec [2,655..2,699] → 2,267 ops/sec [2,256..2,280] 🔴 -15.0% 3,446 ops/sec [3,421..3,460] → 3,936 ops/sec [3,928..3,950] 🟢 +14.2%
find (50 elements) 5,821 ops/sec [5,739..5,883] → 4,780 ops/sec [4,747..4,821] 🔴 -17.9% 7,180 ops/sec [7,142..7,222] → 7,812 ops/sec [7,795..7,835] 🟢 +8.8%
array.values().map().filter().toArray() 8,157 ops/sec [8,073..8,261] → 6,798 ops/sec [6,780..6,875] 🔴 -16.7% 9,676 ops/sec [9,643..9,728] → 11,003 ops/sec [10,978..11,014] 🟢 +13.7%
array.values().take(5).toArray() 212,179 ops/sec [209,967..213,874] → 174,629 ops/sec [173,589..176,150] 🔴 -17.7% 230,777 ops/sec [229,161..232,628] → 251,127 ops/sec [250,523..251,728] 🟢 +8.8%
array.values().drop(45).toArray() 196,668 ops/sec [195,911..196,687] → 169,335 ops/sec [166,255..169,760] 🔴 -13.9% 208,574 ops/sec [205,481..210,851] → 242,460 ops/sec [241,315..243,640] 🟢 +16.2%
map.entries() chained helpers 10,094 ops/sec [9,901..10,182] → 8,129 ops/sec [8,061..8,234] 🔴 -19.5% 5,672 ops/sec [5,634..5,720] → 6,289 ops/sec [6,273..6,302] 🟢 +10.9%
set.values() chained helpers 17,293 ops/sec [17,113..17,438] → 14,089 ops/sec [14,030..14,222] 🔴 -18.5% 19,305 ops/sec [19,127..19,337] → 22,824 ops/sec [22,751..22,859] 🟢 +18.2%
string iterator map + toArray 13,425 ops/sec [13,198..13,546] → 11,310 ops/sec [11,260..11,354] 🔴 -15.8% 14,092 ops/sec [13,967..14,199] → 15,551 ops/sec [15,456..15,673] 🟢 +10.4%
json.js — Interp: 🟢 4, 🔴 13, 3 unch. · avg -4.2% · Bytecode: 🟢 20 · avg +11.7%
Benchmark Interpreted Δ Bytecode Δ
parse simple object 150,659 ops/sec [148,931..151,914] → 140,261 ops/sec [139,400..141,091] 🔴 -6.9% 151,027 ops/sec [150,090..151,630] → 167,403 ops/sec [166,273..168,036] 🟢 +10.8%
parse nested object 95,500 ops/sec [94,632..96,659] → 80,891 ops/sec [80,406..81,941] 🔴 -15.3% 93,580 ops/sec [92,812..94,271] → 107,287 ops/sec [106,931..107,585] 🟢 +14.6%
parse array of objects 55,007 ops/sec [54,385..55,163] → 48,421 ops/sec [48,184..49,121] 🔴 -12.0% 54,000 ops/sec [53,444..54,396] → 64,056 ops/sec [63,519..64,323] 🟢 +18.6%
parse large flat object 60,303 ops/sec [60,132..60,669] → 54,305 ops/sec [53,968..54,494] 🔴 -9.9% 60,796 ops/sec [60,358..61,477] → 72,089 ops/sec [71,252..72,302] 🟢 +18.6%
parse mixed types 68,779 ops/sec [68,079..69,732] → 62,760 ops/sec [62,099..63,414] 🔴 -8.7% 67,214 ops/sec [66,684..67,504] → 80,198 ops/sec [80,007..80,482] 🟢 +19.3%
stringify simple object 144,712 ops/sec [143,587..147,842] → 146,197 ops/sec [144,838..147,084] ~ overlap (+1.0%) 156,611 ops/sec [155,981..157,962] → 169,284 ops/sec [168,833..170,102] 🟢 +8.1%
stringify nested object 80,598 ops/sec [79,524..81,214] → 78,445 ops/sec [78,054..78,732] 🔴 -2.7% 84,131 ops/sec [83,854..84,454] → 92,843 ops/sec [92,513..94,573] 🟢 +10.4%
stringify array of objects 36,531 ops/sec [36,218..36,722] → 38,760 ops/sec [38,601..38,832] 🟢 +6.1% 36,695 ops/sec [36,621..36,873] → 39,416 ops/sec [39,151..39,499] 🟢 +7.4%
stringify mixed types 62,037 ops/sec [61,955..62,195] → 60,455 ops/sec [60,288..60,488] 🔴 -2.6% 61,727 ops/sec [61,552..61,875] → 68,916 ops/sec [68,227..69,483] 🟢 +11.6%
reviver doubles numbers 46,669 ops/sec [45,548..47,364] → 42,902 ops/sec [40,547..43,543] 🔴 -8.1% 49,347 ops/sec [47,816..50,724] → 55,116 ops/sec [53,261..57,587] 🟢 +11.7%
reviver filters properties 39,911 ops/sec [39,749..40,198] → 39,273 ops/sec [39,119..40,009] ~ overlap (-1.6%) 39,760 ops/sec [39,396..40,284] → 47,050 ops/sec [46,540..47,110] 🟢 +18.3%
reviver on nested object 50,273 ops/sec [50,009..51,070] → 46,520 ops/sec [46,363..46,833] 🔴 -7.5% 52,150 ops/sec [51,519..53,282] → 57,596 ops/sec [55,720..60,025] 🟢 +10.4%
reviver on array 31,231 ops/sec [31,087..31,521] → 28,920 ops/sec [27,826..29,551] 🔴 -7.4% 32,220 ops/sec [31,432..32,618] → 36,067 ops/sec [35,463..36,354] 🟢 +11.9%
replacer function doubles numbers 39,428 ops/sec [39,182..39,613] → 38,353 ops/sec [38,084..38,597] 🔴 -2.7% 44,607 ops/sec [44,104..44,705] → 48,623 ops/sec [47,625..48,900] 🟢 +9.0%
replacer function excludes properties 53,346 ops/sec [53,125..53,784] → 50,026 ops/sec [49,683..50,840] 🔴 -6.2% 56,046 ops/sec [55,634..56,403] → 61,602 ops/sec [60,628..61,666] 🟢 +9.9%
array replacer (allowlist) 89,327 ops/sec [88,834..89,720] → 81,748 ops/sec [81,519..82,597] 🔴 -8.5% 94,422 ops/sec [94,121..95,489] → 99,933 ops/sec [99,235..102,209] 🟢 +5.8%
stringify with 2-space indent 72,073 ops/sec [71,251..72,378] → 73,809 ops/sec [73,116..74,109] 🟢 +2.4% 75,680 ops/sec [75,371..77,168] → 81,229 ops/sec [80,404..81,676] 🟢 +7.3%
stringify with tab indent 71,081 ops/sec [70,982..71,450] → 73,281 ops/sec [72,877..73,751] 🟢 +3.1% 74,047 ops/sec [73,520..74,296] → 80,419 ops/sec [80,053..80,570] 🟢 +8.6%
parse then stringify 42,809 ops/sec [42,335..42,990] → 43,299 ops/sec [42,983..43,592] ~ overlap (+1.1%) 45,189 ops/sec [45,012..45,419] → 49,780 ops/sec [49,379..49,922] 🟢 +10.2%
stringify then parse 25,067 ops/sec [24,928..25,161] → 25,480 ops/sec [25,420..25,734] 🟢 +1.6% 26,294 ops/sec [25,688..26,832] → 29,143 ops/sec [29,043..29,164] 🟢 +10.8%
jsx.jsx — Interp: 🔴 21 · avg -12.3% · Bytecode: 🟢 21 · avg +5.7%
Benchmark Interpreted Δ Bytecode Δ
simple element 204,132 ops/sec [202,748..208,571] → 193,129 ops/sec [192,466..194,409] 🔴 -5.4% 310,431 ops/sec [310,046..310,638] → 332,995 ops/sec [331,295..333,948] 🟢 +7.3%
self-closing element 214,204 ops/sec [212,055..215,030] → 187,775 ops/sec [185,882..189,583] 🔴 -12.3% 356,136 ops/sec [353,421..357,374] → 374,927 ops/sec [373,465..377,002] 🟢 +5.3%
element with string attribute 176,144 ops/sec [175,751..176,995] → 153,325 ops/sec [151,811..154,231] 🔴 -13.0% 245,758 ops/sec [242,919..249,073] → 264,052 ops/sec [262,640..268,308] 🟢 +7.4%
element with multiple attributes 153,241 ops/sec [150,666..154,088] → 130,417 ops/sec [129,777..131,027] 🔴 -14.9% 204,750 ops/sec [204,129..205,864] → 209,601 ops/sec [207,610..211,384] 🟢 +2.4%
element with expression attribute 164,307 ops/sec [161,787..165,393] → 143,927 ops/sec [143,187..145,087] 🔴 -12.4% 243,584 ops/sec [242,595..246,126] → 265,455 ops/sec [261,786..266,639] 🟢 +9.0%
text child 207,627 ops/sec [206,610..208,978] → 181,597 ops/sec [179,870..182,128] 🔴 -12.5% 329,260 ops/sec [326,958..330,372] → 337,066 ops/sec [335,571..340,825] 🟢 +2.4%
expression child 203,724 ops/sec [202,587..204,627] → 178,379 ops/sec [177,346..179,067] 🔴 -12.4% 309,529 ops/sec [309,218..311,256] → 335,339 ops/sec [333,296..336,008] 🟢 +8.3%
mixed text and expression 192,595 ops/sec [192,378..194,495] → 165,160 ops/sec [163,658..166,356] 🔴 -14.2% 290,570 ops/sec [287,578..293,885] → 295,145 ops/sec [294,328..297,408] 🟢 +1.6%
nested elements (3 levels) 81,336 ops/sec [80,921..81,875] → 72,378 ops/sec [72,034..72,689] 🔴 -11.0% 115,087 ops/sec [114,205..116,152] → 124,694 ops/sec [122,557..125,439] 🟢 +8.3%
sibling children 58,761 ops/sec [58,594..58,923] → 49,719 ops/sec [49,272..49,879] 🔴 -15.4% 88,826 ops/sec [88,293..89,731] → 90,946 ops/sec [90,312..92,028] 🟢 +2.4%
component element 147,147 ops/sec [146,562..148,909] → 132,272 ops/sec [129,819..133,568] 🔴 -10.1% 214,958 ops/sec [212,399..216,021] → 233,936 ops/sec [232,397..234,827] 🟢 +8.8%
component with children 92,643 ops/sec [92,376..93,261] → 81,990 ops/sec [81,360..82,251] 🔴 -11.5% 134,280 ops/sec [133,358..135,197] → 139,355 ops/sec [138,292..140,128] 🟢 +3.8%
dotted component 124,465 ops/sec [123,594..125,443] → 109,167 ops/sec [108,896..109,568] 🔴 -12.3% 168,405 ops/sec [166,666..169,776] → 182,409 ops/sec [181,658..183,642] 🟢 +8.3%
empty fragment 214,634 ops/sec [211,943..215,055] → 188,691 ops/sec [188,512..189,024] 🔴 -12.1% 369,609 ops/sec [362,926..375,157] → 382,997 ops/sec [379,660..384,629] 🟢 +3.6%
fragment with children 59,545 ops/sec [59,123..59,720] → 53,240 ops/sec [52,931..53,809] 🔴 -10.6% 86,763 ops/sec [86,225..87,677] → 92,907 ops/sec [92,841..93,056] 🟢 +7.1%
spread attributes 106,778 ops/sec [105,762..107,471] → 94,243 ops/sec [92,390..94,641] 🔴 -11.7% 131,079 ops/sec [130,422..132,165] → 141,395 ops/sec [139,241..142,295] 🟢 +7.9%
spread with overrides 93,805 ops/sec [93,439..94,394] → 82,305 ops/sec [81,511..83,205] 🔴 -12.3% 115,177 ops/sec [113,239..115,748] → 121,802 ops/sec [121,070..122,420] 🟢 +5.8%
shorthand props 155,780 ops/sec [154,552..157,192] → 134,330 ops/sec [132,255..135,401] 🔴 -13.8% 232,364 ops/sec [230,873..234,201] → 246,789 ops/sec [242,171..249,368] 🟢 +6.2%
nav bar structure 27,138 ops/sec [27,078..27,184] → 22,573 ops/sec [22,450..22,712] 🔴 -16.8% 39,635 ops/sec [39,309..40,078] → 42,017 ops/sec [41,804..42,407] 🟢 +6.0%
card component tree 31,826 ops/sec [31,421..32,028] → 28,757 ops/sec [28,521..29,037] 🔴 -9.6% 43,964 ops/sec [43,890..44,036] → 46,281 ops/sec [46,102..46,446] 🟢 +5.3%
10 list items via Array.from 14,387 ops/sec [14,324..14,494] → 12,273 ops/sec [12,141..12,312] 🔴 -14.7% 19,099 ops/sec [18,883..19,404] → 19,734 ops/sec [19,496..19,813] 🟢 +3.3%
modules.js — Interp: 🔴 9 · avg -13.5% · Bytecode: 🟢 7, 🔴 1, 1 unch. · avg +11.5%
Benchmark Interpreted Δ Bytecode Δ
call imported function 454,717 ops/sec [451,487..457,267] → 409,358 ops/sec [408,334..410,184] 🔴 -10.0% 663,683 ops/sec [661,819..667,707] → 671,030 ops/sec [665,927..676,779] ~ overlap (+1.1%)
call two imported functions 258,875 ops/sec [257,868..260,573] → 236,159 ops/sec [235,555..237,679] 🔴 -8.8% 361,568 ops/sec [359,908..362,047] → 356,623 ops/sec [354,712..357,722] 🔴 -1.4%
read imported constant 1,652,210 ops/sec [1,639,130..1,655,071] → 1,391,860 ops/sec [1,389,553..1,393,046] 🔴 -15.8% 3,713,695 ops/sec [3,709,896..3,717,036] → 4,263,381 ops/sec [4,259,760..4,269,020] 🟢 +14.8%
read imported string 1,634,829 ops/sec [1,603,309..1,645,057] → 1,382,186 ops/sec [1,373,485..1,388,742] 🔴 -15.5% 3,722,032 ops/sec [3,711,608..3,728,707] → 4,275,766 ops/sec [4,264,047..4,280,190] 🟢 +14.9%
read JSON string property 1,664,291 ops/sec [1,655,662..1,681,368] → 1,396,464 ops/sec [1,385,889..1,399,174] 🔴 -16.1% 3,715,380 ops/sec [3,702,567..3,717,249] → 4,240,866 ops/sec [4,233,699..4,244,586] 🟢 +14.1%
read JSON number property 1,643,751 ops/sec [1,632,961..1,647,653] → 1,378,575 ops/sec [1,376,518..1,379,194] 🔴 -16.1% 3,700,256 ops/sec [3,697,768..3,703,203] → 4,280,411 ops/sec [4,272,727..4,281,731] 🟢 +15.7%
read JSON boolean property 1,645,058 ops/sec [1,638,799..1,652,394] → 1,407,065 ops/sec [1,404,487..1,412,712] 🔴 -14.5% 3,718,908 ops/sec [3,707,654..3,725,440] → 4,280,592 ops/sec [4,277,075..4,282,069] 🟢 +15.1%
read JSON array property 1,655,678 ops/sec [1,649,431..1,658,651] → 1,396,900 ops/sec [1,392,667..1,406,048] 🔴 -15.6% 3,700,011 ops/sec [3,693,702..3,706,479] → 4,265,204 ops/sec [4,264,394..4,267,391] 🟢 +15.3%
read multiple JSON properties 929,925 ops/sec [922,577..938,193] → 843,562 ops/sec [843,325..844,424] 🔴 -9.3% 3,350,157 ops/sec [3,343,589..3,360,516] → 3,822,674 ops/sec [3,736,693..3,826,434] 🟢 +14.1%
numbers.js — Interp: 🟢 2, 🔴 9 · avg -5.5% · Bytecode: 🟢 11 · avg +17.3%
Benchmark Interpreted Δ Bytecode Δ
integer arithmetic 478,200 ops/sec [470,130..483,027] → 450,207 ops/sec [447,545..454,286] 🔴 -5.9% 1,100,659 ops/sec [1,090,664..1,114,467] → 1,827,869 ops/sec [1,826,794..1,828,434] 🟢 +66.1%
floating point arithmetic 575,605 ops/sec [552,044..580,087] → 520,999 ops/sec [518,065..521,990] 🔴 -9.5% 801,387 ops/sec [799,843..802,013] → 1,294,662 ops/sec [1,290,963..1,298,822] 🟢 +61.6%
number coercion 188,077 ops/sec [187,233..188,678] → 191,818 ops/sec [190,979..193,385] 🟢 +2.0% 232,604 ops/sec [231,399..233,275] → 247,886 ops/sec [247,236..248,528] 🟢 +6.6%
toFixed 97,580 ops/sec [96,859..98,090] → 99,214 ops/sec [98,697..99,748] 🟢 +1.7% 110,014 ops/sec [109,193..110,439] → 122,606 ops/sec [121,849..123,512] 🟢 +11.4%
toString 148,558 ops/sec [148,246..150,900] → 136,354 ops/sec [135,833..136,889] 🔴 -8.2% 181,574 ops/sec [180,640..182,873] → 196,270 ops/sec [195,376..196,976] 🟢 +8.1%
valueOf 227,094 ops/sec [225,464..229,506] → 199,900 ops/sec [199,214..201,848] 🔴 -12.0% 268,865 ops/sec [266,396..269,997] → 290,818 ops/sec [288,718..292,362] 🟢 +8.2%
toPrecision 138,989 ops/sec [136,860..140,300] → 122,013 ops/sec [121,291..122,463] 🔴 -12.2% 162,090 ops/sec [161,483..162,483] → 163,338 ops/sec [162,956..165,074] 🟢 +0.8%
Number.isNaN 324,188 ops/sec [319,645..327,183] → 298,909 ops/sec [298,526..299,293] 🔴 -7.8% 346,028 ops/sec [345,213..346,760] → 369,396 ops/sec [368,363..369,711] 🟢 +6.8%
Number.isFinite 313,966 ops/sec [312,791..315,498] → 311,735 ops/sec [311,339..312,211] 🔴 -0.7% 325,398 ops/sec [323,237..326,901] → 348,592 ops/sec [348,200..349,586] 🟢 +7.1%
Number.isInteger 321,092 ops/sec [316,846..324,295] → 313,604 ops/sec [311,443..315,029] 🔴 -2.3% 352,925 ops/sec [351,626..353,452] → 386,006 ops/sec [384,313..386,838] 🟢 +9.4%
Number.parseInt and parseFloat 251,249 ops/sec [248,559..253,843] → 238,011 ops/sec [235,854..238,908] 🔴 -5.3% 271,426 ops/sec [268,301..272,652] → 284,110 ops/sec [282,297..286,405] 🟢 +4.7%
objects.js — Interp: 🔴 7 · avg -16.0% · Bytecode: 🟢 3, 4 unch. · avg +2.9%
Benchmark Interpreted Δ Bytecode Δ
create simple object 451,286 ops/sec [446,516..455,722] → 381,998 ops/sec [379,591..383,569] 🔴 -15.4% 574,610 ops/sec [562,879..580,219] → 559,551 ops/sec [554,496..565,161] ~ overlap (-2.6%)
create nested object 225,428 ops/sec [223,795..226,103] → 187,779 ops/sec [186,806..189,533] 🔴 -16.7% 250,077 ops/sec [246,965..251,884] → 251,151 ops/sec [248,503..253,359] ~ overlap (+0.4%)
create 50 objects via Array.from 9,100 ops/sec [9,090..9,115] → 7,763 ops/sec [7,657..7,859] 🔴 -14.7% 9,910 ops/sec [9,852..9,920] → 10,030 ops/sec [9,888..10,101] ~ overlap (+1.2%)
property read 557,357 ops/sec [551,048..561,582] → 477,854 ops/sec [474,124..479,150] 🔴 -14.3% 437,024 ops/sec [435,231..438,572] → 446,145 ops/sec [445,545..446,778] 🟢 +2.1%
Object.keys 276,313 ops/sec [270,510..280,644] → 238,020 ops/sec [236,063..239,704] 🔴 -13.9% 302,636 ops/sec [297,442..308,615] → 326,053 ops/sec [324,293..327,086] 🟢 +7.7%
Object.entries 103,900 ops/sec [102,866..104,502] → 83,837 ops/sec [83,226..84,180] 🔴 -19.3% 105,754 ops/sec [104,886..106,710] → 116,737 ops/sec [116,341..117,140] 🟢 +10.4%
spread operator 173,583 ops/sec [173,136..173,971] → 142,628 ops/sec [142,178..142,882] 🔴 -17.8% 203,751 ops/sec [203,038..204,786] → 205,280 ops/sec [204,492..205,405] ~ overlap (+0.8%)
promises.js — Interp: 🔴 12 · avg -20.1% · Bytecode: 🟢 11, 1 unch. · avg +6.2%
Benchmark Interpreted Δ Bytecode Δ
Promise.resolve(value) 521,675 ops/sec [517,122..523,863] → 441,282 ops/sec [438,515..442,488] 🔴 -15.4% 555,962 ops/sec [548,557..557,773] → 593,435 ops/sec [586,209..595,557] 🟢 +6.7%
new Promise(resolve => resolve(value)) 193,652 ops/sec [191,984..195,218] → 160,761 ops/sec [159,702..162,078] 🔴 -17.0% 221,913 ops/sec [221,189..222,625] → 235,788 ops/sec [235,483..236,662] 🟢 +6.3%
Promise.reject(reason) 539,963 ops/sec [536,453..547,266] → 444,054 ops/sec [440,700..445,020] 🔴 -17.8% 543,124 ops/sec [542,097..547,043] → 581,537 ops/sec [578,928..582,047] 🟢 +7.1%
resolve + then (1 handler) 173,030 ops/sec [171,040..174,200] → 155,131 ops/sec [153,912..155,910] 🔴 -10.3% 197,595 ops/sec [197,334..199,881] → 209,825 ops/sec [209,399..210,363] 🟢 +6.2%
resolve + then chain (3 deep) 68,015 ops/sec [67,523..68,344] → 56,491 ops/sec [56,325..56,688] 🔴 -16.9% 74,812 ops/sec [72,889..76,698] → 79,104 ops/sec [78,434..79,864] 🟢 +5.7%
resolve + then chain (10 deep) 22,456 ops/sec [21,876..22,539] → 15,510 ops/sec [15,405..15,561] 🔴 -30.9% 24,531 ops/sec [23,951..25,204] → 25,266 ops/sec [24,865..25,320] ~ overlap (+3.0%)
reject + catch + then 98,923 ops/sec [98,521..99,705] → 74,335 ops/sec [74,078..74,691] 🔴 -24.9% 107,487 ops/sec [106,909..108,179] → 114,625 ops/sec [114,109..115,427] 🟢 +6.6%
resolve + finally + then 83,812 ops/sec [83,142..84,273] → 67,262 ops/sec [66,857..67,792] 🔴 -19.7% 89,128 ops/sec [88,849..90,003] → 96,985 ops/sec [96,817..97,300] 🟢 +8.8%
Promise.all (5 resolved) 31,235 ops/sec [30,985..31,542] → 24,812 ops/sec [24,515..24,999] 🔴 -20.6% 31,859 ops/sec [31,771..32,062] → 34,333 ops/sec [34,037..34,498] 🟢 +7.8%
Promise.race (5 resolved) 34,771 ops/sec [34,554..34,857] → 26,652 ops/sec [26,458..26,813] 🔴 -23.3% 33,991 ops/sec [33,755..34,473] → 35,868 ops/sec [35,734..35,937] 🟢 +5.5%
Promise.allSettled (5 mixed) 26,313 ops/sec [25,590..26,515] → 20,880 ops/sec [20,782..21,017] 🔴 -20.6% 27,407 ops/sec [27,293..27,601] → 28,740 ops/sec [28,652..28,868] 🟢 +4.9%
Promise.any (5 mixed) 31,516 ops/sec [31,307..31,552] → 24,041 ops/sec [23,800..24,060] 🔴 -23.7% 31,983 ops/sec [31,873..32,098] → 33,733 ops/sec [33,618..34,050] 🟢 +5.5%
regexp.js — Interp: 🔴 11 · avg -12.2% · Bytecode: 🟢 11 · avg +4.6%
Benchmark Interpreted Δ Bytecode Δ
regex literal creation 169,543 ops/sec [167,594..171,957] → 154,797 ops/sec [153,693..155,626] 🔴 -8.7% 160,856 ops/sec [159,008..161,799] → 164,081 ops/sec [163,220..164,823] 🟢 +2.0%
new RegExp(pattern, flags) 146,377 ops/sec [145,152..146,858] → 126,837 ops/sec [125,298..127,778] 🔴 -13.3% 157,527 ops/sec [157,156..158,433] → 161,324 ops/sec [159,004..162,783] 🟢 +2.4%
RegExp(existingRegex) returns the same regex 763,103 ops/sec [758,491..765,827] → 683,705 ops/sec [681,880..686,283] 🔴 -10.4% 1,002,370 ops/sec [1,001,183..1,005,709] → 1,090,104 ops/sec [1,087,336..1,091,025] 🟢 +8.8%
test() on a global regex 150,218 ops/sec [148,936..151,305] → 131,620 ops/sec [130,774..133,344] 🔴 -12.4% 179,177 ops/sec [178,592..179,819] → 188,980 ops/sec [188,363..189,249] 🟢 +5.5%
exec() with capture groups 131,822 ops/sec [131,076..132,381] → 118,687 ops/sec [117,709..119,370] 🔴 -10.0% 155,795 ops/sec [154,449..156,116] → 159,043 ops/sec [157,782..159,741] 🟢 +2.1%
toString() 477,011 ops/sec [475,019..477,449] → 449,621 ops/sec [446,932..451,169] 🔴 -5.7% 625,061 ops/sec [622,882..627,364] → 638,640 ops/sec [636,802..643,373] 🟢 +2.2%
match() with global regex 42,862 ops/sec [42,737..43,056] → 36,807 ops/sec [36,531..37,100] 🔴 -14.1% 43,663 ops/sec [43,508..44,132] → 44,932 ops/sec [44,699..45,019] 🟢 +2.9%
matchAll() with capture groups 22,125 ops/sec [21,971..22,288] → 18,294 ops/sec [18,189..18,438] 🔴 -17.3% 27,559 ops/sec [27,415..27,852] → 29,561 ops/sec [29,311..29,684] 🟢 +7.3%
replace() with global regex 41,398 ops/sec [41,076..41,473] → 35,860 ops/sec [35,689..35,936] 🔴 -13.4% 41,669 ops/sec [41,347..42,031] → 45,143 ops/sec [44,954..45,271] 🟢 +8.3%
search() with regex 88,142 ops/sec [87,783..88,783] → 75,727 ops/sec [75,492..75,844] 🔴 -14.1% 85,582 ops/sec [84,619..85,912] → 91,267 ops/sec [90,956..91,807] 🟢 +6.6%
split() with regex separator 43,172 ops/sec [43,076..43,255] → 36,603 ops/sec [36,391..36,692] 🔴 -15.2% 44,338 ops/sec [43,664..44,903] → 45,391 ops/sec [45,121..45,577] 🟢 +2.4%
strings.js — Interp: 🔴 11 · avg -15.6% · Bytecode: 🟢 8, 🔴 2, 1 unch. · avg +2.4%
Benchmark Interpreted Δ Bytecode Δ
string concatenation 397,526 ops/sec [393,928..400,077] → 315,770 ops/sec [314,294..317,864] 🔴 -20.6% 321,884 ops/sec [320,905..322,577] → 296,996 ops/sec [295,150..298,690] 🔴 -7.7%
template literal 613,554 ops/sec [607,640..620,064] → 550,346 ops/sec [547,802..552,525] 🔴 -10.3% 655,571 ops/sec [652,920..664,528] → 636,078 ops/sec [635,060..637,174] 🔴 -3.0%
string repeat 380,929 ops/sec [377,261..383,674] → 332,044 ops/sec [329,053..334,452] 🔴 -12.8% 465,181 ops/sec [462,288..467,014] → 490,625 ops/sec [489,724..491,630] 🟢 +5.5%
split and join 133,262 ops/sec [131,441..134,079] → 105,440 ops/sec [104,746..106,248] 🔴 -20.9% 153,249 ops/sec [151,185..153,497] → 156,439 ops/sec [155,906..157,856] 🟢 +2.1%
indexOf and includes 162,015 ops/sec [161,479..163,765] → 143,909 ops/sec [142,676..144,328] 🔴 -11.2% 191,204 ops/sec [190,349..191,727] → 202,457 ops/sec [201,477..204,145] 🟢 +5.9%
toUpperCase and toLowerCase 246,098 ops/sec [244,855..247,177] → 208,975 ops/sec [207,580..210,528] 🔴 -15.1% 329,415 ops/sec [326,836..330,619] → 332,541 ops/sec [329,093..333,956] ~ overlap (+0.9%)
slice and substring 149,264 ops/sec [147,462..149,515] → 120,584 ops/sec [119,873..120,875] 🔴 -19.2% 196,799 ops/sec [196,392..197,686] → 203,930 ops/sec [202,763..204,631] 🟢 +3.6%
trim operations 183,512 ops/sec [181,881..185,275] → 147,725 ops/sec [146,683..148,477] 🔴 -19.5% 238,795 ops/sec [237,854..239,349] → 245,489 ops/sec [243,945..246,178] 🟢 +2.8%
replace and replaceAll 198,339 ops/sec [196,159..199,944] → 158,405 ops/sec [157,928..158,677] 🔴 -20.1% 233,125 ops/sec [232,907..233,945] → 240,838 ops/sec [240,080..242,141] 🟢 +3.3%
startsWith and endsWith 130,521 ops/sec [128,964..131,712] → 113,344 ops/sec [112,444..114,100] 🔴 -13.2% 158,182 ops/sec [157,186..162,068] → 171,051 ops/sec [170,078..171,472] 🟢 +8.1%
padStart and padEnd 186,050 ops/sec [184,486..187,360] → 169,053 ops/sec [165,745..169,990] 🔴 -9.1% 234,737 ops/sec [232,229..236,199] → 245,180 ops/sec [244,302..245,910] 🟢 +4.4%
typed-arrays.js — Interp: 🟢 3, 🔴 18, 1 unch. · avg -13.0% · Bytecode: 🟢 21, 1 unch. · avg +10.1%
Benchmark Interpreted Δ Bytecode Δ
new Int32Array(0) 324,701 ops/sec [322,451..326,234] → 270,908 ops/sec [270,396..271,201] 🔴 -16.6% 363,513 ops/sec [359,175..367,688] → 381,540 ops/sec [381,148..382,671] 🟢 +5.0%
new Int32Array(100) 293,383 ops/sec [289,571..294,363] → 231,519 ops/sec [229,184..232,499] 🔴 -21.1% 328,421 ops/sec [326,014..330,461] → 351,238 ops/sec [349,244..352,152] 🟢 +6.9%
new Int32Array(1000) 186,556 ops/sec [184,779..187,780] → 169,340 ops/sec [167,556..170,565] 🔴 -9.2% 193,926 ops/sec [191,243..196,138] → 220,209 ops/sec [219,246..220,584] 🟢 +13.6%
new Float64Array(100) 279,644 ops/sec [279,107..281,694] → 227,491 ops/sec [227,232..228,787] 🔴 -18.6% 300,335 ops/sec [294,947..301,001] → 327,802 ops/sec [326,889..328,263] 🟢 +9.1%
Int32Array.from([...]) 181,410 ops/sec [180,952..181,769] → 164,064 ops/sec [161,820..165,448] 🔴 -9.6% 187,287 ops/sec [186,413..189,923] → 208,905 ops/sec [207,777..209,498] 🟢 +11.5%
Int32Array.of(1, 2, 3, 4, 5) 296,716 ops/sec [291,303..299,131] → 218,461 ops/sec [214,939..220,813] 🔴 -26.4% 348,657 ops/sec [344,471..359,467] → 354,086 ops/sec [353,591..355,009] ~ overlap (+1.6%)
sequential write 100 elements 3,431 ops/sec [3,355..3,467] → 2,879 ops/sec [2,839..2,898] 🔴 -16.1% 15,249 ops/sec [15,097..15,364] → 17,434 ops/sec [17,311..17,539] 🟢 +14.3%
sequential read 100 elements 3,504 ops/sec [3,462..3,516] → 2,913 ops/sec [2,899..2,936] 🔴 -16.9% 10,909 ops/sec [10,775..11,062] → 11,546 ops/sec [11,507..11,575] 🟢 +5.8%
Float64Array write 100 elements 3,204 ops/sec [3,147..3,216] → 2,826 ops/sec [2,813..2,838] 🔴 -11.8% 11,040 ops/sec [10,882..11,130] → 12,932 ops/sec [12,851..12,954] 🟢 +17.1%
fill(42) 46,222 ops/sec [45,954..46,279] → 53,867 ops/sec [53,787..53,961] 🟢 +16.5% 46,574 ops/sec [46,443..46,609] → 55,102 ops/sec [54,972..55,172] 🟢 +18.3%
slice() 203,365 ops/sec [201,968..206,063] → 187,620 ops/sec [186,203..188,440] 🔴 -7.7% 217,449 ops/sec [216,249..217,968] → 239,377 ops/sec [239,078..239,518] 🟢 +10.1%
map(x => x * 2) 8,014 ops/sec [7,952..8,044] → 6,196 ops/sec [6,169..6,219] 🔴 -22.7% 8,799 ops/sec [8,743..8,803] → 9,485 ops/sec [9,416..9,501] 🟢 +7.8%
filter(x => x > 50) 8,263 ops/sec [8,162..8,379] → 6,614 ops/sec [6,558..6,651] 🔴 -20.0% 9,691 ops/sec [9,643..9,713] → 10,247 ops/sec [10,186..10,262] 🟢 +5.7%
reduce (sum) 7,930 ops/sec [7,823..8,118] → 6,491 ops/sec [6,395..6,549] 🔴 -18.1% 7,351 ops/sec [7,312..7,454] → 8,065 ops/sec [8,052..8,088] 🟢 +9.7%
sort() 175,126 ops/sec [173,924..175,780] → 192,264 ops/sec [191,981..193,043] 🟢 +9.8% 180,895 ops/sec [180,552..181,026] → 209,403 ops/sec [209,220..209,797] 🟢 +15.8%
indexOf() 426,287 ops/sec [420,354..432,428] → 422,990 ops/sec [421,670..424,505] ~ overlap (-0.8%) 492,492 ops/sec [489,446..493,686] → 561,093 ops/sec [559,598..562,625] 🟢 +13.9%
reverse() 328,971 ops/sec [326,237..332,174] → 337,760 ops/sec [336,620..339,098] 🟢 +2.7% 358,299 ops/sec [357,579..358,966] → 402,623 ops/sec [402,217..403,143] 🟢 +12.4%
create view over existing buffer 392,714 ops/sec [391,742..393,547] → 330,672 ops/sec [328,807..332,838] 🔴 -15.8% 435,816 ops/sec [431,319..437,415] → 470,816 ops/sec [469,635..473,201] 🟢 +8.0%
subarray() 424,898 ops/sec [418,878..428,996] → 339,951 ops/sec [337,384..346,607] 🔴 -20.0% 501,394 ops/sec [498,207..508,226] → 542,646 ops/sec [541,490..546,580] 🟢 +8.2%
set() from array 576,377 ops/sec [572,690..579,814] → 536,090 ops/sec [531,960..538,708] 🔴 -7.0% 632,792 ops/sec [631,647..633,853] → 692,107 ops/sec [691,601..692,594] 🟢 +9.4%
for-of loop 4,965 ops/sec [4,944..4,977] → 3,720 ops/sec [3,699..3,744] 🔴 -25.1% 17,911 ops/sec [17,660..17,993] → 19,836 ops/sec [19,686..20,000] 🟢 +10.7%
spread into array 17,649 ops/sec [17,523..17,800] → 11,948 ops/sec [11,912..12,016] 🔴 -32.3% 92,086 ops/sec [91,500..93,383] → 97,674 ops/sec [96,859..98,926] 🟢 +6.1%

Measured on ubuntu-latest x64. Benchmark ranges compare cached main-branch min/max ops/sec with the PR run; overlapping ranges are treated as unchanged noise. Percentage deltas are secondary context.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 6, 2026

Suite Timing

Suite Metric Interpreted Bytecode
Tests Total 3685 3685
Tests Passed 3644 ✅ 3685 ✅
Tests Skipped 41 0
Tests Execution 202.7ms 193.4ms
Tests Engine 373.8ms 679.2ms
Benchmarks Total 274 274
Benchmarks Duration 7.19min 6.35min

Measured on ubuntu-latest x64.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
units/Goccia.Lexer.Test.pas (1)

20-29: Consider adding an explicit #13#10 case for line tracking.

Using sLineBreak only checks the current host newline. Adding a fixed CRLF assertion would keep this behavior locked even when PR checks run on a single OS.

Suggested test addition
 type
   TLexerTests = class(TTestSuite)
   private
     procedure TestIgnoresLeadingHashbang;
     procedure TestPreservesLineNumbersAfterHashbang;
+    procedure TestPreservesLineNumbersAfterHashbangCRLF;
   public
     procedure SetupTests; override;
   end;

 procedure TLexerTests.SetupTests;
 begin
   Test('Ignores leading hashbang', TestIgnoresLeadingHashbang);
   Test('Preserves line numbers after hashbang', TestPreservesLineNumbersAfterHashbang);
+  Test('Preserves line numbers after hashbang (CRLF)', TestPreservesLineNumbersAfterHashbangCRLF);
 end;

+procedure TLexerTests.TestPreservesLineNumbersAfterHashbangCRLF;
+var
+  Lexer: TGocciaLexer;
+  Tokens: TObjectList<TGocciaToken>;
+begin
+  Lexer := TGocciaLexer.Create('#!/usr/bin/env goccia' + `#13`#10 + 'const value = 1;', '<test>');
+  try
+    Tokens := Lexer.ScanTokens;
+    Expect<Integer>(Tokens[0].Line).ToBe(2);
+    Expect<Integer>(Tokens[0].Column).ToBe(1);
+  finally
+    Lexer.Free;
+  end;
+end;

Also applies to: 49-63

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@units/Goccia.Lexer.Test.pas` around lines 20 - 29, The tests currently only
assert newline handling using sLineBreak which is platform-dependent; update the
lexer line-tracking tests (specifically the
TestPreservesLineNumbersAfterHashbang and related test procedures referenced in
TLexerTests.SetupTests and the tests around lines 49-63) to include an explicit
CRLF case (`#13`#10) in addition to sLineBreak so CI on different OSes still
verifies CRLF behavior; modify the test bodies to feed an input containing "#!"
followed by `#13`#10 and assert the same preserved line numbers as with
sLineBreak.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@units/Goccia.Lexer.Test.pas`:
- Around line 20-29: The tests currently only assert newline handling using
sLineBreak which is platform-dependent; update the lexer line-tracking tests
(specifically the TestPreservesLineNumbersAfterHashbang and related test
procedures referenced in TLexerTests.SetupTests and the tests around lines
49-63) to include an explicit CRLF case (`#13`#10) in addition to sLineBreak so CI
on different OSes still verifies CRLF behavior; modify the test bodies to feed
an input containing "#!" followed by `#13`#10 and assert the same preserved line
numbers as with sLineBreak.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e68fbe60-c73c-40fd-af6c-2bba4285fc29

📥 Commits

Reviewing files that changed from the base of the PR and between 31f74d5 and e2b58f7.

📒 Files selected for processing (5)
  • README.md
  • docs/build-system.md
  • tests/language/shebang.js
  • units/Goccia.Lexer.Test.pas
  • units/Goccia.Lexer.pas

- Cover leading hashbang skipping with both LF and CRLF
- Verify token line numbers stay correct after hashbangs
@frostney frostney merged commit b17bfd3 into main Apr 6, 2026
54 checks passed
@frostney frostney deleted the t3code/ignore-shebang-passthrough branch April 6, 2026 21:36
@frostney frostney added the new feature New feature or request label Apr 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

new feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant