Commit Graph

95 Commits

Author SHA1 Message Date
Johan Dahlin
9f0265f953 LibJS: Box ExpressionKind::BigIntLiteral variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
5da800bff2 LibJS: Box ExpressionKind::StringLiteral variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
8dda68e642 LibJS: Box StatementKind::Program variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
3d0aaf41a9 LibJS: Box ExpressionKind::RegExpLiteral variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
780605f986 LibJS: Box ExpressionKind::TemplateLiteral variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
bb44d3bb38 LibJS: Box StatementKind::Export variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
9d29703962 LibJS: Box StatementKind::Import variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
b922b4a31b LibJS: Box StatementKind::Try variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
ff047383e4 LibJS: Box StatementKind::Switch variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
102c73a072 LibJS: Box ExpressionKind::SuperCall variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
0a1bf8079c LibJS: Box ExpressionKind::New variant 2026-03-28 11:55:41 +01:00
Johan Dahlin
d2a5c1260d LibJS: Box ExpressionKind::Call variant 2026-03-28 11:55:41 +01:00
Andreas Kling
c8a0a960b5 LibJS: Validate regex literals during parsing
Now that LibRegex is safe to use (for parsing) off the main thread,
we can validate regex literals directly while parsing JavaScript.

This allows us to remove the deferred regex compilation pass that we
previously ran on the main thread after parsing JS in the background.
2026-03-27 17:32:19 +01:00
InvalidUsernameException
61e6dbe4e7 LibJS: Copy object of member expression to preserve evaluation order
Noticed this pattern when reading some minified JS while debugging a
seemingly unrelated problem and immediately got suspicious because of my
earlier, similar fixes.
2026-03-22 15:40:38 +01:00
InvalidUsernameException
a94d8a1f78 LibJS: Remove some dead code
Looks like the combined parse and compile code path wasn't used
(anymore).
2026-03-22 15:40:38 +01:00
Andreas Kling
cf7576728d LibJS: Collect hoisted var declarations when checking module exports
The check_undeclared_exports() function only looked at top-level
VariableDeclaration nodes when collecting declared names. This missed
var declarations nested inside for loops, if/else blocks, try/catch,
switch statements, etc. Since var declarations are hoisted to the
enclosing module scope, they are valid export targets.

This caused legitimate modules (like the claude.ai JS bundle) to fail
with "'name' in export is not declared" errors when a var was declared
inside a for loop and later exported.

Fix this by recursively walking nested statements to collect var
declarations, while correctly not crossing function boundaries (since
var does not hoist out of functions) and not collecting block-scoped
let/const declarations.
2026-03-22 09:24:44 -05:00
pwespi
3dc3bcb556 LibJS: Fix expected SyntaxErrors for private fields 2026-03-20 16:06:51 -05:00
Andreas Kling
bb0acb54ae LibJS: Optimize x >> 0 to ToInt32 in bytecode codegen
x >> 0 is a common JS idiom equivalent to ToInt32(x). We already had
this optimization for x | 0, now do it for right shift by zero as well.

This allows the asmint handler for ToInt32 to run instead of the more
expensive RightShift handler, which wastes time loading and checking the
rhs operand and performing a shift by zero.
2026-03-20 00:51:23 -05:00
Andreas Kling
02b0746676 LibJS: Deduplicate double constants in bytecode generator
Add a deduplication cache for double constants, matching the existing
approach for int32 and string constants. Multiple references to the
same floating-point value now share a single constant table entry.
2026-03-20 00:51:23 -05:00
Andreas Kling
144ab69715 LibJS: Remove C++ pipeline compatibility hacks from Rust codegen
Now that the C++ bytecode pipeline has been removed, we no longer
need to match its register allocation or block layout. This removes:

- All manual drop() calls that existed solely to match C++ register
  lifetimes, replaced with scope blocks to naturally limit register
  lifetimes without increasing register pressure.

- The unnecessary saved_property copy in update expressions. The
  property register is now used directly since emit_update_op
  doesn't evaluate user expressions that could mutate it. The copy
  is retained in compound/logical assignments where the RHS can
  mutate the property variable (e.g. a[i] |= a[++i]).

- All "matching C++", "Match C++", etc. comments throughout
  codegen.rs and generator.rs that referenced the removed pipeline.
2026-03-20 00:51:23 -05:00
Andreas Kling
f5eea4d232 LibJS: Fix catch parameter and new.target regressions
- Restrict catch parameter conflict check to only direct children
  of the catch body block, not nested scopes
- Set new_target_is_valid for dynamic function compilation (new
  Function)
- Move check_parameters_post_body before flag restoration in
  parse_method_definition so generator methods inside static init
  blocks correctly allow 'await' as a parameter name
2026-03-19 23:15:03 -05:00
Andreas Kling
5374f0a85c LibJS: Add more early errors in Rust parser
- Reject duplicate bindings in catch parameter patterns
- Reject redeclaration of catch parameter with let/const/function
- Reject binding patterns with initializers in for-in heads (AnnexB
  only permits simple BindingIdentifier with initializer)
- Reject 'await' as binding identifier in class static init blocks
  and module code
2026-03-19 23:15:03 -05:00
Andreas Kling
49cc44a3eb LibJS: Reject arguments/eval in strict mode destructuring and arrows
Check identifier name validity for destructuring assignment pattern
bound names, and validate arrow function parameters after the arrow
is confirmed rather than during speculative parameter parsing.

This fixes arguments/eval as destructuring assignment targets and as
arrow function parameter names in strict mode.
2026-03-19 23:15:03 -05:00
Andreas Kling
66dbb355fe LibJS: Reject new.target in arrow functions at global scope
Arrow functions don't have their own new.target binding -- they
inherit from the enclosing scope. At the global level, there is no
enclosing function, so new.target inside a global arrow is invalid.

Add a new_target_is_valid flag to ParserFlags that is set to true
when entering regular (non-arrow) function bodies, method
definitions, and class static init blocks. Arrow functions inherit
the flag from their enclosing scope rather than setting it.
2026-03-19 23:15:03 -05:00
Andreas Kling
6029a3d40e LibJS: Add missing early errors in Rust parser
- Reject `true`, `false`, `null` as label identifiers
- Reject generator declarations in if-statement bodies (not covered
  by Annex B)
- Reject `await` as label in class static init blocks and modules
- Reject `arguments` in class static initialization blocks
- Reject generator shorthand without method body in object literals
- Reject `get constructor()` / `set constructor()` in class bodies
- Reject `super.#private` member access
2026-03-19 23:15:03 -05:00
Andreas Kling
30f108ba36 LibJS: Remove C++ lexer, use Rust tokenizer for syntax highlighting
Delete Lexer.cpp/h and Token.cpp, replacing all tokenization with a
new rust_tokenize() FFI function that calls back for each token.

Rewrite SyntaxHighlighter.cpp and js.cpp REPL to use the Rust
tokenizer. The token type and category enums in Token.h now mirror
the Rust definitions in token.rs.

Move is_syntax_character/is_whitespace/is_line_terminator helpers
into RegExpConstructor.cpp as static functions, since they were only
used there.
2026-03-19 21:55:10 -05:00
Andrew Kaster
f06bd0303f LibJS: Use enum for retrieving well known symbols from C++ to Rust 2026-03-19 09:48:32 +01:00
Andrew Kaster
5d43707896 LibJS: Directly use LiteralValueKind enum across FFI boundary 2026-03-19 09:48:32 +01:00
RubenKelevra
fae2f8f3ba LibJS: Align new-expression paren flags with C++ parser 2026-03-18 17:41:36 -05:00
RubenKelevra
3cb636ca38 LibJS: Keep new call-paren optional chaining valid 2026-03-18 17:41:36 -05:00
RubenKelevra
ea8fa63e79 LibJS: Reject optional chaining on unparenthesized new 2026-03-18 17:41:36 -05:00
RubenKelevra
04b27429de LibJS: Isolate super validity in nested function scopes 2026-03-18 17:41:36 -05:00
RubenKelevra
d8469c384d LibJS: Reject invalid bare private identifier usage 2026-03-18 17:41:36 -05:00
RubenKelevra
d6229a1cc8 LibJS: Fix async arrow and for-of async parsing 2026-03-18 17:41:36 -05:00
RubenKelevra
af777b5d86 LibJS: Align duplicate parameter early errors 2026-03-18 17:41:36 -05:00
RubenKelevra
40984d0f39 LibJS: Enforce const initializers in declarations 2026-03-18 17:41:36 -05:00
Andrew Kaster
92e4c20ad5 LibJS: Generate FFI header using cbindgen instead of hand-rolling
Replace the BytecodeFactory header with cbindgen.

This will help ensure that types and enums and constants are kept in
sync between the C++ and Rust code. It's also a step in exporting more
Rust enums directly rather than relying on magic constants for
switch statements.

The FFI functions are now all placed in the JS::FFI namespace, which
is the cause for all the churn in the scripting parts of LibJS and
LibWeb.
2026-03-17 20:49:50 -05:00
Andrew Kaster
ba8a71152c LibJS: Wrap ParseErrorCallback typedef in Option
The automatic conversion of `Option<function pointer>` to a C function
pointer is only supported by cbindgen if the option is in the typedef
itself, rather than an argument type. This no-op commit will make a
future cbingen update happy.
2026-03-17 20:49:50 -05:00
juhotuho10
2a42ef36db LibJS/Rust: Apply lint clippy::explicit_iter_loop 2026-03-16 13:55:16 -05:00
juhotuho10
012c7d077b LibJS/Rust: Apply lint clippy::borrow_as_ptr 2026-03-16 13:55:16 -05:00
juhotuho10
8deedd4e67 LibJS/Rust: Apply lint clippy::unnested_or_patterns 2026-03-16 13:55:16 -05:00
juhotuho10
21d1cfdd63 LibJS/Rust: Apply lint clippy::redundant_clone 2026-03-16 13:55:16 -05:00
juhotuho10
dfa7993780 LibJS/Rust: Apply lint clippy::elidable_lifetime_names 2026-03-16 13:55:16 -05:00
juhotuho10
277177484e LibJS/Rust: Apply lint clippy::ref_option 2026-03-16 13:55:16 -05:00
juhotuho10
59251cc371 LibJS/Rust: Apply lint clippy::useless_let_if_seq 2026-03-16 13:55:16 -05:00
juhotuho10
57c2e40f0e LibJS/Rust: Apply lint clippy::unnecessary_wraps 2026-03-16 13:55:16 -05:00
juhotuho10
9ed1700558 LibJS/Rust: Apply lint clippy::manual_let_else 2026-03-16 13:55:16 -05:00
juhotuho10
3342e2c125 LibJS/Rust: Apply lint clippy::semicolon_if_nothing_returned 2026-03-16 13:55:16 -05:00
juhotuho10
671306d260 LibJS/Rust: Apply lint clippy::uninlined_format_args 2026-03-16 13:55:16 -05:00
Johan Dahlin
9454aa3796 LibJS: Replace FunctionTable sparse Vec with HashMap
Switch from a sparse Vec<Option<Box<FunctionData>>> keyed by numeric
FunctionId to FxHashMap<FunctionId, Box<FunctionData>>. The previous
representation allocated slots for every ID between 0 and max, wasting
memory when IDs are sparse (common in large bundles with many modules).
2026-03-15 10:51:47 -05:00