Support a bit more interface syntax when parsing, see #160

This commit is contained in:
dcodeIO 2018-07-10 00:34:40 +02:00
parent c4ebc8c291
commit 27dbbd1d75
8 changed files with 127 additions and 65 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -76,6 +76,7 @@ export enum DiagnosticCode {
Unterminated_Unicode_escape_sequence = 1199, Unterminated_Unicode_escape_sequence = 1199,
Decorators_are_not_valid_here = 1206, Decorators_are_not_valid_here = 1206,
_abstract_modifier_can_only_appear_on_a_class_method_or_property_declaration = 1242, _abstract_modifier_can_only_appear_on_a_class_method_or_property_declaration = 1242,
Method_0_cannot_have_an_implementation_because_it_is_marked_abstract = 1245,
A_class_may_only_extend_another_class = 1311, A_class_may_only_extend_another_class = 1311,
A_parameter_property_cannot_be_declared_using_a_rest_parameter = 1317, A_parameter_property_cannot_be_declared_using_a_rest_parameter = 1317,
Duplicate_identifier_0 = 2300, Duplicate_identifier_0 = 2300,
@ -188,6 +189,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
case 1199: return "Unterminated Unicode escape sequence."; case 1199: return "Unterminated Unicode escape sequence.";
case 1206: return "Decorators are not valid here."; case 1206: return "Decorators are not valid here.";
case 1242: return "'abstract' modifier can only appear on a class, method, or property declaration."; case 1242: return "'abstract' modifier can only appear on a class, method, or property declaration.";
case 1245: return "Method '{0}' cannot have an implementation because it is marked abstract.";
case 1311: return "A class may only extend another class."; case 1311: return "A class may only extend another class.";
case 1317: return "A parameter property cannot be declared using a rest parameter."; case 1317: return "A parameter property cannot be declared using a rest parameter.";
case 2300: return "Duplicate identifier '{0}'."; case 2300: return "Duplicate identifier '{0}'.";

View File

@ -69,6 +69,7 @@
"Unterminated Unicode escape sequence.": 1199, "Unterminated Unicode escape sequence.": 1199,
"Decorators are not valid here.": 1206, "Decorators are not valid here.": 1206,
"'abstract' modifier can only appear on a class, method, or property declaration.": 1242, "'abstract' modifier can only appear on a class, method, or property declaration.": 1242,
"Method '{0}' cannot have an implementation because it is marked abstract.": 1245,
"A class may only extend another class.": 1311, "A class may only extend another class.": 1311,
"A parameter property cannot be declared using a rest parameter.": 1317, "A parameter property cannot be declared using a rest parameter.": 1317,

View File

@ -82,7 +82,8 @@ import {
mangleInternalPath, mangleInternalPath,
nodeIsCallable, nodeIsCallable,
nodeIsGenericCallable nodeIsGenericCallable,
InterfaceDeclaration
} from "./ast"; } from "./ast";
const builtinsFile = LIBRARY_PREFIX + "builtins.ts"; const builtinsFile = LIBRARY_PREFIX + "builtins.ts";
@ -1556,21 +1557,50 @@ export class Parser extends DiagnosticEmitter {
// Identifier ... // Identifier ...
var startPos = tn.pos; var startPos = tn.pos;
var isInterface = parent.kind == NodeKind.INTERFACEDECLARATION;
var decorators = new Array<DecoratorNode>(); var decorators = new Array<DecoratorNode>();
while (tn.skip(Token.AT)) { while (tn.skip(Token.AT)) {
let decorator = this.parseDecorator(tn); let decorator = this.parseDecorator(tn);
if (!decorator) break; if (!decorator) break;
if (isInterface) {
this.error(
DiagnosticCode.Decorators_are_not_valid_here,
decorator.range
);
}
decorators.push(<DecoratorNode>decorator); decorators.push(<DecoratorNode>decorator);
} }
var flags = parent.flags & CommonFlags.AMBIENT; // inherit // inherit ambient status
var flags = parent.flags & CommonFlags.AMBIENT;
// implemented methods are virtual
if (isInterface) flags |= CommonFlags.VIRTUAL;
if (tn.skip(Token.PUBLIC)) { if (tn.skip(Token.PUBLIC)) {
if (isInterface) {
this.error(
DiagnosticCode._0_modifier_cannot_be_used_here,
tn.range(), "public"
);
}
flags |= CommonFlags.PUBLIC; flags |= CommonFlags.PUBLIC;
} else if (tn.skip(Token.PRIVATE)) { } else if (tn.skip(Token.PRIVATE)) {
if (isInterface) {
this.error(
DiagnosticCode._0_modifier_cannot_be_used_here,
tn.range(), "private"
);
}
flags |= CommonFlags.PRIVATE; flags |= CommonFlags.PRIVATE;
} else if (tn.skip(Token.PROTECTED)) { } else if (tn.skip(Token.PROTECTED)) {
if (isInterface) {
this.error(
DiagnosticCode._0_modifier_cannot_be_used_here,
tn.range(), "protected"
);
}
flags |= CommonFlags.PROTECTED; flags |= CommonFlags.PROTECTED;
} }
@ -1579,16 +1609,27 @@ export class Parser extends DiagnosticEmitter {
var abstractStart: i32 = 0; var abstractStart: i32 = 0;
var abstractEnd: i32 = 0; var abstractEnd: i32 = 0;
if (tn.skip(Token.STATIC)) { if (tn.skip(Token.STATIC)) {
if (isInterface) {
this.error(
DiagnosticCode._0_modifier_cannot_be_used_here,
tn.range(), "static"
);
}
flags |= CommonFlags.STATIC; flags |= CommonFlags.STATIC;
staticStart = tn.tokenPos; staticStart = tn.tokenPos;
staticEnd = tn.pos; staticEnd = tn.pos;
} else { } else {
flags |= CommonFlags.INSTANCE;
if (tn.skip(Token.ABSTRACT)) { if (tn.skip(Token.ABSTRACT)) {
flags |= (CommonFlags.ABSTRACT | CommonFlags.INSTANCE); if (isInterface) {
this.error(
DiagnosticCode._0_modifier_cannot_be_used_here,
tn.range(), "abstract"
);
}
flags |= CommonFlags.ABSTRACT;
abstractStart = tn.tokenPos; abstractStart = tn.tokenPos;
abstractEnd = tn.pos; abstractEnd = tn.pos;
} else {
flags |= CommonFlags.INSTANCE;
} }
if (parent.flags & CommonFlags.GENERIC) { if (parent.flags & CommonFlags.GENERIC) {
flags |= CommonFlags.GENERIC_CONTEXT; flags |= CommonFlags.GENERIC_CONTEXT;
@ -1612,6 +1653,7 @@ export class Parser extends DiagnosticEmitter {
var isSetter = false; var isSetter = false;
var setStart: i32 = 0; var setStart: i32 = 0;
var setEnd: i32 = 0; var setEnd: i32 = 0;
if (!isInterface) {
if (tn.skip(Token.GET)) { if (tn.skip(Token.GET)) {
if (tn.peek(true, IdentifierHandling.PREFER) == Token.IDENTIFIER && !tn.nextTokenOnNewLine) { if (tn.peek(true, IdentifierHandling.PREFER) == Token.IDENTIFIER && !tn.nextTokenOnNewLine) {
flags |= CommonFlags.GET; flags |= CommonFlags.GET;
@ -1664,6 +1706,7 @@ export class Parser extends DiagnosticEmitter {
); // recoverable ); // recoverable
} }
} }
}
if (!isConstructor && !tn.skipIdentifier()) { if (!isConstructor && !tn.skipIdentifier()) {
this.error( this.error(
@ -1787,10 +1830,15 @@ export class Parser extends DiagnosticEmitter {
DiagnosticCode.An_implementation_cannot_be_declared_in_ambient_contexts, DiagnosticCode.An_implementation_cannot_be_declared_in_ambient_contexts,
tn.range() tn.range()
); // recoverable ); // recoverable
} else if (flags & CommonFlags.ABSTRACT) {
this.error(
DiagnosticCode.Method_0_cannot_have_an_implementation_because_it_is_marked_abstract,
tn.range(), name.text
); // recoverable
} }
body = this.parseBlockStatement(tn, false); body = this.parseBlockStatement(tn, false);
if (!body) return null; if (!body) return null;
} else if (!(flags & CommonFlags.AMBIENT)) { } else if (!(flags & CommonFlags.AMBIENT) && !isInterface) {
this.error( this.error(
DiagnosticCode.Function_implementation_is_missing_or_not_immediately_following_the_declaration, DiagnosticCode.Function_implementation_is_missing_or_not_immediately_following_the_declaration,
tn.range() tn.range()

View File

@ -775,6 +775,12 @@ export class Program extends DiagnosticEmitter {
// remember classes that implement interfaces // remember classes that implement interfaces
} else if (numImplementsTypes) { } else if (numImplementsTypes) {
for (let i = 0; i < numImplementsTypes; ++i) {
this.warning( // TODO
DiagnosticCode.Operation_not_supported,
implementsTypes[i].range
);
}
queuedImplements.push(prototype); queuedImplements.push(prototype);
} }
} }
@ -2094,32 +2100,27 @@ export class Program extends DiagnosticEmitter {
var element: Element | null; var element: Element | null;
if (context) { if (context) {
let parent: Element | null;
switch (context.kind) { switch (context.kind) {
case ElementKind.FUNCTION: { // search locals case ElementKind.FUNCTION: { // search locals, use prototype
element = (<Function>context).flow.getScopedLocal(name); element = (<Function>context).flow.getScopedLocal(name);
if (element) { if (element) {
this.resolvedThisExpression = null; this.resolvedThisExpression = null;
this.resolvedElementExpression = null; this.resolvedElementExpression = null;
return element; return element;
} }
parent = (<Function>context).prototype.parent; context = (<Function>context).prototype.parent;
break; break;
} }
case ElementKind.CLASS: { case ElementKind.CLASS: { // use prototype
parent = (<Class>context).prototype.parent; context = (<Class>context).prototype.parent;
break;
}
default: {
parent = context;
break; break;
} }
} }
// search parent // search context
while (parent) { while (context) {
let members = parent.members; let members = context.members;
if (members) { if (members) {
if (element = members.get(name)) { if (element = members.get(name)) {
this.resolvedThisExpression = null; this.resolvedThisExpression = null;
@ -2127,7 +2128,7 @@ export class Program extends DiagnosticEmitter {
return element; return element;
} }
} }
parent = parent.parent; context = context.parent;
} }
} }

View File

@ -0,0 +1,5 @@
interface Foo {
bar(): void;
baz: i32;
readonly baz2: f64;
}

View File

@ -0,0 +1,5 @@
interface Foo {
bar(): void;
baz: i32;
readonly baz2: f64;
}