/*
* This file is part of TREB.
*
* TREB is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* TREB is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along
* with TREB. If not, see .
*
* Copyright 2022-2026 trebco, llc.
* info@treb.app
*
*/
import type { FunctionMap } from '../descriptors';
import type { UnionValue} from 'treb-base-types';
import { ValueType } from 'treb-base-types';
import type { ExpressionUnit } from 'treb-parser';
export const LambdaFunctionLibrary: FunctionMap = {
Lambda: {
// FIXME: we could use the create_binding_context callback
// here to validate the original parameters, might be useful
description: 'Creates a function',
arguments: [
{ name: 'Argument', repeat: true, boxed: true, passthrough: true },
{ name: 'Function', boxed: true, passthrough: true },
],
// pass through render/click functions
pass_through_ui: 'indirect',
fn: (...args: ExpressionUnit[]) => {
return {
type: ValueType.function,
// FIXME: lock down this type
value: {
// we should probably clone these
bindings: args.slice(0, args.length - 1),
func: args[args.length - 1],
alt: 'LAMBDA', // metadata
type: 'function', // metadata
},
};
}
},
Let: {
// this function has weird semantics we don't normally see --
// the first two arguments repeat, and the last one is constant.
// our tooltips aren't prepared for this.
// also it creates temporary names, we'll need to create some sort
// of temporary binding context. complicated!
description: 'Binds values to names for a calculation',
arguments: [
{ name: 'Name', repeat: true },
{ name: 'Value', repeat: true },
{ name: 'Calculation', boxed: true },
],
create_binding_context: ({args, descriptors}) => {
if (args.length % 2 !== 1) {
return undefined; // error
}
const context: Record = {};
for (let i = 0; i < args.length - 1; i += 2) {
const name = args[i];
const value = args[i+1];
if (name.type === 'identifier') {
context[name.name] = value;
}
else {
return undefined; // error
}
}
return {
context,
args: args.slice(-1),
argument_descriptors: descriptors.slice(-1),
}
},
fn: (arg?: UnionValue) => {
return arg ? arg : { type: ValueType.undefined };
},
},
};