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