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,
Decorators_are_not_valid_here = 1206,
_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_parameter_property_cannot_be_declared_using_a_rest_parameter = 1317,
Duplicate_identifier_0 = 2300,
@ -188,6 +189,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
case 1199: return "Unterminated Unicode escape sequence.";
case 1206: return "Decorators are not valid here.";
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 1317: return "A parameter property cannot be declared using a rest parameter.";
case 2300: return "Duplicate identifier '{0}'.";

View File

@ -69,6 +69,7 @@
"Unterminated Unicode escape sequence.": 1199,
"Decorators are not valid here.": 1206,
"'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 parameter property cannot be declared using a rest parameter.": 1317,

View File

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

View File

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