MichaReiser/speedy.js

View on GitHub
packages/compiler/src/code-generation/value/unresolved-function-reference.ts

Summary

Maintainability
A
0 mins
Test Coverage
import * as assert from "assert";
import * as llvm from "llvm-node";
import * as ts from "typescript";
import {CodeGenerationContext} from "../code-generation-context";
import {RuntimeSystemNameMangler} from "../runtime-system-name-mangler";
import {AbstractFunctionReference} from "./abstract-function-reference";
import {FunctionFactory, FunctionProperties} from "./function-factory";
import {ResolvedFunction} from "./resolved-function";
import {SpeedyJSFunctionFactory} from "./speedyjs-function-factory";

/**
 * Reference to a probably overloaded function.
 * Implements the logic to resolve the specific overload for a call expression.
 */
export class UnresolvedFunctionReference extends AbstractFunctionReference {
    /**
     * The function properties
     */
    properties: Partial<FunctionProperties>;

    /**
     * Creates a reference to a function reference that has the specified overloads
     * @param signatures the references of the function
     * @param context the context
     * @param classType the class type if the function is an instance or static method of an object
     * @param properties properties for the declared function
     * @return {UnresolvedFunctionReference} the function reference
     */
    static createRuntimeFunction(signatures: ts.Signature[],
                                 context: CodeGenerationContext,
                                 classType?: ts.ObjectType,
                                 properties?: Partial<FunctionProperties>) {
        properties = Object.assign({ linkage: llvm.LinkageTypes.ExternalLinkage, alwaysInline: true }, properties);
        const functionFactory = new FunctionFactory(new RuntimeSystemNameMangler(context.compilationContext), context.runtimeTypeConverter);
        return new UnresolvedFunctionReference(signatures, functionFactory, classType, properties);
    }

    /**
     * Creates a reference to a function that has the specified overloads
     * @param signatures the signatures of the function
     * @param context the context
     * @param classType the class type if the function is an instance or static method of an object
     * @return the function reference
     */
    static createFunction(signatures: ts.Signature[], context: CodeGenerationContext, classType?: ts.ObjectType) {
        return new UnresolvedFunctionReference(signatures, new SpeedyJSFunctionFactory(context), classType);
    }

    protected constructor(private signatures: ts.Signature[],
                          protected llvmFunctionFactory: FunctionFactory,
                          classType?: ts.ObjectType,
                          properties?: Partial<FunctionProperties>) {
        super(classType);
        assert(signatures.length, "Cannot reference a function without a signature");
        this.properties = properties || { linkage: llvm.LinkageTypes.LinkOnceODRLinkage };
    }

    protected getResolvedFunction(context: CodeGenerationContext) {
        if (this.signatures.length > 1) {
            throw new Error(`Cannot dereference an overloaded function`);
        }

        const signature = this.signatures[0];

        if (signature.typeParameters && signature.typeParameters.length) {
            throw new Error(`Cannot dereference a generic function`);
        }

        if (!signature.declaration.parameters.every(parameter => !parameter.questionToken)) {
            throw new Error(`Cannot deference a function with optional arguments`);
        }

        return this.getResolvedFunctionFromSignature(signature, context.compilationContext);
    }

    protected getLLVMFunction(resolvedFunction: ResolvedFunction, context: CodeGenerationContext, passedArguments?: llvm.Value[]): llvm.Function {
        const numberOfArguments = passedArguments ? passedArguments.length : resolvedFunction.parameters.length;

        return this.llvmFunctionFactory.getOrCreate(resolvedFunction, numberOfArguments, context, this.properties);
    }
}