Skip to content

fix(js): reject top-level import/export in scripts as a SyntaxError#88

Open
codymullins wants to merge 2 commits into
mainfrom
fix/js-script-import-export-syntaxerror
Open

fix(js): reject top-level import/export in scripts as a SyntaxError#88
codymullins wants to merge 2 commits into
mainfrom
fix/js-script-import-export-syntaxerror

Conversation

@codymullins

Copy link
Copy Markdown
Collaborator

What

Static ImportDeclaration and ExportDeclaration are module-only productions (a ScriptBody is just a StatementList). The parser accepted them in a script and the compiler later threw an internal NotSupportedException, so negative parse tests saw the wrong failure:

global-code/export.js :: expected parse error, got NotSupportedException
eval-code/direct/import.js :: host:NotSupportedException: statement kind 'ImportDeclaration' not yet supported

Fix

Guard the static import/export dispatch in ParseProgramStatement on the module goal (_module). In a script, a top-level import … / export … now throws a JsParseException — a parse-phase SyntaxError, which the eval path surfaces to JS as a SyntaxError. The import(...) and import.meta expression forms are unaffected (they route to ParseStatement before the guard).

Result (Test262, language scope)

Category Before After
language/global-code 40/75 — 53.3% 44/75 — 58.7%
language/eval-code 393/454 — 86.6% 397/454 — 87.4%

+8 scenarios across the two categories (the import/export parse tests in each).

Regression check

The new parse error fires on zero positive tests (grep of the full-language failure dump for the new message: 0 hits). The only behavior change is rejecting module syntax in a script, which was already a compile failure before. The full-language headline stays flat this run only because an unrelated batch of flaky async/import(...) tests in expressions/statements wobbled by ~the same count — a known run-to-run variance under the Debug harness, not caused by this change (a parser guard on the import/export statement tokens cannot affect those expressions).

Static ImportDeclaration and ExportDeclaration are module-only productions (spec sec-modules). In a script, which is the default goal, the parser accepted them and the compiler later threw an internal NotSupportedException, so a negative parse test saw the wrong failure (got NotSupportedException instead of a parse error).

Guard the static import/export dispatch in ParseProgramStatement on the module goal. In a script a top-level import/export now throws a JsParseException, which the eval path surfaces as a JS SyntaxError. The import(...) and import.meta expression forms are unaffected (they route to ParseStatement before the guard).

Test262 language/global-code 53.3% -> 58.7%, language/eval-code 86.6% -> 87.4% (+8 scenarios across both, the import/export parse tests).

No regression: the new parse error fires on zero positive tests. The full-language headline is flat only because an unrelated batch of flaky async/dynamic-import tests in expressions/statements wobbled by the same magnitude this run.
Copilot AI review requested due to automatic review settings June 17, 2026 01:54

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

The module-syntax parser tests parsed import/export through ParseProgram (the script goal), which now rejects them. Route those tests through the module goal where the productions are valid, and add tests that a top-level import/export in a script throws JsParseException while import(...) still parses. Two export-list tests declare their local bindings to satisfy the module-goal early-error pass.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants