import { type NodeInput, type NodeExpr, type NodeIdentifier, type BuiltInFunctionTable, ComplexDecimal, Scope, CallFrame } from 'mathjslab'; import { appEngine } from './appEngine'; /** * External numerical functions shared by MathJSLab web applications. */ const commonExternalFunctionTable: BuiltInFunctionTable = { summation: { type: 'BUILTIN', id: 'summation', mapper: false, ev: [false, true, true, false], func: (variable: NodeIdentifier, start: ComplexDecimal, end: ComplexDecimal, expr: NodeExpr): ComplexDecimal => { if (!start.im.eq(0)) throw new Error('complex number sum index'); if (!end.im.eq(0)) throw new Error('complex number sum index'); let result: ComplexDecimal = ComplexDecimal.zero(); /* Create a local scope for the summation variable. */ const sumScope = Scope.create(appEngine.interpreter.context.currentScope); /* Push the summation scope while evaluating the expression. */ appEngine.interpreter.context.callStack!.push(new CallFrame(sumScope)); for (let i = start.re.toNumber(); i <= end.re.toNumber(); i++) { const value = ComplexDecimal.create(i, 0); sumScope.defineName(variable.id, value); const evalResult = appEngine.interpreter.Evaluator(expr, sumScope) as ComplexDecimal; result = ComplexDecimal.add(result, evalResult); } /* Restore the call stack after evaluating the summation. */ appEngine.interpreter.context.callStack!.pop(); return result; }, UnparserMathML: (tree: NodeInput): string => { return ( '' + appEngine.interpreter.UnparserMathML(tree.args[0]) + '=' + appEngine.interpreter.UnparserMathML(tree.args[1]) + '' + appEngine.interpreter.UnparserMathML(tree.args[2]) + '' + '' + appEngine.interpreter.UnparserMathML(tree.args[3]) + '' ); }, }, productory: { type: 'BUILTIN', id: 'productory', mapper: false, ev: [false, true, true, false], func: (variable: NodeIdentifier, start: ComplexDecimal, end: ComplexDecimal, expr: NodeExpr): ComplexDecimal => { if (!start.im.eq(0)) throw new Error('complex number prod index'); if (!end.im.eq(0)) throw new Error('complex number prod index'); let result: ComplexDecimal = ComplexDecimal.one(); const context = appEngine.interpreter.context; /* Create a local scope for the product variable. */ const localScope = Scope.create(context.currentScope); /* Push the product scope while evaluating the expression. */ context.callStack!.push(new CallFrame(localScope)); try { for (let i = start.re.toNumber(); i <= end.re.toNumber(); i++) { /* Assign the iteration value inside the local scope. */ localScope.defineName(variable.id, ComplexDecimal.create(i, 0)); /* Evaluate the expression with the product scope active. */ const value = appEngine.interpreter.Evaluator(expr) as ComplexDecimal; result = ComplexDecimal.mul(result, value); } } finally { /* Always restore the call stack, including error paths. */ context.callStack!.pop(); } return result; }, UnparserMathML: (tree: NodeInput): string => { return ( '' + appEngine.interpreter.UnparserMathML(tree.args[0]) + '=' + appEngine.interpreter.UnparserMathML(tree.args[1]) + '' + appEngine.interpreter.UnparserMathML(tree.args[2]) + '' + '' + appEngine.interpreter.UnparserMathML(tree.args[3]) + '' ); }, }, }; export { commonExternalFunctionTable }; export default { commonExternalFunctionTable };