Skip to content

Add declare to parser #2160

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 2, 2021
Merged
Show file tree
Hide file tree
Changes from 2 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
3 changes: 3 additions & 0 deletions src/extra/ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down
52 changes: 52 additions & 0 deletions src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1839,6 +1839,7 @@ export class Parser extends DiagnosticEmitter {
): Node | null {

// before:
// 'declare'?
// ('public' | 'private' | 'protected')?
// ('static' | 'abstract')?
// 'readonly'?
Expand Down Expand Up @@ -1870,6 +1871,44 @@ 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.peek() == Token.DECLARE) {
let state = tn.mark();
tn.next();
if (tn.peek() != Token.COLON) { // modifier
tn.discard(state);
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 { // identifier
tn.reset(state);
}
} else if (contextIsAmbient) {
flags |= CommonFlags.AMBIENT;
}

var accessStart = 0;
var accessEnd = 0;
if (tn.skip(Token.PUBLIC)) {
Expand Down Expand Up @@ -2108,6 +2147,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;
Expand Down Expand Up @@ -2291,6 +2337,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;
}
Expand Down
12 changes: 12 additions & 0 deletions tests/parser/class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,16 @@ export class Invalid<T> {
// 1049: A 'set' accessor must have exactly one parameter.
// 1095: A 'set' accessor cannot have a return type annotation.
set instanceSetter<T>(): 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 {}
}
9 changes: 9 additions & 0 deletions tests/parser/class.ts.fixture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ export class Invalid<T> {
instanceFunction() {}
get instanceGetter<T>(a: i32) {}
set instanceSetter<T>() {}
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)
Expand All @@ -23,3 +26,9 @@ export class Invalid<T> {
// 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)