Skip to content

Commit 26a2e7c

Browse files
committed
feat(typescript): parse 'declare namespace ...'
wip
1 parent d24e7ab commit 26a2e7c

17 files changed

+864
-8
lines changed

docs/CHANGELOG.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ Semantic Versioning.
1313
* TypeScript: Type variables such as `Readonly<T>` and `IArguments` are now
1414
recognized by the new `typescript` global group which is enabled by default.
1515
* TypeScript: `declare class`, `declare abstract class`, `declare const`,
16-
`declare let`, `declare var`, `declare type`, `declare interface`, and
17-
`declare function` are now supported.
16+
`declare let`, `declare var`, `declare type`, `declare interface`,
17+
`declare function`, and `declare namespace` are now supported.
1818
* `array[i, j]` now reports [E0450][] ("misleading use of ',' operator in
1919
index") (implemented by [Yunus][]).
2020
* `while (x > 0, y > 0)` now reports [E0451][] ("misleading use of ',' operator

po/de.po

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,27 @@ msgstr ""
295295
"Das 'enum' Feature aus TypeScript ist noch nicht in quick-lint-js "
296296
"implementiert"
297297

298+
#: src/quick-lint-js/diag/diagnostic-types.h
299+
msgid "'declare' should not be written inside a 'declare namespace'"
300+
msgstr ""
301+
302+
#: src/quick-lint-js/diag/diagnostic-types.h
303+
#, fuzzy
304+
msgid "containing 'declare namespace' starts here"
305+
msgstr "Array beginnt hier"
306+
307+
#: src/quick-lint-js/diag/diagnostic-types.h
308+
#, fuzzy
309+
msgid "'declare namespace' cannot contain statements, only declarations"
310+
msgstr ""
311+
"Das 'enum' Feature aus TypeScript ist noch nicht in quick-lint-js "
312+
"implementiert"
313+
314+
#: src/quick-lint-js/diag/diagnostic-types.h
315+
#, fuzzy
316+
msgid "'declare' here"
317+
msgstr "Funktionsaufruf beginnt hier"
318+
298319
#: src/quick-lint-js/diag/diagnostic-types.h
299320
#, fuzzy
300321
msgid "'declare {1}' cannot have initializer"

po/[email protected]

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,25 @@ msgstr "IIFE started here"
252252
msgid "TypeScript 'declare function' is not allowed in JavaScript"
253253
msgstr "TypeScript's 'interface' feature is not allowed in JavaScript code"
254254

255+
#: src/quick-lint-js/diag/diagnostic-types.h
256+
msgid "'declare' should not be written inside a 'declare namespace'"
257+
msgstr ""
258+
259+
#: src/quick-lint-js/diag/diagnostic-types.h
260+
#, fuzzy
261+
msgid "containing 'declare namespace' starts here"
262+
msgstr "you opened Pandora's Box here"
263+
264+
#: src/quick-lint-js/diag/diagnostic-types.h
265+
#, fuzzy
266+
msgid "'declare namespace' cannot contain statements, only declarations"
267+
msgstr "TypeScript's 'interface' feature is not allowed in JavaScript code"
268+
269+
#: src/quick-lint-js/diag/diagnostic-types.h
270+
#, fuzzy
271+
msgid "'declare' here"
272+
msgstr "IIFE started here"
273+
255274
#: src/quick-lint-js/diag/diagnostic-types.h
256275
#, fuzzy
257276
msgid "'declare {1}' cannot have initializer"

po/fr_FR.po

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,27 @@ msgstr ""
303303
"la fonctionnalité 'enum' de TypeScript n'est pas encore implémentée dans "
304304
"quick-lint-js"
305305

306+
#: src/quick-lint-js/diag/diagnostic-types.h
307+
msgid "'declare' should not be written inside a 'declare namespace'"
308+
msgstr ""
309+
310+
#: src/quick-lint-js/diag/diagnostic-types.h
311+
#, fuzzy
312+
msgid "containing 'declare namespace' starts here"
313+
msgstr "tableau débuté ici"
314+
315+
#: src/quick-lint-js/diag/diagnostic-types.h
316+
#, fuzzy
317+
msgid "'declare namespace' cannot contain statements, only declarations"
318+
msgstr ""
319+
"la fonctionnalité 'enum' de TypeScript n'est pas encore implémentée dans "
320+
"quick-lint-js"
321+
322+
#: src/quick-lint-js/diag/diagnostic-types.h
323+
#, fuzzy
324+
msgid "'declare' here"
325+
msgstr "appel de fonction débuté ici"
326+
306327
#: src/quick-lint-js/diag/diagnostic-types.h
307328
#, fuzzy
308329
msgid "'declare {1}' cannot have initializer"

po/messages.pot

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,22 @@ msgstr ""
243243
msgid "TypeScript 'declare function' is not allowed in JavaScript"
244244
msgstr ""
245245

246+
#: src/quick-lint-js/diag/diagnostic-types.h
247+
msgid "'declare' should not be written inside a 'declare namespace'"
248+
msgstr ""
249+
250+
#: src/quick-lint-js/diag/diagnostic-types.h
251+
msgid "containing 'declare namespace' starts here"
252+
msgstr ""
253+
254+
#: src/quick-lint-js/diag/diagnostic-types.h
255+
msgid "'declare namespace' cannot contain statements, only declarations"
256+
msgstr ""
257+
258+
#: src/quick-lint-js/diag/diagnostic-types.h
259+
msgid "'declare' here"
260+
msgstr ""
261+
246262
#: src/quick-lint-js/diag/diagnostic-types.h
247263
msgid "'declare {1}' cannot have initializer"
248264
msgstr ""

po/pt_BR.po

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,25 @@ msgstr "'function' está aqui"
253253
msgid "TypeScript 'declare function' is not allowed in JavaScript"
254254
msgstr "'implements' não é permitido em JavaScript"
255255

256+
#: src/quick-lint-js/diag/diagnostic-types.h
257+
msgid "'declare' should not be written inside a 'declare namespace'"
258+
msgstr ""
259+
260+
#: src/quick-lint-js/diag/diagnostic-types.h
261+
#, fuzzy
262+
msgid "containing 'declare namespace' starts here"
263+
msgstr "array iniciou aqui"
264+
265+
#: src/quick-lint-js/diag/diagnostic-types.h
266+
#, fuzzy
267+
msgid "'declare namespace' cannot contain statements, only declarations"
268+
msgstr "interfaces não podem conter blocos estáticos"
269+
270+
#: src/quick-lint-js/diag/diagnostic-types.h
271+
#, fuzzy
272+
msgid "'declare' here"
273+
msgstr "'function' está aqui"
274+
256275
#: src/quick-lint-js/diag/diagnostic-types.h
257276
#, fuzzy
258277
msgid "'declare {1}' cannot have initializer"

po/sv_SE.po

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,25 @@ msgstr "funktionkallelse startar här"
268268
msgid "TypeScript 'declare function' is not allowed in JavaScript"
269269
msgstr "TypeScripts 'enum' är inte ännu implementerad av quick-lint-js"
270270

271+
#: src/quick-lint-js/diag/diagnostic-types.h
272+
msgid "'declare' should not be written inside a 'declare namespace'"
273+
msgstr ""
274+
275+
#: src/quick-lint-js/diag/diagnostic-types.h
276+
#, fuzzy
277+
msgid "containing 'declare namespace' starts here"
278+
msgstr "lista startar här"
279+
280+
#: src/quick-lint-js/diag/diagnostic-types.h
281+
#, fuzzy
282+
msgid "'declare namespace' cannot contain statements, only declarations"
283+
msgstr "TypeScripts 'enum' är inte ännu implementerad av quick-lint-js"
284+
285+
#: src/quick-lint-js/diag/diagnostic-types.h
286+
#, fuzzy
287+
msgid "'declare' here"
288+
msgstr "funktionkallelse startar här"
289+
271290
#: src/quick-lint-js/diag/diagnostic-types.h
272291
#, fuzzy
273292
msgid "'declare {1}' cannot have initializer"

src/quick-lint-js/diag/diagnostic-types.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,33 @@
302302
"allowed in JavaScript"), \
303303
declare_keyword)) \
304304
\
305+
QLJS_DIAG_TYPE( \
306+
diag_declare_keyword_is_not_allowed_inside_declare_namespace, "E0358", \
307+
diagnostic_severity::error, \
308+
{ \
309+
source_code_span declare_keyword; \
310+
source_code_span declare_namespace_declare_keyword; \
311+
}, \
312+
MESSAGE( \
313+
QLJS_TRANSLATABLE( \
314+
"'declare' should not be written inside a 'declare namespace'"), \
315+
declare_keyword) \
316+
MESSAGE( \
317+
QLJS_TRANSLATABLE("containing 'declare namespace' starts here"), \
318+
declare_namespace_declare_keyword)) \
319+
\
320+
QLJS_DIAG_TYPE( \
321+
diag_declare_namespace_cannot_contain_statement, "E0357", \
322+
diagnostic_severity::error, \
323+
{ \
324+
source_code_span first_statement_token; \
325+
source_code_span declare_keyword; \
326+
}, \
327+
MESSAGE(QLJS_TRANSLATABLE("'declare namespace' cannot contain " \
328+
"statements, only declarations"), \
329+
first_statement_token) \
330+
MESSAGE(QLJS_TRANSLATABLE("'declare' here"), declare_keyword)) \
331+
\
305332
QLJS_DIAG_TYPE( \
306333
diag_declare_var_cannot_have_initializer, "E0351", \
307334
diagnostic_severity::error, \

src/quick-lint-js/fe/parse-statement.cpp

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2017,6 +2017,23 @@ void parser::parse_and_visit_switch(parse_visitor_base &v) {
20172017

20182018
void parser::parse_and_visit_typescript_namespace(
20192019
parse_visitor_base &v, source_code_span namespace_keyword_span) {
2020+
this->parse_and_visit_typescript_namespace_head(v, namespace_keyword_span);
2021+
2022+
if (this->peek().type != token_type::left_curly) {
2023+
this->diag_reporter_->report(diag_missing_body_for_typescript_namespace{
2024+
.expected_body =
2025+
source_code_span::unit(this->lexer_.end_of_previous_token()),
2026+
});
2027+
return;
2028+
}
2029+
2030+
v.visit_enter_namespace_scope();
2031+
this->parse_and_visit_statement_block_no_scope(v);
2032+
v.visit_exit_namespace_scope();
2033+
}
2034+
2035+
void parser::parse_and_visit_typescript_namespace_head(
2036+
parse_visitor_base &v, source_code_span namespace_keyword_span) {
20202037
if (this->peek().has_leading_newline) {
20212038
this->diag_reporter_->report(
20222039
diag_newline_not_allowed_after_namespace_keyword{
@@ -2043,6 +2060,14 @@ void parser::parse_and_visit_typescript_namespace(
20432060
QLJS_PARSER_UNIMPLEMENTED();
20442061
break;
20452062
}
2063+
}
2064+
2065+
void parser::parse_and_visit_typescript_declare_namespace(
2066+
parse_visitor_base &v, source_code_span declare_keyword_span) {
2067+
QLJS_ASSERT(this->peek().type == token_type::kw_namespace);
2068+
source_code_span namespace_keyword_span = this->peek().span();
2069+
this->skip();
2070+
this->parse_and_visit_typescript_namespace_head(v, namespace_keyword_span);
20462071

20472072
if (this->peek().type != token_type::left_curly) {
20482073
this->diag_reporter_->report(diag_missing_body_for_typescript_namespace{
@@ -2051,9 +2076,62 @@ void parser::parse_and_visit_typescript_namespace(
20512076
});
20522077
return;
20532078
}
2079+
source_code_span left_curly_span = this->peek().span();
2080+
this->skip();
20542081

20552082
v.visit_enter_namespace_scope();
2056-
this->parse_and_visit_statement_block_no_scope(v);
2083+
for (;;) {
2084+
switch (this->peek().type) {
2085+
// TODO(strager): Deduplicate list with
2086+
// parse_and_visit_possible_declare_statement.
2087+
case token_type::kw_abstract:
2088+
case token_type::kw_async:
2089+
case token_type::kw_class:
2090+
case token_type::kw_const:
2091+
case token_type::kw_enum:
2092+
case token_type::kw_function:
2093+
case token_type::kw_let:
2094+
case token_type::kw_namespace:
2095+
case token_type::kw_var:
2096+
this->parse_and_visit_declare_statement(v, declare_keyword_span);
2097+
break;
2098+
2099+
case token_type::right_curly:
2100+
this->skip();
2101+
goto done;
2102+
2103+
case token_type::end_of_file:
2104+
this->diag_reporter_->report(diag_unclosed_code_block{
2105+
.block_open = left_curly_span,
2106+
});
2107+
goto done;
2108+
2109+
case token_type::kw_declare: {
2110+
this->diag_reporter_->report(
2111+
diag_declare_keyword_is_not_allowed_inside_declare_namespace{
2112+
.declare_keyword = this->peek().span(),
2113+
.declare_namespace_declare_keyword = declare_keyword_span,
2114+
});
2115+
bool parsed_statement = this->parse_and_visit_statement(
2116+
v, parse_statement_type::any_statement_in_block);
2117+
QLJS_ASSERT(parsed_statement);
2118+
break;
2119+
}
2120+
2121+
default: {
2122+
this->diag_reporter_->report(
2123+
diag_declare_namespace_cannot_contain_statement{
2124+
.first_statement_token = this->peek().span(),
2125+
.declare_keyword = declare_keyword_span,
2126+
});
2127+
bool parsed_statement = this->parse_and_visit_statement(
2128+
v, parse_statement_type::any_statement_in_block);
2129+
QLJS_ASSERT(parsed_statement);
2130+
break;
2131+
}
2132+
}
2133+
}
2134+
done:
20572135
v.visit_exit_namespace_scope();
20582136
}
20592137

@@ -4480,6 +4558,7 @@ parser::parse_and_visit_possible_declare_statement(parse_visitor_base &v) {
44804558
case token_type::kw_type:
44814559
case token_type::kw_var:
44824560
case token_type::kw_function:
4561+
case token_type::kw_namespace:
44834562
this->lexer_.commit_transaction(std::move(transaction));
44844563
this->parse_and_visit_declare_statement(v, declare_keyword_span);
44854564
return parse_possible_declare_result::parsed;
@@ -4680,6 +4759,11 @@ void parser::parse_and_visit_declare_statement(
46804759
break;
46814760
}
46824761

4762+
// declare namespace ns {}
4763+
case token_type::kw_namespace:
4764+
this->parse_and_visit_typescript_declare_namespace(v, declare_keyword_span);
4765+
break;
4766+
46834767
// declare: // Label.
46844768
// declare();
46854769
case token_type::colon:

src/quick-lint-js/fe/parse.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,10 @@ class parser {
368368

369369
void parse_and_visit_typescript_namespace(
370370
parse_visitor_base &v, source_code_span namespace_keyword_span);
371+
void parse_and_visit_typescript_namespace_head(
372+
parse_visitor_base &v, source_code_span namespace_keyword_span);
373+
void parse_and_visit_typescript_declare_namespace(
374+
parse_visitor_base &v, source_code_span declare_keyword_span);
371375

372376
void parse_and_visit_typescript_type_alias(parse_visitor_base &v,
373377
source_code_span type_token);

0 commit comments

Comments
 (0)