Skip to content

Commit 27dbbd1

Browse files
committed
Support a bit more interface syntax when parsing, see #160
1 parent c4ebc8c commit 27dbbd1

8 files changed

+123
-61
lines changed

Diff for: dist/assemblyscript.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: dist/assemblyscript.js.map

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: src/diagnosticMessages.generated.ts

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

Diff for: src/diagnosticMessages.json

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

Diff for: src/parser.ts

+94-46
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ import {
8282

8383
mangleInternalPath,
8484
nodeIsCallable,
85-
nodeIsGenericCallable
85+
nodeIsGenericCallable,
86+
InterfaceDeclaration
8687
} from "./ast";
8788

8889
const builtinsFile = LIBRARY_PREFIX + "builtins.ts";
@@ -1556,21 +1557,50 @@ export class Parser extends DiagnosticEmitter {
15561557
// Identifier ...
15571558

15581559
var startPos = tn.pos;
1560+
var isInterface = parent.kind == NodeKind.INTERFACEDECLARATION;
15591561

15601562
var decorators = new Array<DecoratorNode>();
15611563
while (tn.skip(Token.AT)) {
15621564
let decorator = this.parseDecorator(tn);
15631565
if (!decorator) break;
1566+
if (isInterface) {
1567+
this.error(
1568+
DiagnosticCode.Decorators_are_not_valid_here,
1569+
decorator.range
1570+
);
1571+
}
15641572
decorators.push(<DecoratorNode>decorator);
15651573
}
15661574

1567-
var flags = parent.flags & CommonFlags.AMBIENT; // inherit
1575+
// inherit ambient status
1576+
var flags = parent.flags & CommonFlags.AMBIENT;
1577+
1578+
// implemented methods are virtual
1579+
if (isInterface) flags |= CommonFlags.VIRTUAL;
15681580

15691581
if (tn.skip(Token.PUBLIC)) {
1582+
if (isInterface) {
1583+
this.error(
1584+
DiagnosticCode._0_modifier_cannot_be_used_here,
1585+
tn.range(), "public"
1586+
);
1587+
}
15701588
flags |= CommonFlags.PUBLIC;
15711589
} else if (tn.skip(Token.PRIVATE)) {
1590+
if (isInterface) {
1591+
this.error(
1592+
DiagnosticCode._0_modifier_cannot_be_used_here,
1593+
tn.range(), "private"
1594+
);
1595+
}
15721596
flags |= CommonFlags.PRIVATE;
15731597
} else if (tn.skip(Token.PROTECTED)) {
1598+
if (isInterface) {
1599+
this.error(
1600+
DiagnosticCode._0_modifier_cannot_be_used_here,
1601+
tn.range(), "protected"
1602+
);
1603+
}
15741604
flags |= CommonFlags.PROTECTED;
15751605
}
15761606

@@ -1579,16 +1609,27 @@ export class Parser extends DiagnosticEmitter {
15791609
var abstractStart: i32 = 0;
15801610
var abstractEnd: i32 = 0;
15811611
if (tn.skip(Token.STATIC)) {
1612+
if (isInterface) {
1613+
this.error(
1614+
DiagnosticCode._0_modifier_cannot_be_used_here,
1615+
tn.range(), "static"
1616+
);
1617+
}
15821618
flags |= CommonFlags.STATIC;
15831619
staticStart = tn.tokenPos;
15841620
staticEnd = tn.pos;
15851621
} else {
1622+
flags |= CommonFlags.INSTANCE;
15861623
if (tn.skip(Token.ABSTRACT)) {
1587-
flags |= (CommonFlags.ABSTRACT | CommonFlags.INSTANCE);
1624+
if (isInterface) {
1625+
this.error(
1626+
DiagnosticCode._0_modifier_cannot_be_used_here,
1627+
tn.range(), "abstract"
1628+
);
1629+
}
1630+
flags |= CommonFlags.ABSTRACT;
15881631
abstractStart = tn.tokenPos;
15891632
abstractEnd = tn.pos;
1590-
} else {
1591-
flags |= CommonFlags.INSTANCE;
15921633
}
15931634
if (parent.flags & CommonFlags.GENERIC) {
15941635
flags |= CommonFlags.GENERIC_CONTEXT;
@@ -1612,56 +1653,58 @@ export class Parser extends DiagnosticEmitter {
16121653
var isSetter = false;
16131654
var setStart: i32 = 0;
16141655
var setEnd: i32 = 0;
1615-
if (tn.skip(Token.GET)) {
1616-
if (tn.peek(true, IdentifierHandling.PREFER) == Token.IDENTIFIER && !tn.nextTokenOnNewLine) {
1617-
flags |= CommonFlags.GET;
1618-
isGetter = true;
1619-
setStart = tn.tokenPos;
1620-
setEnd = tn.pos;
1621-
if (flags & CommonFlags.READONLY) {
1656+
if (!isInterface) {
1657+
if (tn.skip(Token.GET)) {
1658+
if (tn.peek(true, IdentifierHandling.PREFER) == Token.IDENTIFIER && !tn.nextTokenOnNewLine) {
1659+
flags |= CommonFlags.GET;
1660+
isGetter = true;
1661+
setStart = tn.tokenPos;
1662+
setEnd = tn.pos;
1663+
if (flags & CommonFlags.READONLY) {
1664+
this.error(
1665+
DiagnosticCode._0_modifier_cannot_be_used_here,
1666+
tn.range(readonlyStart, readonlyEnd), "readonly"
1667+
); // recoverable
1668+
}
1669+
} else {
1670+
tn.reset(state);
1671+
}
1672+
} else if (tn.skip(Token.SET)) {
1673+
if (tn.peek(true, IdentifierHandling.PREFER) == Token.IDENTIFIER && !tn.nextTokenOnNewLine) {
1674+
flags |= CommonFlags.SET | CommonFlags.SET;
1675+
isSetter = true;
1676+
setStart = tn.tokenPos;
1677+
setEnd = tn.pos;
1678+
if (flags & CommonFlags.READONLY) {
1679+
this.error(
1680+
DiagnosticCode._0_modifier_cannot_be_used_here,
1681+
tn.range(readonlyStart, readonlyEnd), "readonly"
1682+
); // recoverable
1683+
}
1684+
} else {
1685+
tn.reset(state);
1686+
}
1687+
} else if (tn.skip(Token.CONSTRUCTOR)) {
1688+
flags |= CommonFlags.CONSTRUCTOR;
1689+
isConstructor = true;
1690+
if (flags & CommonFlags.STATIC) {
16221691
this.error(
16231692
DiagnosticCode._0_modifier_cannot_be_used_here,
1624-
tn.range(readonlyStart, readonlyEnd), "readonly"
1693+
tn.range(staticStart, staticEnd), "static"
1694+
); // recoverable
1695+
}
1696+
if (flags & CommonFlags.ABSTRACT) {
1697+
this.error(
1698+
DiagnosticCode._0_modifier_cannot_be_used_here,
1699+
tn.range(abstractStart, abstractEnd), "abstract"
16251700
); // recoverable
16261701
}
1627-
} else {
1628-
tn.reset(state);
1629-
}
1630-
} else if (tn.skip(Token.SET)) {
1631-
if (tn.peek(true, IdentifierHandling.PREFER) == Token.IDENTIFIER && !tn.nextTokenOnNewLine) {
1632-
flags |= CommonFlags.SET | CommonFlags.SET;
1633-
isSetter = true;
1634-
setStart = tn.tokenPos;
1635-
setEnd = tn.pos;
16361702
if (flags & CommonFlags.READONLY) {
16371703
this.error(
16381704
DiagnosticCode._0_modifier_cannot_be_used_here,
16391705
tn.range(readonlyStart, readonlyEnd), "readonly"
16401706
); // recoverable
16411707
}
1642-
} else {
1643-
tn.reset(state);
1644-
}
1645-
} else if (tn.skip(Token.CONSTRUCTOR)) {
1646-
flags |= CommonFlags.CONSTRUCTOR;
1647-
isConstructor = true;
1648-
if (flags & CommonFlags.STATIC) {
1649-
this.error(
1650-
DiagnosticCode._0_modifier_cannot_be_used_here,
1651-
tn.range(staticStart, staticEnd), "static"
1652-
); // recoverable
1653-
}
1654-
if (flags & CommonFlags.ABSTRACT) {
1655-
this.error(
1656-
DiagnosticCode._0_modifier_cannot_be_used_here,
1657-
tn.range(abstractStart, abstractEnd), "abstract"
1658-
); // recoverable
1659-
}
1660-
if (flags & CommonFlags.READONLY) {
1661-
this.error(
1662-
DiagnosticCode._0_modifier_cannot_be_used_here,
1663-
tn.range(readonlyStart, readonlyEnd), "readonly"
1664-
); // recoverable
16651708
}
16661709
}
16671710

@@ -1787,10 +1830,15 @@ export class Parser extends DiagnosticEmitter {
17871830
DiagnosticCode.An_implementation_cannot_be_declared_in_ambient_contexts,
17881831
tn.range()
17891832
); // recoverable
1833+
} else if (flags & CommonFlags.ABSTRACT) {
1834+
this.error(
1835+
DiagnosticCode.Method_0_cannot_have_an_implementation_because_it_is_marked_abstract,
1836+
tn.range(), name.text
1837+
); // recoverable
17901838
}
17911839
body = this.parseBlockStatement(tn, false);
17921840
if (!body) return null;
1793-
} else if (!(flags & CommonFlags.AMBIENT)) {
1841+
} else if (!(flags & CommonFlags.AMBIENT) && !isInterface) {
17941842
this.error(
17951843
DiagnosticCode.Function_implementation_is_missing_or_not_immediately_following_the_declaration,
17961844
tn.range()

Diff for: src/program.ts

+14-13
Original file line numberDiff line numberDiff line change
@@ -775,6 +775,12 @@ export class Program extends DiagnosticEmitter {
775775

776776
// remember classes that implement interfaces
777777
} else if (numImplementsTypes) {
778+
for (let i = 0; i < numImplementsTypes; ++i) {
779+
this.warning( // TODO
780+
DiagnosticCode.Operation_not_supported,
781+
implementsTypes[i].range
782+
);
783+
}
778784
queuedImplements.push(prototype);
779785
}
780786
}
@@ -2094,40 +2100,35 @@ export class Program extends DiagnosticEmitter {
20942100
var element: Element | null;
20952101

20962102
if (context) {
2097-
let parent: Element | null;
20982103

20992104
switch (context.kind) {
2100-
case ElementKind.FUNCTION: { // search locals
2105+
case ElementKind.FUNCTION: { // search locals, use prototype
21012106
element = (<Function>context).flow.getScopedLocal(name);
21022107
if (element) {
21032108
this.resolvedThisExpression = null;
21042109
this.resolvedElementExpression = null;
21052110
return element;
21062111
}
2107-
parent = (<Function>context).prototype.parent;
2112+
context = (<Function>context).prototype.parent;
21082113
break;
21092114
}
2110-
case ElementKind.CLASS: {
2111-
parent = (<Class>context).prototype.parent;
2112-
break;
2113-
}
2114-
default: {
2115-
parent = context;
2115+
case ElementKind.CLASS: { // use prototype
2116+
context = (<Class>context).prototype.parent;
21162117
break;
21172118
}
21182119
}
21192120

2120-
// search parent
2121-
while (parent) {
2122-
let members = parent.members;
2121+
// search context
2122+
while (context) {
2123+
let members = context.members;
21232124
if (members) {
21242125
if (element = members.get(name)) {
21252126
this.resolvedThisExpression = null;
21262127
this.resolvedElementExpression = null;
21272128
return element;
21282129
}
21292130
}
2130-
parent = parent.parent;
2131+
context = context.parent;
21312132
}
21322133
}
21332134

Diff for: tests/parser/interface.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
interface Foo {
2+
bar(): void;
3+
baz: i32;
4+
readonly baz2: f64;
5+
}

Diff for: tests/parser/interface.ts.fixture.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
interface Foo {
2+
bar(): void;
3+
baz: i32;
4+
readonly baz2: f64;
5+
}

0 commit comments

Comments
 (0)