From 24a20061f1ce45608a8ec43f3527539ada409f65 Mon Sep 17 00:00:00 2001 From: romdotdog <70765447+romdotdog@users.noreply.github.com> Date: Tue, 30 Nov 2021 22:27:28 -0600 Subject: [PATCH 1/4] add `declare` to parser --- src/extra/ast.ts | 3 +++ src/parser.ts | 45 ++++++++++++++++++++++++++++++++ tests/parser/class.ts | 12 +++++++++ tests/parser/class.ts.fixture.ts | 9 +++++++ 4 files changed, 69 insertions(+) diff --git a/src/extra/ast.ts b/src/extra/ast.ts index ffa272d1a8..cbffac40fb 100644 --- a/src/extra/ast.ts +++ b/src/extra/ast.ts @@ -1677,6 +1677,9 @@ export class ASTBuilder { serializeAccessModifiers(node: DeclarationStatement): void { var sb = this.sb; + if (node.is(CommonFlags.DECLARE)) { + sb.push("declare "); + } if (node.is(CommonFlags.PUBLIC)) { sb.push("public "); } else if (node.is(CommonFlags.PRIVATE)) { diff --git a/src/parser.ts b/src/parser.ts index 53bbdd0562..35562fa108 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -1839,6 +1839,7 @@ export class Parser extends DiagnosticEmitter { ): Node | null { // before: + // 'declare'? // ('public' | 'private' | 'protected')? // ('static' | 'abstract')? // 'readonly'? @@ -1870,6 +1871,37 @@ export class Parser extends DiagnosticEmitter { // implemented methods are virtual if (isInterface) flags |= CommonFlags.VIRTUAL; + var declareStart = 0; + var declareEnd = 0; + var contextIsAmbient = parent.is(CommonFlags.AMBIENT); + if (tn.skip(Token.DECLARE)) { + if (isInterface) { + this.error( + DiagnosticCode._0_modifier_cannot_be_used_here, + tn.range(), "declare" + ); + } else { + if (contextIsAmbient) { + this.error( + DiagnosticCode.A_declare_modifier_cannot_be_used_in_an_already_ambient_context, + tn.range() + ); // recoverable + } else { + this.error( + DiagnosticCode.Not_implemented_0, + tn.range(), "Ambient fields" + ); // recoverable + + flags |= CommonFlags.DECLARE | CommonFlags.AMBIENT; + declareStart = tn.tokenPos; + declareEnd = tn.pos; + } + } + if (!startPos) startPos = tn.tokenPos; + } else if (contextIsAmbient) { + flags |= CommonFlags.AMBIENT; + } + var accessStart = 0; var accessEnd = 0; if (tn.skip(Token.PUBLIC)) { @@ -2108,6 +2140,13 @@ export class Parser extends DiagnosticEmitter { // method: '(' Parameters (':' Type)? '{' Statement* '}' ';'? if (tn.skip(Token.OPENPAREN)) { + if (flags & CommonFlags.DECLARE) { + this.error( + DiagnosticCode._0_modifier_cannot_be_used_here, + tn.range(declareStart, declareEnd), "declare" + ); // recoverable + } + let signatureStart = tn.tokenPos; let parameters = this.parseParameters(tn, isConstructor); if (!parameters) return null; @@ -2291,6 +2330,12 @@ export class Parser extends DiagnosticEmitter { } let initializer: Expression | null = null; if (tn.skip(Token.EQUALS)) { + if (flags & CommonFlags.AMBIENT) { + this.error( + DiagnosticCode.Initializers_are_not_allowed_in_ambient_contexts, + tn.range() + ); // recoverable + } initializer = this.parseExpression(tn); if (!initializer) return null; } diff --git a/tests/parser/class.ts b/tests/parser/class.ts index e80a34b527..ad0113b9e1 100644 --- a/tests/parser/class.ts +++ b/tests/parser/class.ts @@ -26,4 +26,16 @@ export class Invalid { // 1049: A 'set' accessor must have exactly one parameter. // 1095: A 'set' accessor cannot have a return type annotation. set instanceSetter(): i32 {} + + // 100: Not implemented: Ambient fields + declare declareField: i32; + + // 100: Not implemented: Ambient fields + // 1039: Initializers are not allowed in ambient contexts. + declare declareInitializer: i32 = 0; + + // 100: Not implemented: Ambient fields + // 1042: 'declare' modifier cannot be used here. + // 1183: An implementation cannot be declared in ambient contexts. + declare declareMethod(): i32 {} } diff --git a/tests/parser/class.ts.fixture.ts b/tests/parser/class.ts.fixture.ts index dfdd064c5b..a4e592890e 100644 --- a/tests/parser/class.ts.fixture.ts +++ b/tests/parser/class.ts.fixture.ts @@ -14,6 +14,9 @@ export class Invalid { instanceFunction() {} get instanceGetter(a: i32) {} set instanceSetter() {} + declare declareField: i32; + declare declareInitializer: i32 = 0; + declare declareMethod(): i32 {} } // ERROR 1092: "Type parameters cannot appear on a constructor declaration." in class.ts(15,14+3) // ERROR 1110: "Type expected." in class.ts(18,21+0) @@ -23,3 +26,9 @@ export class Invalid { // ERROR 1094: "An accessor cannot have type parameters." in class.ts(28,21+3) // ERROR 1049: "A 'set' accessor must have exactly one parameter." in class.ts(28,7+14) // ERROR 1095: "A 'set' accessor cannot have a return type annotation." in class.ts(28,26+1) +// ERROR 100: "Not implemented: Ambient fields" in class.ts(31,3+7) +// ERROR 100: "Not implemented: Ambient fields" in class.ts(35,3+7) +// ERROR 1039: "Initializers are not allowed in ambient contexts." in class.ts(35,35+1) +// ERROR 100: "Not implemented: Ambient fields" in class.ts(40,3+7) +// ERROR 1042: "'declare' modifier cannot be used here." in class.ts(40,3+7) +// ERROR 1183: "An implementation cannot be declared in ambient contexts." in class.ts(40,32+1) From 64b51cccddcccc87fffcc2be6fbd96dd681f0ec4 Mon Sep 17 00:00:00 2001 From: romdotdog <70765447+romdotdog@users.noreply.github.com> Date: Tue, 30 Nov 2021 22:33:55 -0600 Subject: [PATCH 2/4] forgot to parse as identifier --- src/parser.ts | 47 +++++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/src/parser.ts b/src/parser.ts index 35562fa108..e1ee5f0305 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -1874,30 +1874,37 @@ export class Parser extends DiagnosticEmitter { var declareStart = 0; var declareEnd = 0; var contextIsAmbient = parent.is(CommonFlags.AMBIENT); - if (tn.skip(Token.DECLARE)) { - if (isInterface) { - this.error( - DiagnosticCode._0_modifier_cannot_be_used_here, - tn.range(), "declare" - ); - } else { - if (contextIsAmbient) { + if (tn.peek() == Token.DECLARE) { + let state = tn.mark(); + tn.next(); + if (tn.peek() != Token.COLON) { // modifier + tn.discard(state); + if (isInterface) { this.error( - DiagnosticCode.A_declare_modifier_cannot_be_used_in_an_already_ambient_context, - tn.range() - ); // recoverable + DiagnosticCode._0_modifier_cannot_be_used_here, + tn.range(), "declare" + ); } else { - this.error( - DiagnosticCode.Not_implemented_0, - tn.range(), "Ambient fields" - ); // recoverable - - flags |= CommonFlags.DECLARE | CommonFlags.AMBIENT; - declareStart = tn.tokenPos; - declareEnd = tn.pos; + if (contextIsAmbient) { + this.error( + DiagnosticCode.A_declare_modifier_cannot_be_used_in_an_already_ambient_context, + tn.range() + ); // recoverable + } else { + this.error( + DiagnosticCode.Not_implemented_0, + tn.range(), "Ambient fields" + ); // recoverable + + flags |= CommonFlags.DECLARE | CommonFlags.AMBIENT; + declareStart = tn.tokenPos; + declareEnd = tn.pos; + } } + if (!startPos) startPos = tn.tokenPos; + } else { // identifier + tn.reset(state); } - if (!startPos) startPos = tn.tokenPos; } else if (contextIsAmbient) { flags |= CommonFlags.AMBIENT; } From bb284a120c093590a4b0f59691acdfc0c1c6b879 Mon Sep 17 00:00:00 2001 From: romdotdog <70765447+romdotdog@users.noreply.github.com> Date: Wed, 1 Dec 2021 18:18:41 -0600 Subject: [PATCH 3/4] revise error messages --- src/diagnosticMessages.generated.ts | 2 ++ src/diagnosticMessages.json | 1 + src/parser.ts | 14 ++++++++------ tests/parser/class.ts | 3 +-- tests/parser/class.ts.fixture.ts | 5 ++--- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/diagnosticMessages.generated.ts b/src/diagnosticMessages.generated.ts index 2db65faca4..08f802e245 100644 --- a/src/diagnosticMessages.generated.ts +++ b/src/diagnosticMessages.generated.ts @@ -65,6 +65,7 @@ export enum DiagnosticCode { A_rest_parameter_must_be_last_in_a_parameter_list = 1014, Parameter_cannot_have_question_mark_and_initializer = 1015, A_required_parameter_cannot_follow_an_optional_parameter = 1016, + _0_modifier_cannot_appear_on_class_elements_of_this_kind = 1031, Statements_are_not_allowed_in_ambient_contexts = 1036, Initializers_are_not_allowed_in_ambient_contexts = 1039, _0_modifier_cannot_be_used_here = 1042, @@ -249,6 +250,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string { case 1014: return "A rest parameter must be last in a parameter list."; case 1015: return "Parameter cannot have question mark and initializer."; case 1016: return "A required parameter cannot follow an optional parameter."; + case 1031: return "'{0}' modifier cannot appear on class elements of this kind."; case 1036: return "Statements are not allowed in ambient contexts."; case 1039: return "Initializers are not allowed in ambient contexts."; case 1042: return "'{0}' modifier cannot be used here."; diff --git a/src/diagnosticMessages.json b/src/diagnosticMessages.json index 0b6d18ab7b..80ad2ef498 100644 --- a/src/diagnosticMessages.json +++ b/src/diagnosticMessages.json @@ -62,6 +62,7 @@ "A rest parameter must be last in a parameter list.": 1014, "Parameter cannot have question mark and initializer.": 1015, "A required parameter cannot follow an optional parameter.": 1016, + "'{0}' modifier cannot appear on class elements of this kind.": 1031, "Statements are not allowed in ambient contexts.": 1036, "Initializers are not allowed in ambient contexts.": 1039, "'{0}' modifier cannot be used here.": 1042, diff --git a/src/parser.ts b/src/parser.ts index e1ee5f0305..d3185a23d3 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -1891,11 +1891,6 @@ export class Parser extends DiagnosticEmitter { tn.range() ); // recoverable } else { - this.error( - DiagnosticCode.Not_implemented_0, - tn.range(), "Ambient fields" - ); // recoverable - flags |= CommonFlags.DECLARE | CommonFlags.AMBIENT; declareStart = tn.tokenPos; declareEnd = tn.pos; @@ -2149,7 +2144,7 @@ export class Parser extends DiagnosticEmitter { if (tn.skip(Token.OPENPAREN)) { if (flags & CommonFlags.DECLARE) { this.error( - DiagnosticCode._0_modifier_cannot_be_used_here, + DiagnosticCode._0_modifier_cannot_appear_on_class_elements_of_this_kind, tn.range(declareStart, declareEnd), "declare" ); // recoverable } @@ -2295,6 +2290,13 @@ export class Parser extends DiagnosticEmitter { // field: (':' Type)? ('=' Expression)? ';'? } else { + if (flags & CommonFlags.DECLARE) { + this.error( + DiagnosticCode.Not_implemented_0, + tn.range(declareStart, declareEnd), "Ambient fields" + ); // recoverable + } + if (flags & CommonFlags.ABSTRACT) { this.error( DiagnosticCode._0_modifier_cannot_be_used_here, diff --git a/tests/parser/class.ts b/tests/parser/class.ts index ad0113b9e1..b55a2880e6 100644 --- a/tests/parser/class.ts +++ b/tests/parser/class.ts @@ -34,8 +34,7 @@ export class Invalid { // 1039: Initializers are not allowed in ambient contexts. declare declareInitializer: i32 = 0; - // 100: Not implemented: Ambient fields - // 1042: 'declare' modifier cannot be used here. + // 1031: 'declare' modifier cannot appear on class elements of this kind. // 1183: An implementation cannot be declared in ambient contexts. declare declareMethod(): i32 {} } diff --git a/tests/parser/class.ts.fixture.ts b/tests/parser/class.ts.fixture.ts index a4e592890e..9d25f7a31d 100644 --- a/tests/parser/class.ts.fixture.ts +++ b/tests/parser/class.ts.fixture.ts @@ -29,6 +29,5 @@ export class Invalid { // ERROR 100: "Not implemented: Ambient fields" in class.ts(31,3+7) // ERROR 100: "Not implemented: Ambient fields" in class.ts(35,3+7) // ERROR 1039: "Initializers are not allowed in ambient contexts." in class.ts(35,35+1) -// ERROR 100: "Not implemented: Ambient fields" in class.ts(40,3+7) -// ERROR 1042: "'declare' modifier cannot be used here." in class.ts(40,3+7) -// ERROR 1183: "An implementation cannot be declared in ambient contexts." in class.ts(40,32+1) +// ERROR 1031: "'declare' modifier cannot appear on class elements of this kind." in class.ts(39,3+7) +// ERROR 1183: "An implementation cannot be declared in ambient contexts." in class.ts(39,32+1) From 73999e9cd79b8ebf8d30fb8d5d56305c42656e20 Mon Sep 17 00:00:00 2001 From: romdotdog <70765447+romdotdog@users.noreply.github.com> Date: Wed, 1 Dec 2021 22:23:57 -0600 Subject: [PATCH 4/4] declare is a keyword (temporarily) --- src/parser.ts | 37 +++++++++------------- tests/parser/also-identifier.ts | 4 +-- tests/parser/also-identifier.ts.fixture.ts | 2 -- 3 files changed, 17 insertions(+), 26 deletions(-) diff --git a/src/parser.ts b/src/parser.ts index d3185a23d3..60510cdcd0 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -1874,32 +1874,25 @@ export class Parser extends DiagnosticEmitter { var declareStart = 0; var declareEnd = 0; var contextIsAmbient = parent.is(CommonFlags.AMBIENT); - if (tn.peek() == Token.DECLARE) { - let state = tn.mark(); - tn.next(); - if (tn.peek() != Token.COLON) { // modifier - tn.discard(state); - if (isInterface) { + if (tn.skip(Token.DECLARE)) { + if (isInterface) { + this.error( + DiagnosticCode._0_modifier_cannot_be_used_here, + tn.range(), "declare" + ); + } else { + if (contextIsAmbient) { this.error( - DiagnosticCode._0_modifier_cannot_be_used_here, - tn.range(), "declare" - ); + DiagnosticCode.A_declare_modifier_cannot_be_used_in_an_already_ambient_context, + tn.range() + ); // recoverable } else { - if (contextIsAmbient) { - this.error( - DiagnosticCode.A_declare_modifier_cannot_be_used_in_an_already_ambient_context, - tn.range() - ); // recoverable - } else { - flags |= CommonFlags.DECLARE | CommonFlags.AMBIENT; - declareStart = tn.tokenPos; - declareEnd = tn.pos; - } + flags |= CommonFlags.DECLARE | CommonFlags.AMBIENT; + declareStart = tn.tokenPos; + declareEnd = tn.pos; } - if (!startPos) startPos = tn.tokenPos; - } else { // identifier - tn.reset(state); } + if (!startPos) startPos = tn.tokenPos; } else if (contextIsAmbient) { flags |= CommonFlags.AMBIENT; } diff --git a/tests/parser/also-identifier.ts b/tests/parser/also-identifier.ts index 39b5477bba..702cead65b 100644 --- a/tests/parser/also-identifier.ts +++ b/tests/parser/also-identifier.ts @@ -1,6 +1,6 @@ class Foo { as: i32; - declare: i32; + //declare: i32; delete: i32; from: i32; for: i32; @@ -19,7 +19,7 @@ class Foo { var as: i32; var constructor: i32; -var declare: i32; +//var declare: i32; var from: i32; var get: i32; var is: i32; diff --git a/tests/parser/also-identifier.ts.fixture.ts b/tests/parser/also-identifier.ts.fixture.ts index 8de8b51707..8d3188b81e 100644 --- a/tests/parser/also-identifier.ts.fixture.ts +++ b/tests/parser/also-identifier.ts.fixture.ts @@ -1,6 +1,5 @@ class Foo { as: i32; - declare: i32; delete: i32; from: i32; for: i32; @@ -18,7 +17,6 @@ class Foo { } var as: i32; var constructor: i32; -var declare: i32; var from: i32; var get: i32; var is: i32;