using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using Unity.VisualScripting.Antlr3.Runtime;
using UnityEngine;
namespace Unity.VisualScripting.Dependencies.NCalc
{
public class Expression
{
private Expression()
{
// Fix: the original grammar doesn't include a null identifier.
Parameters["null"] = Parameters["NULL"] = null;
}
public Expression(string expression, EvaluateOptions options = EvaluateOptions.None) : this()
{
if (string.IsNullOrEmpty(expression))
{
throw new ArgumentException("Expression can't be empty", nameof(expression));
}
// Fix: The original grammar doesn't allow double quotes for strings.
expression = expression.Replace('\"', '\'');
OriginalExpression = expression;
Options = options;
}
public Expression(LogicalExpression expression, EvaluateOptions options = EvaluateOptions.None) : this()
{
if (expression == null)
{
throw new ArgumentException("Expression can't be null", nameof(expression));
}
ParsedExpression = expression;
Options = options;
}
public event EvaluateFunctionHandler EvaluateFunction;
public event EvaluateParameterHandler EvaluateParameter;
///
/// Textual representation of the expression to evaluate.
///
protected readonly string OriginalExpression;
protected Dictionary ParameterEnumerators;
private Dictionary _parameters;
public EvaluateOptions Options { get; set; }
public string Error { get; private set; }
public LogicalExpression ParsedExpression { get; private set; }
public Dictionary Parameters
{
get
{
return _parameters ?? (_parameters = new Dictionary());
}
set
{
_parameters = value;
}
}
public void UpdateUnityTimeParameters()
{
Parameters["dt"] = Parameters["DT"] = Time.deltaTime;
Parameters["second"] = Parameters["Second"] = 1 / Time.deltaTime;
}
///
/// Pre-compiles the expression in order to check syntax errors.
/// If errors are detected, the Error property contains the message.
///
/// True if the expression syntax is correct, otherwise false
public bool HasErrors()
{
try
{
if (ParsedExpression == null)
{
ParsedExpression = Compile(OriginalExpression, (Options & EvaluateOptions.NoCache) == EvaluateOptions.NoCache);
}
// In case HasErrors() is called multiple times for the same expression
return ParsedExpression != null && Error != null;
}
catch (Exception e)
{
Error = e.Message;
return true;
}
}
public object Evaluate(Flow flow)
{
if (HasErrors())
{
throw new EvaluationException(Error);
}
if (ParsedExpression == null)
{
ParsedExpression = Compile(OriginalExpression, (Options & EvaluateOptions.NoCache) == EvaluateOptions.NoCache);
}
var visitor = new EvaluationVisitor(flow, Options);
visitor.EvaluateFunction += EvaluateFunction;
visitor.EvaluateParameter += EvaluateParameter;
visitor.Parameters = Parameters;
// If array evaluation, execute the same expression multiple times
if ((Options & EvaluateOptions.IterateParameters) == EvaluateOptions.IterateParameters)
{
var size = -1;
ParameterEnumerators = new Dictionary();
foreach (var parameter in Parameters.Values)
{
if (parameter is IEnumerable enumerable)
{
var localsize = 0;
foreach (var o in enumerable)
{
localsize++;
}
if (size == -1)
{
size = localsize;
}
else if (localsize != size)
{
throw new EvaluationException("When IterateParameters option is used, IEnumerable parameters must have the same number of items.");
}
}
}
foreach (var key in Parameters.Keys)
{
var parameter = Parameters[key] as IEnumerable;
if (parameter != null)
{
ParameterEnumerators.Add(key, parameter.GetEnumerator());
}
}
var results = new List