mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-26 07:22:21 +00:00
Initial function calls
This commit is contained in:
parent
d3d4938b68
commit
dc74dd118d
@ -440,23 +440,27 @@ export class Module {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createCall(target: BinaryenFunctionRef, operands: BinaryenExpressionRef[], returnType: Type): BinaryenExpressionRef {
|
createCall(target: string, operands: BinaryenExpressionRef[], returnType: Type): BinaryenExpressionRef {
|
||||||
if (this.noEmit) return 0;
|
if (this.noEmit) return 0;
|
||||||
|
const cStr: CString = allocString(target);
|
||||||
const cArr: CArray<i32> = allocI32Array(operands);
|
const cArr: CArray<i32> = allocI32Array(operands);
|
||||||
try {
|
try {
|
||||||
return _BinaryenCall(this.ref, target, cArr, operands.length, returnType);
|
return _BinaryenCall(this.ref, cStr, cArr, operands.length, returnType);
|
||||||
} finally {
|
} finally {
|
||||||
_free(cArr);
|
_free(cArr);
|
||||||
|
_free(cStr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createCallImport(target: BinaryenImportRef, operands: BinaryenExpressionRef[], returnType: Type): BinaryenExpressionRef {
|
createCallImport(target: string, operands: BinaryenExpressionRef[], returnType: Type): BinaryenExpressionRef {
|
||||||
if (this.noEmit) return 0;
|
if (this.noEmit) return 0;
|
||||||
|
const cStr: CString = allocString(target);
|
||||||
const cArr: CArray<i32> = allocI32Array(operands);
|
const cArr: CArray<i32> = allocI32Array(operands);
|
||||||
try {
|
try {
|
||||||
return _BinaryenCallImport(this.ref, target, cArr, operands.length, returnType);
|
return _BinaryenCallImport(this.ref, cStr, cArr, operands.length, returnType);
|
||||||
} finally {
|
} finally {
|
||||||
_free(cArr);
|
_free(cArr);
|
||||||
|
_free(cStr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { Module, MemorySegment, UnaryOp, BinaryOp, HostOp, Type as BinaryenType, Relooper } from "./binaryen";
|
import { Module, MemorySegment, UnaryOp, BinaryOp, HostOp, Type as BinaryenType, Relooper } from "./binaryen";
|
||||||
import { PATH_DELIMITER } from "./constants";
|
import { PATH_DELIMITER } from "./constants";
|
||||||
import { DiagnosticCode, DiagnosticMessage, DiagnosticEmitter } from "./diagnostics";
|
import { DiagnosticCode, DiagnosticMessage, DiagnosticEmitter } from "./diagnostics";
|
||||||
import { Program, ClassPrototype, Element, ElementKind, Enum, FunctionPrototype, Function, Global, Local, Namespace, Parameter } from "./program";
|
import { Program, ClassPrototype, Class, Element, ElementKind, Enum, FunctionPrototype, Function, Global, Local, Namespace, Parameter } from "./program";
|
||||||
import { CharCode, I64, U64, normalizePath, sb } from "./util";
|
import { CharCode, I64, U64, normalizePath, sb } from "./util";
|
||||||
import { Token } from "./tokenizer";
|
import { Token, Range } from "./tokenizer";
|
||||||
import {
|
import {
|
||||||
|
|
||||||
Node,
|
Node,
|
||||||
@ -376,18 +376,21 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
const element: Element | null = <Element | null>this.program.elements.get(internalName);
|
const element: Element | null = <Element | null>this.program.elements.get(internalName);
|
||||||
if (!element || element.kind != ElementKind.FUNCTION_PROTOTYPE)
|
if (!element || element.kind != ElementKind.FUNCTION_PROTOTYPE)
|
||||||
throw new Error("unexpected missing function");
|
throw new Error("unexpected missing function");
|
||||||
const resolvedTypeArguments: Type[] | null = this.program.resolveTypeArguments(declaration.typeParameters, typeArguments, contextualTypeArguments, alternativeReportNode); // reports
|
this.compileFunctionUsingTypeArguments(<FunctionPrototype>element, typeArguments, contextualTypeArguments, alternativeReportNode);
|
||||||
if (!resolvedTypeArguments)
|
|
||||||
return;
|
|
||||||
this.compileFunction(<FunctionPrototype>element, resolvedTypeArguments, contextualTypeArguments);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
compileFunction(template: FunctionPrototype, typeArguments: Type[], contextualTypeArguments: Map<string,Type> | null = null): void {
|
compileFunctionUsingTypeArguments(prototype: FunctionPrototype, typeArguments: TypeNode[], contextualTypeArguments: Map<string,Type> | null = null, alternativeReportNode: Node | null = null) {
|
||||||
const instance: Function | null = template.resolve(typeArguments, contextualTypeArguments);
|
const instance: Function | null = prototype.resolveInclTypeArguments(typeArguments, contextualTypeArguments, alternativeReportNode); // reports
|
||||||
if (!instance || instance.compiled)
|
if (!instance)
|
||||||
|
return;
|
||||||
|
this.compileFunction(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
compileFunction(instance: Function): void {
|
||||||
|
if (instance.compiled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const declaration: FunctionDeclaration | null = template.declaration;
|
const declaration: FunctionDeclaration | null = instance.template.declaration;
|
||||||
if (!declaration) // TODO: compile builtins
|
if (!declaration) // TODO: compile builtins
|
||||||
throw new Error("not implemented");
|
throw new Error("not implemented");
|
||||||
|
|
||||||
@ -470,7 +473,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
|
|
||||||
case ElementKind.CLASS_PROTOTYPE:
|
case ElementKind.CLASS_PROTOTYPE:
|
||||||
if ((noTreeShaking || (<ClassPrototype>element).isExport) && !(<ClassPrototype>element).isGeneric)
|
if ((noTreeShaking || (<ClassPrototype>element).isExport) && !(<ClassPrototype>element).isGeneric)
|
||||||
this.compileClass(<ClassPrototype>element, []);
|
this.compileClassUsingTypeArguments(<ClassPrototype>element, []);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ElementKind.ENUM:
|
case ElementKind.ENUM:
|
||||||
@ -479,7 +482,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
|
|
||||||
case ElementKind.FUNCTION_PROTOTYPE:
|
case ElementKind.FUNCTION_PROTOTYPE:
|
||||||
if ((noTreeShaking || (<FunctionPrototype>element).isExport) && !(<FunctionPrototype>element).isGeneric)
|
if ((noTreeShaking || (<FunctionPrototype>element).isExport) && !(<FunctionPrototype>element).isGeneric)
|
||||||
this.compileFunction(<FunctionPrototype>element, []);
|
this.compileFunctionUsingTypeArguments(<FunctionPrototype>element, []);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ElementKind.GLOBAL:
|
case ElementKind.GLOBAL:
|
||||||
@ -508,7 +511,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
|
|
||||||
case ElementKind.CLASS_PROTOTYPE:
|
case ElementKind.CLASS_PROTOTYPE:
|
||||||
if (!(<ClassPrototype>element).isGeneric)
|
if (!(<ClassPrototype>element).isGeneric)
|
||||||
this.compileClass(<ClassPrototype>element, []);
|
this.compileClassUsingTypeArguments(<ClassPrototype>element, []);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ElementKind.ENUM:
|
case ElementKind.ENUM:
|
||||||
@ -517,7 +520,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
|
|
||||||
case ElementKind.FUNCTION_PROTOTYPE:
|
case ElementKind.FUNCTION_PROTOTYPE:
|
||||||
if (!(<FunctionPrototype>element).isGeneric)
|
if (!(<FunctionPrototype>element).isGeneric)
|
||||||
this.compileFunction(<FunctionPrototype>element, []);
|
this.compileFunctionUsingTypeArguments(<FunctionPrototype>element, []);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ElementKind.GLOBAL:
|
case ElementKind.GLOBAL:
|
||||||
@ -538,13 +541,17 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
const element: Element | null = <Element | null>this.program.elements.get(internalName);
|
const element: Element | null = <Element | null>this.program.elements.get(internalName);
|
||||||
if (!element || element.kind != ElementKind.CLASS_PROTOTYPE)
|
if (!element || element.kind != ElementKind.CLASS_PROTOTYPE)
|
||||||
throw new Error("unexpected missing class");
|
throw new Error("unexpected missing class");
|
||||||
const resolvedTypeArguments: Type[] | null = this.program.resolveTypeArguments(declaration.typeParameters, typeArguments, contextualTypeArguments, alternativeReportNode); // reports
|
this.compileClassUsingTypeArguments(<ClassPrototype>element, typeArguments, contextualTypeArguments, alternativeReportNode);
|
||||||
if (!resolvedTypeArguments)
|
|
||||||
return;
|
|
||||||
this.compileClass(<ClassPrototype>element, resolvedTypeArguments, contextualTypeArguments);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
compileClass(cls: ClassPrototype, typeArguments: Type[], contextualTypeArguments: Map<string,Type> | null = null) {
|
compileClassUsingTypeArguments(prototype: ClassPrototype, typeArguments: TypeNode[], contextualTypeArguments: Map<string,Type> | null = null, alternativeReportNode: Node | null = null): void {
|
||||||
|
const instance: Class | null = prototype.resolveInclTypeArguments(typeArguments, contextualTypeArguments, alternativeReportNode);
|
||||||
|
if (!instance)
|
||||||
|
return;
|
||||||
|
this.compileClass(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
compileClass(cls: Class) {
|
||||||
throw new Error("not implemented");
|
throw new Error("not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1319,14 +1326,46 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
const element: Element | null = this.program.resolveElement(expression.expression, this.currentFunction); // reports
|
const element: Element | null = this.program.resolveElement(expression.expression, this.currentFunction); // reports
|
||||||
if (!element)
|
if (!element)
|
||||||
return this.module.createUnreachable();
|
return this.module.createUnreachable();
|
||||||
if (element.kind != ElementKind.FUNCTION_PROTOTYPE) {
|
if (element.kind == ElementKind.FUNCTION_PROTOTYPE) {
|
||||||
// TODO: report 'Cannot invoke an expression whose type lacks a call signature.'
|
const functionInstance: Function | null = (<FunctionPrototype>element).resolveInclTypeArguments(expression.typeArguments, this.currentFunction.contextualTypeArguments, expression); // reports
|
||||||
|
if (!functionInstance)
|
||||||
|
return this.module.createUnreachable();
|
||||||
|
return this.compileCall(functionInstance, expression.arguments, expression);
|
||||||
|
}
|
||||||
|
this.error(DiagnosticCode.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures, expression.range, element.internalName);
|
||||||
|
return this.module.createUnreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
compileCall(functionInstance: Function, argumentExpressions: Expression[], reportNode: Node): BinaryenExpressionRef {
|
||||||
|
if (!functionInstance.compiled)
|
||||||
|
this.compileFunction(functionInstance);
|
||||||
|
const parameters: Parameter[] = functionInstance.parameters;
|
||||||
|
let k: i32 = parameters.length;
|
||||||
|
if (argumentExpressions.length > k) {
|
||||||
|
this.error(DiagnosticCode.Expected_0_arguments_but_got_1, reportNode.range, k.toString(10), argumentExpressions.length.toString(10));
|
||||||
return this.module.createUnreachable();
|
return this.module.createUnreachable();
|
||||||
}
|
}
|
||||||
throw new Error("not implemented");
|
const operands: BinaryenExpressionRef[] = new Array(k);
|
||||||
|
for (let i: i32 = 0; i < k; ++i) {
|
||||||
|
if (argumentExpressions.length > i) {
|
||||||
|
operands[i] = this.compileExpression(argumentExpressions[i], parameters[i].type);
|
||||||
|
} else {
|
||||||
|
const initializer: Expression | null = parameters[i].initializer;
|
||||||
|
if (initializer) {
|
||||||
|
operands[i] = this.compileExpression(initializer, parameters[i].type);
|
||||||
|
} else {
|
||||||
|
this.error(DiagnosticCode.Expected_at_least_0_arguments_but_got_1, reportNode.range, (i + 1).toString(10), argumentExpressions.length.toString(10));
|
||||||
|
return this.module.createUnreachable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.module.createCall(functionInstance.internalName, operands, typeToBinaryenType(functionInstance.returnType));
|
||||||
}
|
}
|
||||||
|
|
||||||
compileElementAccessExpression(expression: ElementAccessExpression, contextualType: Type): BinaryenExpressionRef {
|
compileElementAccessExpression(expression: ElementAccessExpression, contextualType: Type): BinaryenExpressionRef {
|
||||||
|
const element: Element | null = this.program.resolveElement(expression.expression, this.currentFunction); // reports
|
||||||
|
if (!element)
|
||||||
|
return this.module.createUnreachable();
|
||||||
throw new Error("not implemented");
|
throw new Error("not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,12 +52,15 @@ export enum DiagnosticCode {
|
|||||||
Type_0_is_not_assignable_to_type_1 = 2322,
|
Type_0_is_not_assignable_to_type_1 = 2322,
|
||||||
_this_cannot_be_referenced_in_current_location = 2332,
|
_this_cannot_be_referenced_in_current_location = 2332,
|
||||||
Property_0_does_not_exist_on_type_1 = 2339,
|
Property_0_does_not_exist_on_type_1 = 2339,
|
||||||
|
Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures = 2349,
|
||||||
The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_or_a_property_access = 2357,
|
The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_or_a_property_access = 2357,
|
||||||
The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access = 2364,
|
The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access = 2364,
|
||||||
Function_implementation_is_missing_or_not_immediately_following_the_declaration = 2391,
|
Function_implementation_is_missing_or_not_immediately_following_the_declaration = 2391,
|
||||||
Duplicate_function_implementation = 2393,
|
Duplicate_function_implementation = 2393,
|
||||||
Export_declaration_conflicts_with_exported_declaration_of_0 = 2484,
|
Export_declaration_conflicts_with_exported_declaration_of_0 = 2484,
|
||||||
The_target_of_an_assignment_must_be_a_variable_or_a_property_access = 2541,
|
The_target_of_an_assignment_must_be_a_variable_or_a_property_access = 2541,
|
||||||
|
Expected_0_arguments_but_got_1 = 2554,
|
||||||
|
Expected_at_least_0_arguments_but_got_1 = 2555,
|
||||||
Expected_0_type_arguments_but_got_1 = 2558,
|
Expected_0_type_arguments_but_got_1 = 2558,
|
||||||
File_0_not_found = 6054
|
File_0_not_found = 6054
|
||||||
}
|
}
|
||||||
@ -115,12 +118,15 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
|
|||||||
case 2322: return "Type '{0}' is not assignable to type '{1}'.";
|
case 2322: return "Type '{0}' is not assignable to type '{1}'.";
|
||||||
case 2332: return "'this' cannot be referenced in current location.";
|
case 2332: return "'this' cannot be referenced in current location.";
|
||||||
case 2339: return "Property '{0}' does not exist on type '{1}'.";
|
case 2339: return "Property '{0}' does not exist on type '{1}'.";
|
||||||
|
case 2349: return "Cannot invoke an expression whose type lacks a call signature. Type '{0}' has no compatible call signatures.";
|
||||||
case 2357: return "The operand of an increment or decrement operator must be a variable or a property access.";
|
case 2357: return "The operand of an increment or decrement operator must be a variable or a property access.";
|
||||||
case 2364: return "The left-hand side of an assignment expression must be a variable or a property access.";
|
case 2364: return "The left-hand side of an assignment expression must be a variable or a property access.";
|
||||||
case 2391: return "Function implementation is missing or not immediately following the declaration.";
|
case 2391: return "Function implementation is missing or not immediately following the declaration.";
|
||||||
case 2393: return "Duplicate function implementation.";
|
case 2393: return "Duplicate function implementation.";
|
||||||
case 2484: return "Export declaration conflicts with exported declaration of '{0}'.";
|
case 2484: return "Export declaration conflicts with exported declaration of '{0}'.";
|
||||||
case 2541: return "The target of an assignment must be a variable or a property access.";
|
case 2541: return "The target of an assignment must be a variable or a property access.";
|
||||||
|
case 2554: return "Expected {0} arguments, but got {1}.";
|
||||||
|
case 2555: return "Expected at least {0} arguments, but got {1}.";
|
||||||
case 2558: return "Expected {0} type arguments, but got {1}.";
|
case 2558: return "Expected {0} type arguments, but got {1}.";
|
||||||
case 6054: return "File '{0}' not found.";
|
case 6054: return "File '{0}' not found.";
|
||||||
default: return "";
|
default: return "";
|
||||||
|
@ -52,12 +52,15 @@
|
|||||||
"Type '{0}' is not assignable to type '{1}'.": 2322,
|
"Type '{0}' is not assignable to type '{1}'.": 2322,
|
||||||
"'this' cannot be referenced in current location.": 2332,
|
"'this' cannot be referenced in current location.": 2332,
|
||||||
"Property '{0}' does not exist on type '{1}'.": 2339,
|
"Property '{0}' does not exist on type '{1}'.": 2339,
|
||||||
|
"Cannot invoke an expression whose type lacks a call signature. Type '{0}' has no compatible call signatures.": 2349,
|
||||||
"The operand of an increment or decrement operator must be a variable or a property access.": 2357,
|
"The operand of an increment or decrement operator must be a variable or a property access.": 2357,
|
||||||
"The left-hand side of an assignment expression must be a variable or a property access.": 2364,
|
"The left-hand side of an assignment expression must be a variable or a property access.": 2364,
|
||||||
"Function implementation is missing or not immediately following the declaration.": 2391,
|
"Function implementation is missing or not immediately following the declaration.": 2391,
|
||||||
"Duplicate function implementation.": 2393,
|
"Duplicate function implementation.": 2393,
|
||||||
"Export declaration conflicts with exported declaration of '{0}'.": 2484,
|
"Export declaration conflicts with exported declaration of '{0}'.": 2484,
|
||||||
"The target of an assignment must be a variable or a property access.": 2541,
|
"The target of an assignment must be a variable or a property access.": 2541,
|
||||||
|
"Expected {0} arguments, but got {1}.": 2554,
|
||||||
|
"Expected at least {0} arguments, but got {1}.": 2555,
|
||||||
"Expected {0} type arguments, but got {1}.": 2558,
|
"Expected {0} type arguments, but got {1}.": 2558,
|
||||||
|
|
||||||
"File '{0}' not found.": 6054
|
"File '{0}' not found.": 6054
|
||||||
|
@ -508,19 +508,19 @@ export class Program extends DiagnosticEmitter {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
resolveTypeArguments(typeParameters: TypeParameter[], typeArgumentNodes: TypeNode[], contextualTypeArguments: Map<string,Type> | null = null, alternativeReportNode: Node | null = null): Type[] | null {
|
resolveTypeArguments(typeParameters: TypeParameter[], typeArgumentNodes: TypeNode[] | null, contextualTypeArguments: Map<string,Type> | null = null, alternativeReportNode: Node | null = null): Type[] | null {
|
||||||
const parameterCount: i32 = typeParameters.length;
|
const parameterCount: i32 = typeParameters.length;
|
||||||
const argumentCount: i32 = typeArgumentNodes.length;
|
const argumentCount: i32 = typeArgumentNodes ? typeArgumentNodes.length : 0;
|
||||||
if (parameterCount != argumentCount) {
|
if (parameterCount != argumentCount) {
|
||||||
if (argumentCount)
|
if (argumentCount)
|
||||||
this.error(DiagnosticCode.Expected_0_type_arguments_but_got_1, Range.join(typeArgumentNodes[0].range, typeArgumentNodes[argumentCount - 1].range), parameterCount.toString(10), argumentCount.toString(10));
|
this.error(DiagnosticCode.Expected_0_type_arguments_but_got_1, Range.join((<TypeNode[]>typeArgumentNodes)[0].range, (<TypeNode[]>typeArgumentNodes)[argumentCount - 1].range), parameterCount.toString(10), argumentCount.toString(10));
|
||||||
else if (alternativeReportNode)
|
else if (alternativeReportNode)
|
||||||
this.error(DiagnosticCode.Expected_0_type_arguments_but_got_1, alternativeReportNode.range.atEnd, parameterCount.toString(10), "0");
|
this.error(DiagnosticCode.Expected_0_type_arguments_but_got_1, alternativeReportNode.range.atEnd, parameterCount.toString(10), "0");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const typeArguments: Type[] = new Array(parameterCount);
|
const typeArguments: Type[] = new Array(parameterCount);
|
||||||
for (let i: i32 = 0; i < parameterCount; ++i) {
|
for (let i: i32 = 0; i < parameterCount; ++i) {
|
||||||
const type: Type | null = this.resolveType(typeArgumentNodes[i], contextualTypeArguments, true); // reports
|
const type: Type | null = this.resolveType((<TypeNode[]>typeArgumentNodes)[i], contextualTypeArguments, true); // reports
|
||||||
if (!type)
|
if (!type)
|
||||||
return null;
|
return null;
|
||||||
// TODO: check extendsType
|
// TODO: check extendsType
|
||||||
@ -531,7 +531,7 @@ export class Program extends DiagnosticEmitter {
|
|||||||
|
|
||||||
resolveElement(expression: Expression, contextualFunction: Function): Element | null {
|
resolveElement(expression: Expression, contextualFunction: Function): Element | null {
|
||||||
|
|
||||||
// this
|
// this -> Class
|
||||||
if (expression.kind == NodeKind.THIS) {
|
if (expression.kind == NodeKind.THIS) {
|
||||||
if (contextualFunction.instanceMethodOf)
|
if (contextualFunction.instanceMethodOf)
|
||||||
return contextualFunction.instanceMethodOf;
|
return contextualFunction.instanceMethodOf;
|
||||||
@ -539,6 +539,8 @@ export class Program extends DiagnosticEmitter {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let ret: Element;
|
||||||
|
|
||||||
// local or global name
|
// local or global name
|
||||||
if (expression.kind == NodeKind.IDENTIFIER) {
|
if (expression.kind == NodeKind.IDENTIFIER) {
|
||||||
const name: string = (<IdentifierExpression>expression).name;
|
const name: string = (<IdentifierExpression>expression).name;
|
||||||
@ -557,10 +559,10 @@ export class Program extends DiagnosticEmitter {
|
|||||||
// static or instance property (incl. enum values) or method
|
// static or instance property (incl. enum values) or method
|
||||||
} else if (expression.kind == NodeKind.PROPERTYACCESS) {
|
} else if (expression.kind == NodeKind.PROPERTYACCESS) {
|
||||||
const target: Element | null = this.resolveElement((<PropertyAccessExpression>expression).expression, contextualFunction); // reports
|
const target: Element | null = this.resolveElement((<PropertyAccessExpression>expression).expression, contextualFunction); // reports
|
||||||
let member: Element | null = null;
|
|
||||||
if (!target)
|
if (!target)
|
||||||
return null;
|
return null;
|
||||||
const propertyName: string = (<PropertyAccessExpression>expression).property.name;
|
const propertyName: string = (<PropertyAccessExpression>expression).property.name;
|
||||||
|
let member: Element | null = null;
|
||||||
if (target.kind == ElementKind.ENUM)
|
if (target.kind == ElementKind.ENUM)
|
||||||
member = <EnumValue | null>(<Enum>target).members.get(propertyName);
|
member = <EnumValue | null>(<Enum>target).members.get(propertyName);
|
||||||
else if (target.kind == ElementKind.CLASS_PROTOTYPE)
|
else if (target.kind == ElementKind.CLASS_PROTOTYPE)
|
||||||
@ -702,10 +704,12 @@ export class Parameter {
|
|||||||
|
|
||||||
name: string;
|
name: string;
|
||||||
type: Type;
|
type: Type;
|
||||||
|
initializer: Expression | null;
|
||||||
|
|
||||||
constructor(name: string, type: Type) {
|
constructor(name: string, type: Type, initializer: Expression | null = null) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
this.initializer = initializer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -802,26 +806,51 @@ export class FunctionPrototype extends Element {
|
|||||||
this.instances.set(instanceKey, instance);
|
this.instances.set(instanceKey, instance);
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resolveInclTypeArguments(typeArgumentNodes: TypeNode[] | null, contextualTypeArguments: Map<string,Type> | null, alternativeReportNode: Node | null): Function | null {
|
||||||
|
let resolvedTypeArguments: Type[] | null;
|
||||||
|
if (this.isGeneric) {
|
||||||
|
if (!this.declaration)
|
||||||
|
throw new Error("not implemented"); // generic builtin
|
||||||
|
resolvedTypeArguments = this.program.resolveTypeArguments(this.declaration.typeParameters, typeArgumentNodes, contextualTypeArguments, alternativeReportNode);
|
||||||
|
if (!resolvedTypeArguments)
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
// TODO: check typeArgumentNodes being empty
|
||||||
|
resolvedTypeArguments = [];
|
||||||
|
}
|
||||||
|
return this.resolve(resolvedTypeArguments, contextualTypeArguments);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A resolved function. */
|
/** A resolved function. */
|
||||||
export class Function extends Element {
|
export class Function extends Element {
|
||||||
|
|
||||||
kind = ElementKind.FUNCTION;
|
kind = ElementKind.FUNCTION;
|
||||||
template: FunctionPrototype;
|
|
||||||
typeArguments: Type[];
|
|
||||||
parameters: Parameter[];
|
|
||||||
returnType: Type;
|
|
||||||
instanceMethodOf: Class | null;
|
|
||||||
locals: Map<string,Local> = new Map();
|
|
||||||
additionalLocals: Type[] = []; // without parameters
|
|
||||||
breakContext: string | null = null;
|
|
||||||
|
|
||||||
|
/** Underlying function template. */
|
||||||
|
template: FunctionPrototype;
|
||||||
|
/** Concrete type arguments. */
|
||||||
|
typeArguments: Type[];
|
||||||
|
/** Concrete function parameters. */
|
||||||
|
parameters: Parameter[];
|
||||||
|
/** Concrete return type. */
|
||||||
|
returnType: Type;
|
||||||
|
/** If a method, the concrete class it is a member of. */
|
||||||
|
instanceMethodOf: Class | null;
|
||||||
|
/** Map of locals by name. */
|
||||||
|
locals: Map<string,Local> = new Map();
|
||||||
|
/** List of additional non-parameter locals. */
|
||||||
|
additionalLocals: Type[] = [];
|
||||||
|
/** Current break context label. */
|
||||||
|
breakContext: string | null = null;
|
||||||
|
/** Contextual type arguments. */
|
||||||
contextualTypeArguments: Map<string,Type> = new Map();
|
contextualTypeArguments: Map<string,Type> = new Map();
|
||||||
|
|
||||||
private breakMajor: i32 = 0;
|
private breakMajor: i32 = 0;
|
||||||
private breakMinor: i32 = 0;
|
private breakMinor: i32 = 0;
|
||||||
|
|
||||||
|
/** Constructs a new concrete function. */
|
||||||
constructor(template: FunctionPrototype, internalName: string, typeArguments: Type[], parameters: Parameter[], returnType: Type, instanceMethodOf: Class | null) {
|
constructor(template: FunctionPrototype, internalName: string, typeArguments: Type[], parameters: Parameter[], returnType: Type, instanceMethodOf: Class | null) {
|
||||||
super(template.program, internalName);
|
super(template.program, internalName);
|
||||||
this.template = template;
|
this.template = template;
|
||||||
@ -841,8 +870,10 @@ export class Function extends Element {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Tests if this function is an instance method. */
|
||||||
get isInstance(): bool { return this.instanceMethodOf != null; }
|
get isInstance(): bool { return this.instanceMethodOf != null; }
|
||||||
|
|
||||||
|
/** Adds a local of the specified type, with an optional name. */
|
||||||
addLocal(type: Type, name: string | null = null): Local {
|
addLocal(type: Type, name: string | null = null): Local {
|
||||||
// if it has a name, check previously as this method will throw otherwise
|
// if it has a name, check previously as this method will throw otherwise
|
||||||
let localIndex = this.parameters.length + this.additionalLocals.length;
|
let localIndex = this.parameters.length + this.additionalLocals.length;
|
||||||
@ -857,12 +888,14 @@ export class Function extends Element {
|
|||||||
return local;
|
return local;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Enters a(nother) break context. */
|
||||||
enterBreakContext(): string {
|
enterBreakContext(): string {
|
||||||
if (!this.breakMinor)
|
if (!this.breakMinor)
|
||||||
this.breakMajor++;
|
this.breakMajor++;
|
||||||
return this.breakContext = this.breakMajor.toString(10) + "." + (++this.breakMinor).toString(10);
|
return this.breakContext = this.breakMajor.toString(10) + "." + (++this.breakMinor).toString(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Leaves the current break context. */
|
||||||
leaveBreakContext(): void {
|
leaveBreakContext(): void {
|
||||||
if (--this.breakMinor < 0)
|
if (--this.breakMinor < 0)
|
||||||
throw new Error("unexpected unbalanced break context");
|
throw new Error("unexpected unbalanced break context");
|
||||||
@ -931,6 +964,21 @@ export class ClassPrototype extends Namespace {
|
|||||||
throw new Error("unexpected instantiation of internal class");
|
throw new Error("unexpected instantiation of internal class");
|
||||||
throw new Error("not implemented");
|
throw new Error("not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resolveInclTypeArguments(typeArgumentNodes: TypeNode[] | null, contextualTypeArguments: Map<string,Type> | null, alternativeReportNode: Node | null): Class | null {
|
||||||
|
let resolvedTypeArguments: Type[] | null;
|
||||||
|
if (this.isGeneric) {
|
||||||
|
if (!this.declaration)
|
||||||
|
throw new Error("not implemented"); // generic builtin
|
||||||
|
resolvedTypeArguments = this.program.resolveTypeArguments(this.declaration.typeParameters, typeArgumentNodes, contextualTypeArguments, alternativeReportNode);
|
||||||
|
if (!resolvedTypeArguments)
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
// TODO: check typeArgumentNodes being empty
|
||||||
|
resolvedTypeArguments = [];
|
||||||
|
}
|
||||||
|
return this.resolve(resolvedTypeArguments, contextualTypeArguments);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A resolved class. */
|
/** A resolved class. */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user