mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-25 15:12:12 +00:00
Support a bit more interface syntax when parsing, see #160
This commit is contained in:
parent
c4ebc8c291
commit
27dbbd1d75
2
dist/assemblyscript.js
vendored
2
dist/assemblyscript.js
vendored
File diff suppressed because one or more lines are too long
2
dist/assemblyscript.js.map
vendored
2
dist/assemblyscript.js.map
vendored
File diff suppressed because one or more lines are too long
@ -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}'.";
|
||||
|
@ -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,
|
||||
|
||||
|
148
src/parser.ts
148
src/parser.ts
@ -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()
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
5
tests/parser/interface.ts
Normal file
5
tests/parser/interface.ts
Normal file
@ -0,0 +1,5 @@
|
||||
interface Foo {
|
||||
bar(): void;
|
||||
baz: i32;
|
||||
readonly baz2: f64;
|
||||
}
|
5
tests/parser/interface.ts.fixture.ts
Normal file
5
tests/parser/interface.ts.fixture.ts
Normal file
@ -0,0 +1,5 @@
|
||||
interface Foo {
|
||||
bar(): void;
|
||||
baz: i32;
|
||||
readonly baz2: f64;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user