@@ -372,7 +372,6 @@ bool parser::parse_and_visit_statement(
372372 case token_type::kw_intrinsic:
373373 case token_type::kw_is:
374374 case token_type::kw_keyof:
375- case token_type::kw_module:
376375 case token_type::kw_never:
377376 case token_type::kw_number:
378377 case token_type::kw_object:
@@ -423,6 +422,7 @@ bool parser::parse_and_visit_statement(
423422 // interface * x;
424423 // interface I {} // TypeScript only.
425424 case token_type::kw_interface:
425+ case token_type::kw_module:
426426 case token_type::kw_namespace:
427427 case token_type::kw_type:
428428 switch (
@@ -622,11 +622,14 @@ parser::parse_and_visit_typescript_interface_or_namespace_or_type_statement(
622622
623623 // type T = number; // TypeScript only.
624624 //
625+ // namespace 'my namespace name' {} // Invalid.
626+ //
625627 // type // ASI
626628 // f();
627629 QLJS_CASE_CONTEXTUAL_KEYWORD:
628630 case token_type::kw_await:
629631 case token_type::identifier:
632+ case token_type::string:
630633 if (this ->peek ().has_leading_newline ) {
631634 bool is_expression = true ;
632635 if (initial_keyword.type == token_type::kw_interface) {
@@ -657,7 +660,8 @@ parser::parse_and_visit_typescript_interface_or_namespace_or_type_statement(
657660 });
658661 }
659662 }
660- if (initial_keyword.type == token_type::kw_namespace) {
663+ if (initial_keyword.type == token_type::kw_module ||
664+ initial_keyword.type == token_type::kw_namespace) {
661665 lexer_transaction inner_transaction = this ->lexer_ .begin_transaction ();
662666 this ->skip ();
663667 if (this ->peek ().type == token_type::left_curly &&
@@ -679,8 +683,11 @@ parser::parse_and_visit_typescript_interface_or_namespace_or_type_statement(
679683 case token_type::kw_interface:
680684 this ->parse_and_visit_typescript_interface (v, initial_keyword.span ());
681685 break ;
686+ case token_type::kw_module:
682687 case token_type::kw_namespace:
683- this ->parse_and_visit_typescript_namespace (v, initial_keyword.span ());
688+ this ->parse_and_visit_typescript_namespace (
689+ v,
690+ /* export_keyword_span=*/ std::nullopt , initial_keyword.span ());
684691 break ;
685692 case token_type::kw_type:
686693 this ->parse_and_visit_typescript_type_alias (v, initial_keyword.span ());
@@ -1100,10 +1107,13 @@ void parser::parse_and_visit_export(parse_visitor_base &v) {
11001107 break ;
11011108
11021109 // export namespace ns {} // TypeScript only.
1110+ case token_type::kw_module:
11031111 case token_type::kw_namespace: {
11041112 source_code_span namespace_keyword = this ->peek ().span ();
11051113 this ->skip ();
1106- this ->parse_and_visit_typescript_namespace (v, namespace_keyword);
1114+ this ->parse_and_visit_typescript_namespace (
1115+ v,
1116+ /* export_keyword_span=*/ export_token_span, namespace_keyword);
11071117 break ;
11081118 }
11091119
@@ -2016,8 +2026,14 @@ void parser::parse_and_visit_switch(parse_visitor_base &v) {
20162026}
20172027
20182028void parser::parse_and_visit_typescript_namespace (
2019- parse_visitor_base &v, source_code_span namespace_keyword_span) {
2020- this ->parse_and_visit_typescript_namespace_head (v, namespace_keyword_span);
2029+ parse_visitor_base &v, std::optional<source_code_span> export_keyword_span,
2030+ source_code_span namespace_keyword_span) {
2031+ this ->parse_and_visit_typescript_namespace_head (
2032+ v,
2033+ /* export_keyword_span=*/ export_keyword_span,
2034+ /* declare_keyword_span=*/ std::nullopt , namespace_keyword_span);
2035+
2036+ typescript_namespace_guard g = this ->enter_typescript_namespace ();
20212037
20222038 if (this ->peek ().type != token_type::left_curly) {
20232039 this ->diag_reporter_ ->report (diag_missing_body_for_typescript_namespace{
@@ -2033,7 +2049,9 @@ void parser::parse_and_visit_typescript_namespace(
20332049}
20342050
20352051void parser::parse_and_visit_typescript_namespace_head (
2036- parse_visitor_base &v, source_code_span namespace_keyword_span) {
2052+ parse_visitor_base &v, std::optional<source_code_span> export_keyword_span,
2053+ std::optional<source_code_span> declare_keyword_span,
2054+ source_code_span namespace_keyword_span) {
20372055 if (this ->peek ().has_leading_newline ) {
20382056 this ->diag_reporter_ ->report (
20392057 diag_newline_not_allowed_after_namespace_keyword{
@@ -2048,6 +2066,7 @@ void parser::parse_and_visit_typescript_namespace_head(
20482066 }
20492067
20502068 switch (this ->peek ().type ) {
2069+ // namespace ns { }
20512070 QLJS_CASE_CONTEXTUAL_KEYWORD:
20522071 case token_type::identifier:
20532072 v.visit_variable_declaration (this ->peek ().identifier_name (),
@@ -2056,6 +2075,27 @@ void parser::parse_and_visit_typescript_namespace_head(
20562075 this ->skip ();
20572076 break ;
20582077
2078+ // module 'my namespace' { }
2079+ // namespace 'ns' { } // Invalid.
2080+ case token_type::string: {
2081+ bool namespace_keyword_is_module =
2082+ namespace_keyword_span.string_view ()[0 ] == u8 ' m' ;
2083+ if (!namespace_keyword_is_module || !declare_keyword_span.has_value () ||
2084+ export_keyword_span.has_value ()) {
2085+ this ->diag_reporter_ ->report (
2086+ diag_string_namespace_name_is_only_allowed_with_declare_module{
2087+ .module_name = this ->peek ().span (),
2088+ });
2089+ } else if (this ->in_typescript_namespace_ ) {
2090+ this ->diag_reporter_ ->report (
2091+ diag_string_namespace_name_is_only_allowed_at_top_level{
2092+ .module_name = this ->peek ().span (),
2093+ });
2094+ }
2095+ this ->skip ();
2096+ break ;
2097+ }
2098+
20592099 default :
20602100 QLJS_PARSER_UNIMPLEMENTED ();
20612101 break ;
@@ -2064,10 +2104,16 @@ void parser::parse_and_visit_typescript_namespace_head(
20642104
20652105void parser::parse_and_visit_typescript_declare_namespace (
20662106 parse_visitor_base &v, source_code_span declare_keyword_span) {
2067- QLJS_ASSERT (this ->peek ().type == token_type::kw_namespace);
2107+ QLJS_ASSERT (this ->peek ().type == token_type::kw_module ||
2108+ this ->peek ().type == token_type::kw_namespace);
20682109 source_code_span namespace_keyword_span = this ->peek ().span ();
20692110 this ->skip ();
2070- this ->parse_and_visit_typescript_namespace_head (v, namespace_keyword_span);
2111+ this ->parse_and_visit_typescript_namespace_head (
2112+ v,
2113+ /* export_keyword_span=*/ std::nullopt ,
2114+ /* declare_keyword_span=*/ declare_keyword_span, namespace_keyword_span);
2115+
2116+ typescript_namespace_guard g = this ->enter_typescript_namespace ();
20712117
20722118 if (this ->peek ().type != token_type::left_curly) {
20732119 this ->diag_reporter_ ->report (diag_missing_body_for_typescript_namespace{
@@ -2091,6 +2137,7 @@ void parser::parse_and_visit_typescript_declare_namespace(
20912137 case token_type::kw_enum:
20922138 case token_type::kw_function:
20932139 case token_type::kw_let:
2140+ case token_type::kw_module:
20942141 case token_type::kw_namespace:
20952142 case token_type::kw_var:
20962143 this ->parse_and_visit_declare_statement (v, declare_keyword_span);
@@ -4558,6 +4605,7 @@ parser::parse_and_visit_possible_declare_statement(parse_visitor_base &v) {
45584605 case token_type::kw_type:
45594606 case token_type::kw_var:
45604607 case token_type::kw_function:
4608+ case token_type::kw_module:
45614609 case token_type::kw_namespace:
45624610 this ->lexer_ .commit_transaction (std::move (transaction));
45634611 this ->parse_and_visit_declare_statement (v, declare_keyword_span);
@@ -4760,6 +4808,7 @@ void parser::parse_and_visit_declare_statement(
47604808 }
47614809
47624810 // declare namespace ns {}
4811+ case token_type::kw_module:
47634812 case token_type::kw_namespace:
47644813 this ->parse_and_visit_typescript_declare_namespace (v, declare_keyword_span);
47654814 break ;
0 commit comments