Skip to content

Commit bda6cb9

Browse files
committed
Initial function expression parsing
1 parent 9ef8b16 commit bda6cb9

8 files changed

+305
-50
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/ast.ts

+33-6
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ export enum NodeKind {
3434
COMMA,
3535
ELEMENTACCESS,
3636
FALSE,
37+
FUNCTION,
38+
FUNCTIONARROW,
3739
LITERAL,
3840
NEW,
3941
NULL,
@@ -225,6 +227,18 @@ export abstract class Node {
225227
return expr;
226228
}
227229

230+
static createFunctionExpression(
231+
declaration: FunctionDeclaration,
232+
isArrow: bool = false
233+
): FunctionExpression {
234+
var expr = isArrow
235+
? new FunctionArrowExpression()
236+
: new FunctionExpression();
237+
expr.range = declaration.range;
238+
expr.declaration = declaration;
239+
return expr;
240+
}
241+
228242
static createIntegerLiteralExpression(
229243
value: I64,
230244
range: Range
@@ -710,7 +724,7 @@ export abstract class Node {
710724
typeParameters: TypeParameter[],
711725
parameters: Parameter[],
712726
returnType: TypeNode | null,
713-
statements: Statement[] | null,
727+
body: Statement | null,
714728
modifiers: Modifier[] | null,
715729
decorators: Decorator[] | null,
716730
range: Range
@@ -721,7 +735,7 @@ export abstract class Node {
721735
stmt.typeParameters = typeParameters; setParent(typeParameters, stmt);
722736
stmt.parameters = parameters; setParent(parameters, stmt);
723737
stmt.returnType = returnType; if (returnType) returnType.parent = stmt;
724-
stmt.statements = statements; if (statements) setParent(statements, stmt);
738+
stmt.body = body; if (body) body.parent = stmt;
725739
stmt.modifiers = modifiers; if (modifiers) setParent(modifiers, stmt);
726740
stmt.decorators = decorators; if (decorators) setParent(decorators, stmt);
727741
return stmt;
@@ -732,7 +746,7 @@ export abstract class Node {
732746
typeParameters: TypeParameter[],
733747
parameters: Parameter[],
734748
returnType: TypeNode | null,
735-
statements: Statement[] | null,
749+
body: Statement | null,
736750
modifiers: Modifier[] | null,
737751
decorators: Decorator[] | null,
738752
range: Range
@@ -743,7 +757,7 @@ export abstract class Node {
743757
stmt.typeParameters = typeParameters; setParent(typeParameters, stmt);
744758
stmt.parameters = parameters; setParent(parameters, stmt);
745759
stmt.returnType = returnType; if (returnType) returnType.parent = stmt;
746-
stmt.statements = statements; if (statements) setParent(statements, stmt);
760+
stmt.body = body; if (body) body.parent = stmt;
747761
stmt.modifiers = modifiers; if (modifiers) setParent(modifiers, stmt);
748762
stmt.decorators = decorators; if (decorators) setParent(decorators, stmt);
749763
return stmt;
@@ -1033,6 +1047,19 @@ export class FloatLiteralExpression extends LiteralExpression {
10331047
value: f64;
10341048
}
10351049

1050+
/** Represents a function expression using the 'function' keyword. */
1051+
export class FunctionExpression extends Expression {
1052+
kind = NodeKind.FUNCTION;
1053+
1054+
/** Inline function declaration. */
1055+
declaration: FunctionDeclaration;
1056+
}
1057+
1058+
/** Represents an arrow function expression. */
1059+
export class FunctionArrowExpression extends FunctionExpression {
1060+
kind = NodeKind.FUNCTIONARROW;
1061+
}
1062+
10361063
/** Represents an integer literal expression. */
10371064
export class IntegerLiteralExpression extends LiteralExpression {
10381065
literalKind = LiteralKind.INTEGER;
@@ -1468,8 +1495,8 @@ export class FunctionDeclaration extends DeclarationStatement {
14681495
parameters: Parameter[];
14691496
/** Return type. */
14701497
returnType: TypeNode | null;
1471-
/** Contained statements. */
1472-
statements: Statement[] | null;
1498+
/** Body statement. Usually a block. */
1499+
body: Statement | null;
14731500
}
14741501

14751502
/** Represents an `if` statement. */

Diff for: src/compiler.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -729,14 +729,14 @@ export class Compiler extends DiagnosticEmitter {
729729

730730
var declaration = instance.prototype.declaration;
731731
if (instance.is(ElementFlags.DECLARED)) {
732-
if (declaration.statements) {
732+
if (declaration.body) {
733733
this.error(
734734
DiagnosticCode.An_implementation_cannot_be_declared_in_ambient_contexts,
735735
declaration.name.range
736736
);
737737
return false;
738738
}
739-
} else if (!declaration.statements) {
739+
} else if (!declaration.body) {
740740
this.error(
741741
DiagnosticCode.Function_implementation_is_missing_or_not_immediately_following_the_declaration,
742742
declaration.name.range
@@ -748,12 +748,12 @@ export class Compiler extends DiagnosticEmitter {
748748
instance.set(ElementFlags.COMPILED);
749749

750750
// compile statements
751-
var stmts: ExpressionRef[] | null = null;
751+
var stmt: ExpressionRef = 0;
752752
if (!instance.is(ElementFlags.DECLARED)) {
753753
var previousFunction = this.currentFunction;
754754
this.currentFunction = instance;
755-
var statements = assert(declaration.statements, "implementation expected");
756-
stmts = this.compileStatements(statements);
755+
var body = assert(declaration.body, "implementation expected");
756+
stmt = this.compileStatement(body);
757757
// make sure the top-level branch or all child branches return
758758
var allBranchesReturn = this.currentFunction.flow.finalize();
759759
if (instance.returnType != Type.void && !allBranchesReturn) {
@@ -810,7 +810,7 @@ export class Compiler extends DiagnosticEmitter {
810810
instance.internalName,
811811
typeRef,
812812
typesToNativeTypes(instance.additionalLocals),
813-
this.module.createBlock(null, <ExpressionRef[]>stmts, NativeType.None)
813+
assert(stmt)
814814
);
815815
}
816816

Diff for: src/extra/ast.ts

+59-15
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
CallExpression,
2626
CommaExpression,
2727
ElementAccessExpression,
28+
FunctionExpression,
2829
NewExpression,
2930
ParenthesizedExpression,
3031
PropertyAccessExpression,
@@ -124,6 +125,11 @@ export function serializeNode(node: Node, sb: string[]): void {
124125
serializeElementAccessExpression(<ElementAccessExpression>node, sb);
125126
break;
126127

128+
case NodeKind.FUNCTION:
129+
case NodeKind.FUNCTIONARROW:
130+
serializeFunctionExpression(<FunctionExpression>node, sb);
131+
break;
132+
127133
case NodeKind.LITERAL:
128134
serializeLiteralExpression(<LiteralExpression>node, sb);
129135
break;
@@ -412,6 +418,21 @@ export function serializeElementAccessExpression(node: ElementAccessExpression,
412418
sb.push("]");
413419
}
414420

421+
export function serializeFunctionExpression(node: FunctionExpression, sb: string[]): void {
422+
var declaration = node.declaration;
423+
var isArrow = node.kind == NodeKind.FUNCTIONARROW;
424+
if (!isArrow) {
425+
if (declaration.name.text.length) {
426+
sb.push("function ");
427+
} else {
428+
sb.push("function");
429+
}
430+
} else {
431+
assert(declaration.name.text.length == 0);
432+
}
433+
serializeFunctionCommon(declaration, sb, isArrow);
434+
}
435+
415436
export function serializeLiteralExpression(node: LiteralExpression, sb: string[]): void {
416437
switch (node.literalKind) {
417438

@@ -608,15 +629,19 @@ export function serializeStatement(node: Statement, sb: string[]): void {
608629

609630
function serializeTerminatedStatement(statement: Statement, sb: string[]): void {
610631
serializeStatement(statement, sb);
611-
if (sb.length) { // i.e. leading EmptyStatement
632+
if (
633+
!sb.length || // leading EmptyStatement
634+
statement.kind == NodeKind.VARIABLE || // potentially assigns a FunctionExpression
635+
statement.kind == NodeKind.EXPRESSION // potentially assigns a FunctionExpression
636+
) {
637+
sb.push(";\n");
638+
} else {
612639
var last = sb[sb.length - 1];
613640
if (last.length && last.charCodeAt(last.length - 1) == CharCode.CLOSEBRACE) {
614641
sb.push("\n");
615642
} else {
616643
sb.push(";\n");
617644
}
618-
} else {
619-
sb.push(";\n");
620645
}
621646
}
622647

@@ -840,11 +865,15 @@ export function serializeFunctionDeclaration(node: FunctionDeclaration, sb: stri
840865
sb.push(" ");
841866
}
842867
}
843-
sb.push("function ");
868+
if (node.name.text.length) {
869+
sb.push("function ");
870+
} else {
871+
sb.push("function");
872+
}
844873
serializeFunctionCommon(node, sb);
845874
}
846875

847-
function serializeFunctionCommon(node: FunctionDeclaration, sb: string[]): void {
876+
function serializeFunctionCommon(node: FunctionDeclaration, sb: string[], isArrow: bool = false): void {
848877
var i: i32, k: i32;
849878
serializeIdentifierExpression(node.name, sb);
850879
if (k = node.typeParameters.length) {
@@ -864,18 +893,33 @@ function serializeFunctionCommon(node: FunctionDeclaration, sb: string[]): void
864893
serializeParameter(node.parameters[i], sb);
865894
}
866895
}
867-
if (node.returnType && !hasModifier(ModifierKind.SET, node.modifiers)) {
868-
sb.push("): ");
869-
serializeTypeNode(node.returnType, sb);
896+
if (isArrow) {
897+
if (node.body) {
898+
if (node.returnType) {
899+
sb.push("): ");
900+
serializeTypeNode(node.returnType, sb);
901+
}
902+
sb.push(" => ");
903+
serializeStatement(<Statement>node.body, sb);
904+
} else {
905+
if (node.returnType) {
906+
sb.push(" => ");
907+
serializeTypeNode(node.returnType, sb);
908+
} else {
909+
sb.push(" => void");
910+
}
911+
}
870912
} else {
871-
sb.push(")");
872-
}
873-
if (node.statements) {
874-
sb.push(" {\n");
875-
for (i = 0, k = node.statements.length; i < k; ++i) {
876-
serializeTerminatedStatement(node.statements[i], sb);
913+
if (node.returnType && !hasModifier(ModifierKind.SET, node.modifiers)) {
914+
sb.push("): ");
915+
serializeTypeNode(node.returnType, sb);
916+
} else {
917+
sb.push(")");
918+
}
919+
if (node.body) {
920+
sb.push(" ");
921+
serializeStatement(node.body, sb);
877922
}
878-
sb.push("}");
879923
}
880924
}
881925

0 commit comments

Comments
 (0)