time-to-botec

Benchmark sampling in different programming languages
Log | Files | Refs | README

lambda.js (4351B)


      1 import * as IError from "../errors/IError.js";
      2 import { REArityError, REDomainError, REOther } from "../errors/messages.js";
      3 import * as Context from "./context.js";
      4 import { fnDefinitionToString, tryCallFnDefinition, } from "../library/registry/fnDefinition.js";
      5 import uniq from "lodash/uniq.js";
      6 import { sort } from "../utility/E_A_Floats.js";
      7 export class BaseLambda {
      8     constructor(body) {
      9         this.body = body;
     10     }
     11     callFrom(args, context, ast) {
     12         const newContext = {
     13             stack: context.stack,
     14             environment: context.environment,
     15             frameStack: context.frameStack.extend(Context.currentFunctionName(context), ast?.location),
     16             evaluate: context.evaluate,
     17             inFunction: this,
     18         };
     19         try {
     20             return this.body(args, newContext);
     21         }
     22         catch (e) {
     23             IError.rethrowWithFrameStack(e, newContext.frameStack);
     24         }
     25     }
     26     call(args, context) {
     27         return this.callFrom(args, context, undefined);
     28     }
     29 }
     30 export class UserDefinedLambda extends BaseLambda {
     31     constructor(name, parameters, stack, body, location) {
     32         const lambda = (args, context) => {
     33             const argsLength = args.length;
     34             const parametersLength = parameters.length;
     35             if (argsLength !== parametersLength) {
     36                 throw new REArityError(undefined, parametersLength, argsLength);
     37             }
     38             let localStack = stack;
     39             for (let i = 0; i < parametersLength; i++) {
     40                 const parameter = parameters[i];
     41                 localStack = localStack.push(parameter.name, args[i]);
     42                 if (parameter.domain && !parameter.domain.value.includes(args[i])) {
     43                     throw new REDomainError(args[i], parameter.domain);
     44                 }
     45             }
     46             const lambdaContext = {
     47                 stack: localStack,
     48                 environment: context.environment,
     49                 frameStack: context.frameStack,
     50                 evaluate: context.evaluate,
     51                 inFunction: context.inFunction,
     52             };
     53             const [value] = context.evaluate(body, lambdaContext);
     54             return value;
     55         };
     56         super(lambda);
     57         this.type = "UserDefinedLambda";
     58         this.name = name;
     59         this.parameters = parameters;
     60         this.location = location;
     61     }
     62     getName() {
     63         return this.name || "<anonymous>";
     64     }
     65     _getParameterNames() {
     66         return this.parameters.map((parameter) => parameter.name);
     67     }
     68     parameterString() {
     69         return this._getParameterNames().join(",");
     70     }
     71     toString() {
     72         return `lambda(${this._getParameterNames().join(",")}=>internal code)`;
     73     }
     74     parameterCounts() {
     75         return [this.parameters.length];
     76     }
     77     parameterCountString() {
     78         return this.parameters.length.toString();
     79     }
     80 }
     81 export class BuiltinLambda extends BaseLambda {
     82     constructor(name, signatures) {
     83         super((args, context) => this._call(args, context));
     84         this.name = name;
     85         this.type = "BuiltinLambda";
     86         this._definitions = signatures;
     87     }
     88     getName() {
     89         return this.name;
     90     }
     91     toString() {
     92         return this.name;
     93     }
     94     parameterString() {
     95         return this._definitions.map(fnDefinitionToString).join(" | ");
     96     }
     97     parameterCounts() {
     98         return sort(uniq(this._definitions.map((d) => d.inputs.length)));
     99     }
    100     parameterCountString() {
    101         return `[${this.parameterCounts().join(",")}]`;
    102     }
    103     signatures() {
    104         return this._definitions.map((d) => d.inputs);
    105     }
    106     _call(args, context) {
    107         const signatures = this._definitions;
    108         const showNameMatchDefinitions = () => {
    109             const defsString = signatures
    110                 .map(fnDefinitionToString)
    111                 .map((def) => `  ${this.name}${def}\n`)
    112                 .join("");
    113             return `There are function matches for ${this.name}(), but with different arguments:\n${defsString}`;
    114         };
    115         for (const signature of signatures) {
    116             const callResult = tryCallFnDefinition(signature, args, context);
    117             if (callResult !== undefined) {
    118                 return callResult;
    119             }
    120         }
    121         throw new REOther(showNameMatchDefinitions());
    122     }
    123 }
    124 //# sourceMappingURL=lambda.js.map