Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions crates/oxc_parser/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,11 @@ pub fn identifier_expected(span: Span) -> OxcDiagnostic {
OxcDiagnostic::error("Identifier expected.").with_label(span)
}

#[cold]
pub fn ts_identifier_expected(span: Span) -> OxcDiagnostic {
ts_error("1003", "Identifier expected.").with_label(span)
}

#[cold]
pub fn identifier_reserved_word(span: Span, reserved: &str) -> OxcDiagnostic {
OxcDiagnostic::error(format!(
Expand Down Expand Up @@ -571,6 +576,16 @@ pub fn ts_empty_type_argument_list(span: Span) -> OxcDiagnostic {
ts_error("1099", "Type argument list cannot be empty.").with_label(span)
}

#[cold]
pub fn ts_namespace_missing_name(span: Span) -> OxcDiagnostic {
ts_error("1437", "Namespace must be given a name.").with_label(span)
}

#[cold]
pub fn ts_module_missing_name(span: Span) -> OxcDiagnostic {
ts_error("1437", "Module must be given a name.").with_label(span)
}

#[cold]
pub fn unexpected_super(span: Span) -> OxcDiagnostic {
OxcDiagnostic::error("'super' can only be used with function calls or in property accesses")
Expand Down
22 changes: 22 additions & 0 deletions crates/oxc_parser/src/js/expression.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use cow_utils::CowUtils;
use oxc_allocator::{Box, TakeIn, Vec};
use oxc_ast::ast::*;
use oxc_diagnostics::OxcDiagnostic;
#[cfg(feature = "regular_expression")]
use oxc_regular_expression::ast::Pattern;
use oxc_span::{Atom, GetSpan, Span};
Expand Down Expand Up @@ -88,6 +89,27 @@ impl<'a> ParserImpl<'a> {
self.ast.binding_identifier(span, name)
}

/// `BindingIdentifier` with custom error for unexpected tokens
pub(crate) fn parse_binding_identifier_with_error(
&mut self,
unexpected_error: impl FnOnce(Span) -> OxcDiagnostic,
) -> BindingIdentifier<'a> {
let cur = self.cur_kind();
if !cur.is_binding_identifier() {
return if cur.is_reserved_keyword() {
let error =
diagnostics::identifier_reserved_word(self.cur_token().span(), cur.to_str());
self.fatal_error(error)
} else {
let error = unexpected_error(self.cur_token().span());
self.fatal_error(error)
};
}
self.check_identifier(cur, self.ctx);
let (span, name) = self.parse_identifier_kind(Kind::Ident);
self.ast.binding_identifier(span, name)
}

pub(crate) fn parse_label_identifier(&mut self) -> LabelIdentifier<'a> {
let kind = self.cur_kind();
if !kind.is_label_identifier(self.ctx.has_yield(), self.ctx.has_await()) {
Expand Down
23 changes: 21 additions & 2 deletions crates/oxc_parser/src/ts/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,25 @@ impl<'a> ParserImpl<'a> {
kind: TSModuleDeclarationKind,
modifiers: &Modifiers<'a>,
) -> Box<'a, TSModuleDeclaration<'a>> {
let id = TSModuleDeclarationName::Identifier(self.parse_binding_identifier());
// Check if we're at `{` to determine which error to use
// TS1437: "Namespace/Module must be given a name" for `namespace {`
// TS1003: "Identifier expected" for `namespace "string" {` or other non-identifiers
let is_missing_name = self.cur_kind() == Kind::LCurly;
let id =
TSModuleDeclarationName::Identifier(self.parse_binding_identifier_with_error(|span| {
if is_missing_name {
match kind {
TSModuleDeclarationKind::Namespace => {
diagnostics::ts_namespace_missing_name(span)
}
TSModuleDeclarationKind::Module => {
diagnostics::ts_module_missing_name(span)
}
}
} else {
diagnostics::ts_identifier_expected(span)
}
}));
let body = if self.eat(Kind::Dot) {
let span = self.start_span();
let decl = self.parse_module_or_namespace_declaration(span, kind, &Modifiers::empty());
Expand Down Expand Up @@ -610,7 +628,8 @@ impl<'a> ParserImpl<'a> {
self.bump_any();
return !self.cur_token().is_on_new_line()
&& (self.cur_kind().is_binding_identifier()
|| self.cur_kind() == Kind::Str);
|| self.cur_kind() == Kind::Str
|| self.cur_kind() == Kind::LCurly);
}
Kind::Abstract
| Kind::Accessor
Expand Down
4 changes: 2 additions & 2 deletions tasks/coverage/snapshots/parser_misc.snap
Original file line number Diff line number Diff line change
Expand Up @@ -357,13 +357,13 @@ Negative Passed: 118/118 (100.00%)
· ╰── `}` expected
╰────

× Unexpected token
× TS(1003): Identifier expected.
╭─[misc/fail/oxc-11592-1.ts:1:11]
1 │ namespace "a" {}
· ───
╰────

× Unexpected token
× TS(1003): Identifier expected.
╭─[misc/fail/oxc-11592-2.ts:1:11]
1 │ namespace "a";
· ───
Expand Down
28 changes: 12 additions & 16 deletions tasks/coverage/snapshots/parser_typescript.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2871,13 +2871,12 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/statements/Va
· ──
╰────

× Expected a semicolon or an implicit semicolon after a statement, but found none
╭─[typescript/tests/cases/compiler/anonymousModules.ts:1:7]
× TS(1437): Module must be given a name.
╭─[typescript/tests/cases/compiler/anonymousModules.ts:1:8]
1 │ module {
·
·
2 │ export var foo = 1;
╰────
help: Try inserting a semicolon here

× Identifier `myFn` has already been declared
╭─[typescript/tests/cases/compiler/anyDeclare.ts:3:9]
Expand Down Expand Up @@ -6392,13 +6391,12 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/statements/Va
17 │ public pe:string;
╰────

× Expected a semicolon or an implicit semicolon after a statement, but found none
╭─[typescript/tests/cases/compiler/externModule.ts:1:8]
× TS(1437): Module must be given a name.
╭─[typescript/tests/cases/compiler/externModule.ts:1:16]
1 │ declare module {
·
·
2 │ export class XDate {
╰────
help: Try inserting a semicolon here

× Expected `,` or `)` but found `=>`
╭─[typescript/tests/cases/compiler/fatarrowfunctionsErrors.ts:2:8]
Expand Down Expand Up @@ -6947,23 +6945,21 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/statements/Va
3 │ }
╰────

× Expected a semicolon or an implicit semicolon after a statement, but found none
╭─[typescript/tests/cases/compiler/innerModExport1.ts:5:11]
× TS(1437): Module must be given a name.
╭─[typescript/tests/cases/compiler/innerModExport1.ts:5:12]
4 │ var non_export_var: number;
5 │ module {
·
·
6 │ var non_export_var = 0;
╰────
help: Try inserting a semicolon here

× Expected a semicolon or an implicit semicolon after a statement, but found none
╭─[typescript/tests/cases/compiler/innerModExport2.ts:5:11]
× TS(1437): Module must be given a name.
╭─[typescript/tests/cases/compiler/innerModExport2.ts:5:12]
4 │ var non_export_var: number;
5 │ module {
·
·
6 │ var non_export_var = 0;
╰────
help: Try inserting a semicolon here

× TS(1099): Type argument list cannot be empty.
╭─[typescript/tests/cases/compiler/instantiateTypeParameter.ts:2:13]
Expand Down
Loading