Expression: formulas, inputs and errors
Separate Parse from Execute, validate result types and avoid stale error text.
Call sequence
- Parse reads the expression and input names. Continue only on Error.Ok.
- Execute receives values in the same order as inputNames. This is Expression syntax rather than C# execution.
- After Execute, check HasExecuteFailed and then the result type. Nil can be a valid result of the null expression.
Read GetErrorText after detecting an error. A successful Execute can retain text from a previous failure, so nonempty text alone does not identify a current failure. A new Parse clears that text and replaces the parsed expression.
Complete numeric adapter
NumericExpression.cs
using System;
using Reckfell;
public sealed class NumericExpression : IDisposable
{
private readonly Expression _expression = new();
private bool _parsed;
private int _inputCount;
public bool TryParse(string formula, string[] names, out string error)
{
_parsed = false;
error = "";
if (_expression.Parse(formula, names) != Error.Ok)
{
error = _expression.GetErrorText();
return false;
}
_inputCount = names.Length;
_parsed = true;
return true;
}
public bool TryEvaluate(double[] values, out double number, out string error)
{
number = 0;
error = "";
if (!_parsed || values.Length != _inputCount)
{
error = "Parse first and supply one value per input name.";
return false;
}
using var inputs = new Reckfell.Collections.Array();
foreach (double value in values)
{
if (!double.IsFinite(value))
{
error = "Inputs must be finite numbers.";
return false;
}
inputs.Add(value);
}
using Variant result = _expression.Execute(inputs, null, false, true);
if (_expression.HasExecuteFailed())
{
error = _expression.GetErrorText();
return false;
}
if (result.VariantType is not (Variant.Type.Int or Variant.Type.Float) ||
!double.IsFinite(result.AsDouble()))
{
error = "Expected a finite numeric result.";
return false;
}
number = result.AsDouble();
return true;
}
public void Dispose() => _expression.Dispose();
}For base_damage * multiplier, supply names base_damage, multiplier and values 20.0, 1.25: the result is 25. Reusing the parse with 2.0, 3.0 gives 6. The adapter refuses a wrong input count, NaN/Infinity, nonnumeric results and execution failures.
Limits
1 / 2 with integer literals produces integer 0. Use a floating operand when a fraction is required. Strings, arrays and other Variant values are not automatically accepted as numbers by this adapter.
showError=false disables ordinary execution-error printing; the error still needs handling. Do not Execute after a failed Parse. constCallsOnly restricts object method calls rather than isolating arbitrary untrusted code. The example uses a developer-supplied formula with changing numeric inputs.