Fixed a function expression parsing issue

Also uncovered a yet-to-be-fixed issue when immediately calling a returned function
This commit is contained in:
dcodeIO 2018-03-12 19:39:05 +01:00
parent 7870e3ac18
commit c93f0bb1fe
10 changed files with 51 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

@ -124,6 +124,10 @@ export function serializeNode(node: Node, sb: string[]): void {
serializeCallExpression(<CallExpression>node, sb);
break;
}
case NodeKind.COMMA: {
serializeCommaExpression(<CommaExpression>node, sb);
break;
}
case NodeKind.ELEMENTACCESS: {
serializeElementAccessExpression(<ElementAccessExpression>node, sb);
break;

View File

@ -2810,11 +2810,14 @@ export class Parser extends DiagnosticEmitter {
if (!expr) return null;
var startPos = expr.range.start;
// CallExpression
var typeArguments = this.tryParseTypeArgumentsBeforeArguments(tn); // skips '(' on success
// there might be better ways to distinguish a LESSTHAN from a CALL with type arguments
if (typeArguments || tn.skip(Token.OPENPAREN)) {
var args = this.parseArguments(tn);
// CallExpression with type arguments
var typeArguments: CommonTypeNode[] | null;
while (
// there might be better ways to distinguish a LESSTHAN from a CALL with type arguments
(typeArguments = this.tryParseTypeArgumentsBeforeArguments(tn)) ||
tn.skip(Token.OPENPAREN)
) {
let args = this.parseArguments(tn);
if (!args) return null;
expr = Node.createCallExpression(expr, typeArguments, args, tn.range(startPos, tn.pos));
}

View File

@ -1697,16 +1697,18 @@ export class Program extends DiagnosticEmitter {
expression: Expression,
contextualFunction: Function
): ResolvedElement | null {
var classType: Class | null;
while (expression.kind == NodeKind.PARENTHESIZED) {
expression = (<ParenthesizedExpression>expression).expression;
}
switch (expression.kind) {
case NodeKind.ASSERTION: {
var type = this.resolveType((<AssertionExpression>expression).toType); // reports
if (type && (classType = type.classType)) {
if (!resolvedElement) resolvedElement = new ResolvedElement();
return resolvedElement.set(classType);
let type = this.resolveType((<AssertionExpression>expression).toType); // reports
if (type) {
let classType = type.classType;
if (classType) {
if (!resolvedElement) resolvedElement = new ResolvedElement();
return resolvedElement.set(classType);
}
}
return null;
}
@ -1714,7 +1716,8 @@ export class Program extends DiagnosticEmitter {
throw new Error("not implemented");
}
case NodeKind.THIS: { // -> Class
if (classType = contextualFunction.instanceMethodOf) {
let classType = contextualFunction.instanceMethodOf;
if (classType) {
if (!resolvedElement) resolvedElement = new ResolvedElement();
return resolvedElement.set(classType);
}
@ -1725,7 +1728,8 @@ export class Program extends DiagnosticEmitter {
return null;
}
case NodeKind.SUPER: { // -> Class
if ((classType = contextualFunction.instanceMethodOf) && (classType = classType.base)) {
let classType = contextualFunction.instanceMethodOf;
if (classType && (classType = classType.base)) {
if (!resolvedElement) resolvedElement = new ResolvedElement();
return resolvedElement.set(classType);
}
@ -1751,21 +1755,31 @@ export class Program extends DiagnosticEmitter {
);
}
case NodeKind.CALL: {
var resolved = this.resolveExpression(
let resolved = this.resolveExpression(
(<CallExpression>expression).expression,
contextualFunction
);
if (resolved) {
var element = resolved.element;
let element = resolved.element;
if (element && element.kind == ElementKind.FUNCTION_PROTOTYPE) {
var instance = (<FunctionPrototype>element).resolveUsingTypeArguments(
let instance = (<FunctionPrototype>element).resolveUsingTypeArguments(
(<CallExpression>expression).typeArguments,
null,
expression
);
if (instance && (classType = instance.signature.returnType.classType)) {
if (!resolvedElement) resolvedElement = new ResolvedElement();
return resolvedElement.set(classType);
if (instance) {
let returnType = instance.signature.returnType;
let classType = returnType.classType;
if (classType) {
if (!resolvedElement) resolvedElement = new ResolvedElement();
return resolvedElement.set(classType);
} else {
let functionType = returnType.functionType;
if (functionType) {
// TODO: Signatures aren't elements but probably should be
throw new Error("not implemented");
}
}
}
}
}

View File

@ -2,12 +2,11 @@
(type $i (func (result i32)))
(type $iii (func (param i32 i32) (result i32)))
(type $III (func (param i64 i64) (result i64)))
(type $FFF (func (param f64 f64) (result f64)))
(type $v (func))
(global $function-types/i32Adder (mut i32) (i32.const 0))
(global $function-types/i64Adder (mut i32) (i32.const 0))
(table 3 3 anyfunc)
(elem (i32.const 0) $function-types/makeAdder<i32>~anonymous|0 $function-types/makeAdder<i64>~anonymous|1 $function-types/makeAdder<f64>~anonymous|2)
(table 2 2 anyfunc)
(elem (i32.const 0) $function-types/makeAdder<i32>~anonymous|0 $function-types/makeAdder<i64>~anonymous|1)
(memory $0 1)
(export "memory" (memory $0))
(start $start)
@ -29,16 +28,7 @@
(func $function-types/makeAdder<i64> (; 3 ;) (type $i) (result i32)
(i32.const 1)
)
(func $function-types/makeAdder<f64>~anonymous|2 (; 4 ;) (type $FFF) (param $0 f64) (param $1 f64) (result f64)
(f64.add
(get_local $0)
(get_local $1)
)
)
(func $function-types/makeAdder<f64> (; 5 ;) (type $i) (result i32)
(i32.const 2)
)
(func $start (; 6 ;) (type $v)
(func $start (; 4 ;) (type $v)
(set_global $function-types/i32Adder
(call $function-types/makeAdder<i32>)
)
@ -59,8 +49,5 @@
(get_global $function-types/i64Adder)
)
)
(drop
(call $function-types/makeAdder<f64>)
)
)
)

View File

@ -12,4 +12,5 @@ i32Adder(1, 2);
var i64Adder = makeAdder<i64>();
i64Adder(1, 2);
makeAdder<f64>()(1, 2);
// TODO:
// makeAdder<f64>()(1, 2);

View File

@ -2,13 +2,12 @@
(type $i (func (result i32)))
(type $iii (func (param i32 i32) (result i32)))
(type $III (func (param i64 i64) (result i64)))
(type $FFF (func (param f64 f64) (result f64)))
(type $v (func))
(global $function-types/i32Adder (mut i32) (i32.const 0))
(global $function-types/i64Adder (mut i32) (i32.const 0))
(global $HEAP_BASE i32 (i32.const 4))
(table 3 3 anyfunc)
(elem (i32.const 0) $function-types/makeAdder<i32>~anonymous|0 $function-types/makeAdder<i64>~anonymous|1 $function-types/makeAdder<f64>~anonymous|2)
(table 2 2 anyfunc)
(elem (i32.const 0) $function-types/makeAdder<i32>~anonymous|0 $function-types/makeAdder<i64>~anonymous|1)
(memory $0 1)
(export "memory" (memory $0))
(start $start)
@ -38,20 +37,7 @@
(i32.const 1)
)
)
(func $function-types/makeAdder<f64>~anonymous|2 (; 4 ;) (type $FFF) (param $0 f64) (param $1 f64) (result f64)
(return
(f64.add
(get_local $0)
(get_local $1)
)
)
)
(func $function-types/makeAdder<f64> (; 5 ;) (type $i) (result i32)
(return
(i32.const 2)
)
)
(func $start (; 6 ;) (type $v)
(func $start (; 4 ;) (type $v)
(nop)
(set_global $function-types/i32Adder
(call $function-types/makeAdder<i32>)
@ -73,16 +59,5 @@
(get_global $function-types/i64Adder)
)
)
(drop
(call $function-types/makeAdder<f64>)
)
(block
(drop
(i32.const 1)
)
(drop
(i32.const 2)
)
)
)
)

View File

@ -0,0 +1 @@
a = fn()(1, 2);

View File

@ -0,0 +1 @@
a = fn()(1, 2);