mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-26 07:22:21 +00:00
Initial function expression parsing
This commit is contained in:
parent
9ef8b162a9
commit
bda6cb9792
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
39
src/ast.ts
39
src/ast.ts
@ -34,6 +34,8 @@ export enum NodeKind {
|
|||||||
COMMA,
|
COMMA,
|
||||||
ELEMENTACCESS,
|
ELEMENTACCESS,
|
||||||
FALSE,
|
FALSE,
|
||||||
|
FUNCTION,
|
||||||
|
FUNCTIONARROW,
|
||||||
LITERAL,
|
LITERAL,
|
||||||
NEW,
|
NEW,
|
||||||
NULL,
|
NULL,
|
||||||
@ -225,6 +227,18 @@ export abstract class Node {
|
|||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static createFunctionExpression(
|
||||||
|
declaration: FunctionDeclaration,
|
||||||
|
isArrow: bool = false
|
||||||
|
): FunctionExpression {
|
||||||
|
var expr = isArrow
|
||||||
|
? new FunctionArrowExpression()
|
||||||
|
: new FunctionExpression();
|
||||||
|
expr.range = declaration.range;
|
||||||
|
expr.declaration = declaration;
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
static createIntegerLiteralExpression(
|
static createIntegerLiteralExpression(
|
||||||
value: I64,
|
value: I64,
|
||||||
range: Range
|
range: Range
|
||||||
@ -710,7 +724,7 @@ export abstract class Node {
|
|||||||
typeParameters: TypeParameter[],
|
typeParameters: TypeParameter[],
|
||||||
parameters: Parameter[],
|
parameters: Parameter[],
|
||||||
returnType: TypeNode | null,
|
returnType: TypeNode | null,
|
||||||
statements: Statement[] | null,
|
body: Statement | null,
|
||||||
modifiers: Modifier[] | null,
|
modifiers: Modifier[] | null,
|
||||||
decorators: Decorator[] | null,
|
decorators: Decorator[] | null,
|
||||||
range: Range
|
range: Range
|
||||||
@ -721,7 +735,7 @@ export abstract class Node {
|
|||||||
stmt.typeParameters = typeParameters; setParent(typeParameters, stmt);
|
stmt.typeParameters = typeParameters; setParent(typeParameters, stmt);
|
||||||
stmt.parameters = parameters; setParent(parameters, stmt);
|
stmt.parameters = parameters; setParent(parameters, stmt);
|
||||||
stmt.returnType = returnType; if (returnType) returnType.parent = stmt;
|
stmt.returnType = returnType; if (returnType) returnType.parent = stmt;
|
||||||
stmt.statements = statements; if (statements) setParent(statements, stmt);
|
stmt.body = body; if (body) body.parent = stmt;
|
||||||
stmt.modifiers = modifiers; if (modifiers) setParent(modifiers, stmt);
|
stmt.modifiers = modifiers; if (modifiers) setParent(modifiers, stmt);
|
||||||
stmt.decorators = decorators; if (decorators) setParent(decorators, stmt);
|
stmt.decorators = decorators; if (decorators) setParent(decorators, stmt);
|
||||||
return stmt;
|
return stmt;
|
||||||
@ -732,7 +746,7 @@ export abstract class Node {
|
|||||||
typeParameters: TypeParameter[],
|
typeParameters: TypeParameter[],
|
||||||
parameters: Parameter[],
|
parameters: Parameter[],
|
||||||
returnType: TypeNode | null,
|
returnType: TypeNode | null,
|
||||||
statements: Statement[] | null,
|
body: Statement | null,
|
||||||
modifiers: Modifier[] | null,
|
modifiers: Modifier[] | null,
|
||||||
decorators: Decorator[] | null,
|
decorators: Decorator[] | null,
|
||||||
range: Range
|
range: Range
|
||||||
@ -743,7 +757,7 @@ export abstract class Node {
|
|||||||
stmt.typeParameters = typeParameters; setParent(typeParameters, stmt);
|
stmt.typeParameters = typeParameters; setParent(typeParameters, stmt);
|
||||||
stmt.parameters = parameters; setParent(parameters, stmt);
|
stmt.parameters = parameters; setParent(parameters, stmt);
|
||||||
stmt.returnType = returnType; if (returnType) returnType.parent = stmt;
|
stmt.returnType = returnType; if (returnType) returnType.parent = stmt;
|
||||||
stmt.statements = statements; if (statements) setParent(statements, stmt);
|
stmt.body = body; if (body) body.parent = stmt;
|
||||||
stmt.modifiers = modifiers; if (modifiers) setParent(modifiers, stmt);
|
stmt.modifiers = modifiers; if (modifiers) setParent(modifiers, stmt);
|
||||||
stmt.decorators = decorators; if (decorators) setParent(decorators, stmt);
|
stmt.decorators = decorators; if (decorators) setParent(decorators, stmt);
|
||||||
return stmt;
|
return stmt;
|
||||||
@ -1033,6 +1047,19 @@ export class FloatLiteralExpression extends LiteralExpression {
|
|||||||
value: f64;
|
value: f64;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Represents a function expression using the 'function' keyword. */
|
||||||
|
export class FunctionExpression extends Expression {
|
||||||
|
kind = NodeKind.FUNCTION;
|
||||||
|
|
||||||
|
/** Inline function declaration. */
|
||||||
|
declaration: FunctionDeclaration;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Represents an arrow function expression. */
|
||||||
|
export class FunctionArrowExpression extends FunctionExpression {
|
||||||
|
kind = NodeKind.FUNCTIONARROW;
|
||||||
|
}
|
||||||
|
|
||||||
/** Represents an integer literal expression. */
|
/** Represents an integer literal expression. */
|
||||||
export class IntegerLiteralExpression extends LiteralExpression {
|
export class IntegerLiteralExpression extends LiteralExpression {
|
||||||
literalKind = LiteralKind.INTEGER;
|
literalKind = LiteralKind.INTEGER;
|
||||||
@ -1468,8 +1495,8 @@ export class FunctionDeclaration extends DeclarationStatement {
|
|||||||
parameters: Parameter[];
|
parameters: Parameter[];
|
||||||
/** Return type. */
|
/** Return type. */
|
||||||
returnType: TypeNode | null;
|
returnType: TypeNode | null;
|
||||||
/** Contained statements. */
|
/** Body statement. Usually a block. */
|
||||||
statements: Statement[] | null;
|
body: Statement | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Represents an `if` statement. */
|
/** Represents an `if` statement. */
|
||||||
|
@ -729,14 +729,14 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
|
|
||||||
var declaration = instance.prototype.declaration;
|
var declaration = instance.prototype.declaration;
|
||||||
if (instance.is(ElementFlags.DECLARED)) {
|
if (instance.is(ElementFlags.DECLARED)) {
|
||||||
if (declaration.statements) {
|
if (declaration.body) {
|
||||||
this.error(
|
this.error(
|
||||||
DiagnosticCode.An_implementation_cannot_be_declared_in_ambient_contexts,
|
DiagnosticCode.An_implementation_cannot_be_declared_in_ambient_contexts,
|
||||||
declaration.name.range
|
declaration.name.range
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (!declaration.statements) {
|
} else if (!declaration.body) {
|
||||||
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,
|
||||||
declaration.name.range
|
declaration.name.range
|
||||||
@ -748,12 +748,12 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
instance.set(ElementFlags.COMPILED);
|
instance.set(ElementFlags.COMPILED);
|
||||||
|
|
||||||
// compile statements
|
// compile statements
|
||||||
var stmts: ExpressionRef[] | null = null;
|
var stmt: ExpressionRef = 0;
|
||||||
if (!instance.is(ElementFlags.DECLARED)) {
|
if (!instance.is(ElementFlags.DECLARED)) {
|
||||||
var previousFunction = this.currentFunction;
|
var previousFunction = this.currentFunction;
|
||||||
this.currentFunction = instance;
|
this.currentFunction = instance;
|
||||||
var statements = assert(declaration.statements, "implementation expected");
|
var body = assert(declaration.body, "implementation expected");
|
||||||
stmts = this.compileStatements(statements);
|
stmt = this.compileStatement(body);
|
||||||
// make sure the top-level branch or all child branches return
|
// make sure the top-level branch or all child branches return
|
||||||
var allBranchesReturn = this.currentFunction.flow.finalize();
|
var allBranchesReturn = this.currentFunction.flow.finalize();
|
||||||
if (instance.returnType != Type.void && !allBranchesReturn) {
|
if (instance.returnType != Type.void && !allBranchesReturn) {
|
||||||
@ -810,7 +810,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
instance.internalName,
|
instance.internalName,
|
||||||
typeRef,
|
typeRef,
|
||||||
typesToNativeTypes(instance.additionalLocals),
|
typesToNativeTypes(instance.additionalLocals),
|
||||||
this.module.createBlock(null, <ExpressionRef[]>stmts, NativeType.None)
|
assert(stmt)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ import {
|
|||||||
CallExpression,
|
CallExpression,
|
||||||
CommaExpression,
|
CommaExpression,
|
||||||
ElementAccessExpression,
|
ElementAccessExpression,
|
||||||
|
FunctionExpression,
|
||||||
NewExpression,
|
NewExpression,
|
||||||
ParenthesizedExpression,
|
ParenthesizedExpression,
|
||||||
PropertyAccessExpression,
|
PropertyAccessExpression,
|
||||||
@ -124,6 +125,11 @@ export function serializeNode(node: Node, sb: string[]): void {
|
|||||||
serializeElementAccessExpression(<ElementAccessExpression>node, sb);
|
serializeElementAccessExpression(<ElementAccessExpression>node, sb);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NodeKind.FUNCTION:
|
||||||
|
case NodeKind.FUNCTIONARROW:
|
||||||
|
serializeFunctionExpression(<FunctionExpression>node, sb);
|
||||||
|
break;
|
||||||
|
|
||||||
case NodeKind.LITERAL:
|
case NodeKind.LITERAL:
|
||||||
serializeLiteralExpression(<LiteralExpression>node, sb);
|
serializeLiteralExpression(<LiteralExpression>node, sb);
|
||||||
break;
|
break;
|
||||||
@ -412,6 +418,21 @@ export function serializeElementAccessExpression(node: ElementAccessExpression,
|
|||||||
sb.push("]");
|
sb.push("]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function serializeFunctionExpression(node: FunctionExpression, sb: string[]): void {
|
||||||
|
var declaration = node.declaration;
|
||||||
|
var isArrow = node.kind == NodeKind.FUNCTIONARROW;
|
||||||
|
if (!isArrow) {
|
||||||
|
if (declaration.name.text.length) {
|
||||||
|
sb.push("function ");
|
||||||
|
} else {
|
||||||
|
sb.push("function");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert(declaration.name.text.length == 0);
|
||||||
|
}
|
||||||
|
serializeFunctionCommon(declaration, sb, isArrow);
|
||||||
|
}
|
||||||
|
|
||||||
export function serializeLiteralExpression(node: LiteralExpression, sb: string[]): void {
|
export function serializeLiteralExpression(node: LiteralExpression, sb: string[]): void {
|
||||||
switch (node.literalKind) {
|
switch (node.literalKind) {
|
||||||
|
|
||||||
@ -608,15 +629,19 @@ export function serializeStatement(node: Statement, sb: string[]): void {
|
|||||||
|
|
||||||
function serializeTerminatedStatement(statement: Statement, sb: string[]): void {
|
function serializeTerminatedStatement(statement: Statement, sb: string[]): void {
|
||||||
serializeStatement(statement, sb);
|
serializeStatement(statement, sb);
|
||||||
if (sb.length) { // i.e. leading EmptyStatement
|
if (
|
||||||
|
!sb.length || // leading EmptyStatement
|
||||||
|
statement.kind == NodeKind.VARIABLE || // potentially assigns a FunctionExpression
|
||||||
|
statement.kind == NodeKind.EXPRESSION // potentially assigns a FunctionExpression
|
||||||
|
) {
|
||||||
|
sb.push(";\n");
|
||||||
|
} else {
|
||||||
var last = sb[sb.length - 1];
|
var last = sb[sb.length - 1];
|
||||||
if (last.length && last.charCodeAt(last.length - 1) == CharCode.CLOSEBRACE) {
|
if (last.length && last.charCodeAt(last.length - 1) == CharCode.CLOSEBRACE) {
|
||||||
sb.push("\n");
|
sb.push("\n");
|
||||||
} else {
|
} else {
|
||||||
sb.push(";\n");
|
sb.push(";\n");
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
sb.push(";\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -840,11 +865,15 @@ export function serializeFunctionDeclaration(node: FunctionDeclaration, sb: stri
|
|||||||
sb.push(" ");
|
sb.push(" ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (node.name.text.length) {
|
||||||
sb.push("function ");
|
sb.push("function ");
|
||||||
|
} else {
|
||||||
|
sb.push("function");
|
||||||
|
}
|
||||||
serializeFunctionCommon(node, sb);
|
serializeFunctionCommon(node, sb);
|
||||||
}
|
}
|
||||||
|
|
||||||
function serializeFunctionCommon(node: FunctionDeclaration, sb: string[]): void {
|
function serializeFunctionCommon(node: FunctionDeclaration, sb: string[], isArrow: bool = false): void {
|
||||||
var i: i32, k: i32;
|
var i: i32, k: i32;
|
||||||
serializeIdentifierExpression(node.name, sb);
|
serializeIdentifierExpression(node.name, sb);
|
||||||
if (k = node.typeParameters.length) {
|
if (k = node.typeParameters.length) {
|
||||||
@ -864,18 +893,33 @@ function serializeFunctionCommon(node: FunctionDeclaration, sb: string[]): void
|
|||||||
serializeParameter(node.parameters[i], sb);
|
serializeParameter(node.parameters[i], sb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (isArrow) {
|
||||||
|
if (node.body) {
|
||||||
|
if (node.returnType) {
|
||||||
|
sb.push("): ");
|
||||||
|
serializeTypeNode(node.returnType, sb);
|
||||||
|
}
|
||||||
|
sb.push(" => ");
|
||||||
|
serializeStatement(<Statement>node.body, sb);
|
||||||
|
} else {
|
||||||
|
if (node.returnType) {
|
||||||
|
sb.push(" => ");
|
||||||
|
serializeTypeNode(node.returnType, sb);
|
||||||
|
} else {
|
||||||
|
sb.push(" => void");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (node.returnType && !hasModifier(ModifierKind.SET, node.modifiers)) {
|
if (node.returnType && !hasModifier(ModifierKind.SET, node.modifiers)) {
|
||||||
sb.push("): ");
|
sb.push("): ");
|
||||||
serializeTypeNode(node.returnType, sb);
|
serializeTypeNode(node.returnType, sb);
|
||||||
} else {
|
} else {
|
||||||
sb.push(")");
|
sb.push(")");
|
||||||
}
|
}
|
||||||
if (node.statements) {
|
if (node.body) {
|
||||||
sb.push(" {\n");
|
sb.push(" ");
|
||||||
for (i = 0, k = node.statements.length; i < k; ++i) {
|
serializeStatement(node.body, sb);
|
||||||
serializeTerminatedStatement(node.statements[i], sb);
|
|
||||||
}
|
}
|
||||||
sb.push("}");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
192
src/parser.ts
192
src/parser.ts
@ -79,7 +79,8 @@ import {
|
|||||||
addModifier,
|
addModifier,
|
||||||
getModifier,
|
getModifier,
|
||||||
hasModifier,
|
hasModifier,
|
||||||
setReusableModifiers
|
setReusableModifiers,
|
||||||
|
FunctionExpression
|
||||||
|
|
||||||
} from "./ast";
|
} from "./ast";
|
||||||
|
|
||||||
@ -776,7 +777,8 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
parseParameter(
|
parseParameter(
|
||||||
tn: Tokenizer
|
tn: Tokenizer,
|
||||||
|
suppressErrors: bool = false
|
||||||
): Parameter | null {
|
): Parameter | null {
|
||||||
|
|
||||||
// before: '...'? Identifier '?'? (':' Type)? ('=' Expression)?
|
// before: '...'? Identifier '?'? (':' Type)? ('=' Expression)?
|
||||||
@ -927,10 +929,8 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
|
|
||||||
var isDeclare = hasModifier(ModifierKind.DECLARE, modifiers);
|
var isDeclare = hasModifier(ModifierKind.DECLARE, modifiers);
|
||||||
|
|
||||||
var statements: Statement[] | null = null;
|
var body: Statement | null = null;
|
||||||
if (tn.skip(Token.OPENBRACE)) {
|
if (tn.skip(Token.OPENBRACE)) {
|
||||||
statements = new Array();
|
|
||||||
|
|
||||||
if (isDeclare) {
|
if (isDeclare) {
|
||||||
this.error(
|
this.error(
|
||||||
DiagnosticCode.An_implementation_cannot_be_declared_in_ambient_contexts,
|
DiagnosticCode.An_implementation_cannot_be_declared_in_ambient_contexts,
|
||||||
@ -938,12 +938,8 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
); // recoverable
|
); // recoverable
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!tn.skip(Token.CLOSEBRACE)) {
|
body = this.parseBlockStatement(tn, false);
|
||||||
var statement = this.parseStatement(tn);
|
if (!body) return null;
|
||||||
if (!statement) return null;
|
|
||||||
statements.push(<Statement>statement);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (!isDeclare) {
|
} else if (!isDeclare) {
|
||||||
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,
|
||||||
@ -956,7 +952,7 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
typeParameters,
|
typeParameters,
|
||||||
<Parameter[]>parameters,
|
<Parameter[]>parameters,
|
||||||
returnType,
|
returnType,
|
||||||
statements,
|
body,
|
||||||
modifiers,
|
modifiers,
|
||||||
decorators,
|
decorators,
|
||||||
tn.range(startPos, tn.pos)
|
tn.range(startPos, tn.pos)
|
||||||
@ -965,6 +961,102 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parseFunctionExpression(tn: Tokenizer): FunctionExpression | null {
|
||||||
|
var startPos = tn.tokenPos;
|
||||||
|
var identifier: IdentifierExpression;
|
||||||
|
var isArrow = false;
|
||||||
|
|
||||||
|
// either at 'function':
|
||||||
|
// Identifier?
|
||||||
|
// '(' Parameters (':' Type)?
|
||||||
|
// Statement
|
||||||
|
|
||||||
|
if (tn.token == Token.FUNCTION) {
|
||||||
|
isArrow = false;
|
||||||
|
if (tn.skip(Token.IDENTIFIER)) {
|
||||||
|
identifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range());
|
||||||
|
} else { // empty name
|
||||||
|
identifier = Node.createIdentifierExpression("", tn.range(tn.pos, tn.pos));
|
||||||
|
}
|
||||||
|
if (!tn.skip(Token.OPENPAREN)) {
|
||||||
|
this.error(
|
||||||
|
DiagnosticCode._0_expected,
|
||||||
|
tn.range(tn.pos), "("
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// or at '(' of arrow function:
|
||||||
|
// Parameters (':' Type)?
|
||||||
|
// Statement
|
||||||
|
|
||||||
|
} else {
|
||||||
|
isArrow = true;
|
||||||
|
assert(tn.token == Token.OPENPAREN);
|
||||||
|
identifier = Node.createIdentifierExpression("", tn.range(tn.tokenPos, tn.tokenPos));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: type parameters? doesn't seem worth it.
|
||||||
|
|
||||||
|
var parameters = this.parseParameters(tn);
|
||||||
|
if (!parameters) return null;
|
||||||
|
|
||||||
|
return this.parseFunctionExpressionCommon(tn, identifier, parameters, isArrow, startPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseFunctionExpressionCommon(
|
||||||
|
tn: Tokenizer,
|
||||||
|
identifier: IdentifierExpression,
|
||||||
|
parameters: Parameter[],
|
||||||
|
isArrow: bool,
|
||||||
|
startPos: i32 = -1
|
||||||
|
): FunctionExpression | null {
|
||||||
|
if (startPos < 0) startPos = identifier.range.start;
|
||||||
|
|
||||||
|
var returnType: TypeNode | null = null;
|
||||||
|
if (tn.skip(Token.COLON)) {
|
||||||
|
returnType = this.parseType(tn);
|
||||||
|
if (!returnType) return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isArrow) {
|
||||||
|
if (!tn.skip(Token.EQUALS_GREATERTHAN)) {
|
||||||
|
this.error(
|
||||||
|
DiagnosticCode._0_expected,
|
||||||
|
tn.range(tn.pos), "=>"
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: Statement | null;
|
||||||
|
if (isArrow) {
|
||||||
|
body = this.parseStatement(tn, false);
|
||||||
|
} else {
|
||||||
|
if (!tn.skip(Token.OPENBRACE)) {
|
||||||
|
this.error(
|
||||||
|
DiagnosticCode._0_expected,
|
||||||
|
tn.range(tn.pos), "{"
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
body = this.parseBlockStatement(tn, false);
|
||||||
|
}
|
||||||
|
if (!body) return null;
|
||||||
|
|
||||||
|
var declaration = Node.createFunctionDeclaration(
|
||||||
|
identifier,
|
||||||
|
[],
|
||||||
|
parameters,
|
||||||
|
returnType,
|
||||||
|
body,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
tn.range(startPos, tn.pos)
|
||||||
|
);
|
||||||
|
return Node.createFunctionExpression(declaration, isArrow);
|
||||||
|
}
|
||||||
|
|
||||||
parseClass(
|
parseClass(
|
||||||
tn: Tokenizer,
|
tn: Tokenizer,
|
||||||
modifiers: Modifier[] | null,
|
modifiers: Modifier[] | null,
|
||||||
@ -1184,7 +1276,7 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
); // recoverable
|
); // recoverable
|
||||||
}
|
}
|
||||||
|
|
||||||
var statements: Statement[] | null = null;
|
var body: Statement | null = null;
|
||||||
if (tn.skip(Token.OPENBRACE)) {
|
if (tn.skip(Token.OPENBRACE)) {
|
||||||
if (parentIsDeclare) {
|
if (parentIsDeclare) {
|
||||||
this.error(
|
this.error(
|
||||||
@ -1192,12 +1284,8 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
tn.range()
|
tn.range()
|
||||||
); // recoverable
|
); // recoverable
|
||||||
}
|
}
|
||||||
statements = new Array();
|
body = this.parseBlockStatement(tn, false);
|
||||||
while (!tn.skip(Token.CLOSEBRACE)) {
|
if (!body) return null;
|
||||||
var statement = this.parseStatement(tn);
|
|
||||||
if (!statement) return null;
|
|
||||||
statements.push(<Statement>statement);
|
|
||||||
}
|
|
||||||
} else if (!parentIsDeclare) {
|
} else if (!parentIsDeclare) {
|
||||||
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,
|
||||||
@ -1210,7 +1298,7 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
typeParameters,
|
typeParameters,
|
||||||
parameters,
|
parameters,
|
||||||
returnType,
|
returnType,
|
||||||
statements,
|
body,
|
||||||
modifiers,
|
modifiers,
|
||||||
decorators,
|
decorators,
|
||||||
tn.range(startPos, tn.pos)
|
tn.range(startPos, tn.pos)
|
||||||
@ -2212,7 +2300,68 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
switch (token) {
|
switch (token) {
|
||||||
|
|
||||||
// ParenthesizedExpression
|
// ParenthesizedExpression
|
||||||
|
// FunctionExpression
|
||||||
case Token.OPENPAREN:
|
case Token.OPENPAREN:
|
||||||
|
|
||||||
|
// determine whether this is a function expression
|
||||||
|
if (tn.skip(Token.CLOSEPAREN)) { // must be a function expression (fast route)
|
||||||
|
return this.parseFunctionExpressionCommon(
|
||||||
|
tn,
|
||||||
|
Node.createIdentifierExpression("", tn.range(startPos, startPos)),
|
||||||
|
[],
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
tn.mark();
|
||||||
|
var again = true;
|
||||||
|
do {
|
||||||
|
switch (tn.next(true)) {
|
||||||
|
|
||||||
|
// function expression
|
||||||
|
case Token.DOT_DOT_DOT:
|
||||||
|
tn.reset();
|
||||||
|
return this.parseFunctionExpression(tn);
|
||||||
|
|
||||||
|
// can be both
|
||||||
|
case Token.IDENTIFIER:
|
||||||
|
tn.readIdentifier();
|
||||||
|
switch (tn.next()) {
|
||||||
|
|
||||||
|
// if we got here, check for arrow
|
||||||
|
case Token.CLOSEPAREN:
|
||||||
|
if (!tn.skip(Token.EQUALS_GREATERTHAN)) {
|
||||||
|
again = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// fall-through
|
||||||
|
|
||||||
|
// function expression
|
||||||
|
case Token.QUESTION: // optional parameter
|
||||||
|
case Token.COLON: // type annotation
|
||||||
|
tn.reset();
|
||||||
|
return this.parseFunctionExpression(tn);
|
||||||
|
|
||||||
|
// can be both
|
||||||
|
case Token.COMMA:
|
||||||
|
break; // continue
|
||||||
|
|
||||||
|
// parenthesized expression
|
||||||
|
// case Token.EQUALS: // missing type annotation for simplicity
|
||||||
|
default:
|
||||||
|
again = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// parenthesized expression
|
||||||
|
default:
|
||||||
|
again = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (again);
|
||||||
|
tn.reset();
|
||||||
|
|
||||||
|
// parse parenthesized
|
||||||
expr = this.parseExpression(tn);
|
expr = this.parseExpression(tn);
|
||||||
if (!expr) return null;
|
if (!expr) return null;
|
||||||
if (!tn.skip(Token.CLOSEPAREN)) {
|
if (!tn.skip(Token.CLOSEPAREN)) {
|
||||||
@ -2307,6 +2456,9 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
tn.range(startPos, tn.pos)
|
tn.range(startPos, tn.pos)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
case Token.FUNCTION:
|
||||||
|
return this.parseFunctionExpression(tn);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
this.error(
|
this.error(
|
||||||
DiagnosticCode.Expression_expected,
|
DiagnosticCode.Expression_expected,
|
||||||
|
16
tests/parser/function-expression.ts
Normal file
16
tests/parser/function-expression.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
var a = function(): void {
|
||||||
|
;
|
||||||
|
};
|
||||||
|
var b = function someName(): void {
|
||||||
|
;
|
||||||
|
};
|
||||||
|
var c = function(a: i32, b: i32): i32 {
|
||||||
|
;
|
||||||
|
};
|
||||||
|
var d = (): void => {
|
||||||
|
;
|
||||||
|
};
|
||||||
|
var e = (a: i32, b: i32): i32 => {
|
||||||
|
;
|
||||||
|
};
|
||||||
|
var f = (a: i32): i32 => a;
|
16
tests/parser/function-expression.ts.fixture.ts
Normal file
16
tests/parser/function-expression.ts.fixture.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
var a = function(): void {
|
||||||
|
;
|
||||||
|
};
|
||||||
|
var b = function someName(): void {
|
||||||
|
;
|
||||||
|
};
|
||||||
|
var c = function(a: i32, b: i32): i32 {
|
||||||
|
;
|
||||||
|
};
|
||||||
|
var d = (): void => {
|
||||||
|
;
|
||||||
|
};
|
||||||
|
var e = (a: i32, b: i32): i32 => {
|
||||||
|
;
|
||||||
|
};
|
||||||
|
var f = (a: i32): i32 => a;
|
Loading…
x
Reference in New Issue
Block a user