mlld
Version:
mlld: a modular prompt scripting language
174 lines (172 loc) • 6.47 kB
JavaScript
import { logger } from './chunk-XGMRAGIT.mjs';
import { isExecutable } from './chunk-V5L6FBQT.mjs';
import { __name } from './chunk-OMKLS24H.mjs';
// interpreter/eval/foreach.ts
async function evaluateForeachCommand(foreachExpr, env) {
if (process.env.MLLD_DEBUG === "true") {
logger.debug("evaluateForeachCommand called with:", {
foreachExpr
});
}
const { execInvocation, arrays } = foreachExpr;
let commandName;
let commandArgs = [];
if (execInvocation.type === "ExecInvocation") {
commandName = execInvocation.commandRef.name;
commandArgs = execInvocation.commandRef.args || [];
} else if (execInvocation.identifier) {
commandName = execInvocation.identifier;
} else {
throw new Error("Invalid foreach command structure");
}
const cmdVariable = env.getVariable(commandName);
if (!cmdVariable) {
throw new Error(`Command not found: ${commandName}`);
}
if (!isExecutable(cmdVariable)) {
throw new Error(`Variable '${commandName}' cannot be used with foreach. Expected an @exec command or @text template with parameters, but got type: ${cmdVariable.type}`);
}
const { evaluateDataValue } = await import('./data-value-evaluator-UFIUOP64.mjs');
const evaluatedArrays = [];
const arrayNodes = arrays || commandArgs;
for (let i = 0; i < arrayNodes.length; i++) {
const arrayVar = arrayNodes[i];
const arrayValue = await evaluateDataValue(arrayVar, env);
if (!Array.isArray(arrayValue)) {
throw new Error(`Argument ${i + 1} to foreach must be an array, got ${typeof arrayValue}`);
}
evaluatedArrays.push(arrayValue);
}
validateArrayInputs(evaluatedArrays);
if (!isWithinPerformanceLimit(evaluatedArrays)) {
const totalCombinations = evaluatedArrays.reduce((total, arr) => total * arr.length, 1);
throw new Error(`Foreach operation would generate ${totalCombinations} combinations, which exceeds the performance limit. Consider reducing array sizes or using more specific filtering.`);
}
const definition = cmdVariable.value;
const paramCount = cmdVariable.paramNames?.length || definition.paramNames?.length || 0;
if (evaluatedArrays.length !== paramCount) {
const paramType = definition.sourceDirective === "text" ? "Text template" : "Command";
throw new Error(`${paramType} '${commandName}' expects ${paramCount} parameter${paramCount !== 1 ? "s" : ""}, but foreach is passing ${evaluatedArrays.length} array${evaluatedArrays.length !== 1 ? "s" : ""}`);
}
const tuples = cartesianProduct(evaluatedArrays);
const { evaluateExecInvocation } = await import('./exec-invocation-BKHC2VUW.mjs');
const results = [];
for (let i = 0; i < tuples.length; i++) {
const tuple = tuples[i];
try {
const execInvocationNode = {
type: "ExecInvocation",
commandRef: {
identifier: commandName,
args: tuple
// Use tuple values directly as arguments
},
withClause: null
};
const result = await evaluateExecInvocation(execInvocationNode, env);
results.push(result.value);
} catch (error) {
const params = cmdVariable.paramNames || definition.paramNames || [];
const iterationContext = params.map((param, index) => `${param}: ${JSON.stringify(tuple[index])}`).join(", ");
throw new Error(`Error in foreach iteration ${i + 1} (${iterationContext}): ${error instanceof Error ? error.message : String(error)}`);
}
}
return results;
}
__name(evaluateForeachCommand, "evaluateForeachCommand");
async function evaluateForeachSection(foreachExpr, env) {
return evaluateForeachCommand(foreachExpr, env);
}
__name(evaluateForeachSection, "evaluateForeachSection");
async function validateForeachExpression(foreachExpr, env) {
const errors = [];
try {
if (!foreachExpr || typeof foreachExpr !== "object") {
errors.push("Foreach expression must be an object");
return {
valid: false,
errors
};
}
const { execInvocation } = foreachExpr.value || foreachExpr;
if (!execInvocation) {
errors.push("Foreach expression missing exec invocation");
return {
valid: false,
errors
};
}
let commandName;
if (execInvocation.type === "ExecInvocation") {
commandName = execInvocation.commandRef.name;
} else if (execInvocation.identifier) {
commandName = execInvocation.identifier;
} else {
errors.push("Invalid foreach command structure");
return {
valid: false,
errors
};
}
const cmdVariable = env.getVariable(commandName);
if (!cmdVariable) {
errors.push(`Command not found: ${commandName}`);
} else if (!isExecutable(cmdVariable)) {
errors.push(`Variable '${commandName}' is not executable`);
}
return {
valid: errors.length === 0,
errors
};
} catch (error) {
errors.push(`Validation error: ${error instanceof Error ? error.message : String(error)}`);
return {
valid: false,
errors
};
}
}
__name(validateForeachExpression, "validateForeachExpression");
function validateArrayInputs(arrays) {
if (arrays.length === 0) {
throw new Error("Foreach requires at least one array argument");
}
for (let i = 0; i < arrays.length; i++) {
const arr = arrays[i];
if (!Array.isArray(arr)) {
throw new Error(`Argument ${i + 1} must be an array`);
}
if (arr.length === 0) {
throw new Error(`Array ${i + 1} cannot be empty`);
}
}
}
__name(validateArrayInputs, "validateArrayInputs");
function isWithinPerformanceLimit(arrays) {
const MAX_COMBINATIONS = 1e4;
const totalCombinations = arrays.reduce((total, arr) => total * arr.length, 1);
return totalCombinations <= MAX_COMBINATIONS;
}
__name(isWithinPerformanceLimit, "isWithinPerformanceLimit");
function cartesianProduct(arrays) {
if (arrays.length === 0) return [];
if (arrays.length === 1) return arrays[0].map((item) => [
item
]);
const result = [];
const [head, ...tail] = arrays;
const tailProduct = cartesianProduct(tail);
for (const headItem of head) {
for (const tailItem of tailProduct) {
result.push([
headItem,
...tailItem
]);
}
}
return result;
}
__name(cartesianProduct, "cartesianProduct");
export { evaluateForeachCommand, evaluateForeachSection, validateForeachExpression };
//# sourceMappingURL=chunk-ODBVL5OR.mjs.map
//# sourceMappingURL=chunk-ODBVL5OR.mjs.map