XMLDoc
This commit is contained in:
parent
4452679310
commit
4d6a0c6bab
1 changed files with 98 additions and 11 deletions
|
|
@ -4,32 +4,47 @@ using System.IO;
|
||||||
|
|
||||||
namespace CSMic
|
namespace CSMic
|
||||||
{
|
{
|
||||||
|
/// <summary> The interpreter that parses user input at runtime into strongly typed .Net values. </summary>
|
||||||
public class InputInterpreter
|
public class InputInterpreter
|
||||||
{
|
{
|
||||||
#region Members
|
#region Members
|
||||||
|
|
||||||
|
/// <summary> The numeric value store. </summary>
|
||||||
private decimal numericValue = 0;
|
private decimal numericValue = 0;
|
||||||
|
/// <summary> The string value store. </summary>
|
||||||
private string stringValue = string.Empty;
|
private string stringValue = string.Empty;
|
||||||
|
/// <summary> The time taken for the last entry the parser interpreted. </summary>
|
||||||
private TimeSpan lastExecutionTime = TimeSpan.Zero;
|
private TimeSpan lastExecutionTime = TimeSpan.Zero;
|
||||||
|
|
||||||
// Variable stores
|
#region Variable stores
|
||||||
|
/// <summary> (Immutable) The numeric variables. </summary>
|
||||||
private readonly Dictionary<string, decimal> numericVariables;
|
private readonly Dictionary<string, decimal> numericVariables;
|
||||||
|
/// <summary> (Immutable) The numeric array variables. </summary>
|
||||||
private readonly Dictionary<string, decimal[]> numericArrayVariables;
|
private readonly Dictionary<string, decimal[]> numericArrayVariables;
|
||||||
private readonly Dictionary<string, string> expressionVariables;
|
/// <summary> (Immutable) The expression variables. </summary>
|
||||||
|
private readonly Dictionary<string, string> expressionVariables;
|
||||||
|
#endregion
|
||||||
|
|
||||||
// Function registry
|
/// <summary> (Immutable) The function registry. </summary>
|
||||||
private readonly Dictionary<string, ICodedFunction> functions;
|
private readonly Dictionary<string, ICodedFunction> functions;
|
||||||
|
|
||||||
// Tracks expression variables currently being evaluated to prevent recursion
|
/// <summary>
|
||||||
|
/// (Immutable) Tracks expression variables currently being evaluated to prevent recursion.
|
||||||
|
/// </summary>
|
||||||
private readonly List<string> evaluationStack;
|
private readonly List<string> evaluationStack;
|
||||||
// Shared recursion tracker across nested evaluations
|
/// <summary> Shared recursion tracker used across nested evaluations. </summary>
|
||||||
private sealed class RecursionTracker { public int Hits; }
|
private sealed class RecursionTracker {
|
||||||
|
/// <summary> The number of recursive trips detected. </summary>
|
||||||
|
public int Hits;
|
||||||
|
}
|
||||||
|
/// <summary> (Immutable) The recursion tracker. </summary>
|
||||||
private readonly RecursionTracker recursion;
|
private readonly RecursionTracker recursion;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary> Default constructor. </summary>
|
||||||
public InputInterpreter()
|
public InputInterpreter()
|
||||||
{
|
{
|
||||||
numericVariables = new Dictionary<string, decimal>(StringComparer.Ordinal);
|
numericVariables = new Dictionary<string, decimal>(StringComparer.Ordinal);
|
||||||
|
|
@ -40,7 +55,8 @@ namespace CSMic
|
||||||
recursion = new RecursionTracker();
|
recursion = new RecursionTracker();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal constructor to create a child interpreter that shares stores
|
/// <summary> Internal constructor to create a child interpreter that shares stores. </summary>
|
||||||
|
/// <param name="parent"> The parent <see cref="InputInterpreter"/>. </param>
|
||||||
internal InputInterpreter(InputInterpreter parent)
|
internal InputInterpreter(InputInterpreter parent)
|
||||||
{
|
{
|
||||||
this.numericVariables = parent.numericVariables;
|
this.numericVariables = parent.numericVariables;
|
||||||
|
|
@ -57,6 +73,8 @@ namespace CSMic
|
||||||
|
|
||||||
#region Properties
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary> Gets the numeric value. </summary>
|
||||||
|
/// <value> The numeric value. </value>
|
||||||
public decimal NumericValue
|
public decimal NumericValue
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
@ -65,6 +83,8 @@ namespace CSMic
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets the string value. </summary>
|
||||||
|
/// <value> The string value. </value>
|
||||||
public string StringValue
|
public string StringValue
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
@ -73,6 +93,8 @@ namespace CSMic
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets the last execution time. </summary>
|
||||||
|
/// <value> The last execution time. </value>
|
||||||
public TimeSpan LastExecutionTime
|
public TimeSpan LastExecutionTime
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
@ -81,6 +103,8 @@ namespace CSMic
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets the variables. </summary>
|
||||||
|
/// <value> The encapsulated variables. </value>
|
||||||
public IEnumerable<Variable> Variables
|
public IEnumerable<Variable> Variables
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
@ -95,12 +119,17 @@ namespace CSMic
|
||||||
|
|
||||||
#region Output Plumbing
|
#region Output Plumbing
|
||||||
|
|
||||||
|
/// <summary> Hydrates long-lived output variables for delayed access. </summary>
|
||||||
|
/// <param name="numericValue"> The numeric value store. </param>
|
||||||
|
/// <param name="stringValue"> The string value store. </param>
|
||||||
internal void ProduceOutput(decimal numericValue, string stringValue)
|
internal void ProduceOutput(decimal numericValue, string stringValue)
|
||||||
{
|
{
|
||||||
this.numericValue = numericValue;
|
this.numericValue = numericValue;
|
||||||
this.stringValue = stringValue;
|
this.stringValue = stringValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Hydrates long-lived output variables for delayed access. </summary>
|
||||||
|
/// <param name="functionValue"> The function value to be converted. </param>
|
||||||
internal void ProduceOutput(FunctionValue functionValue)
|
internal void ProduceOutput(FunctionValue functionValue)
|
||||||
{
|
{
|
||||||
switch (functionValue.Type)
|
switch (functionValue.Type)
|
||||||
|
|
@ -126,12 +155,24 @@ namespace CSMic
|
||||||
|
|
||||||
#region Variable APIs
|
#region Variable APIs
|
||||||
|
|
||||||
|
/// <summary> Attempts to get a numeric value from the variable store with a given name. </summary>
|
||||||
|
/// <param name="name"> The name. </param>
|
||||||
|
/// <param name="value"> [out] The value. </param>
|
||||||
|
/// <returns> True if it succeeds, false if it fails. </returns>
|
||||||
internal bool TryGetNumeric(string name, out decimal value)
|
internal bool TryGetNumeric(string name, out decimal value)
|
||||||
=> numericVariables.TryGetValue(name, out value);
|
=> numericVariables.TryGetValue(name, out value);
|
||||||
|
|
||||||
|
/// <summary> Attempts to get a numeric array from the variable store with a given name. </summary>
|
||||||
|
/// <param name="name"> The name. </param>
|
||||||
|
/// <param name="values"> [out] The values. </param>
|
||||||
|
/// <returns> True if it succeeds, false if it fails. </returns>
|
||||||
internal bool TryGetNumericArray(string name, out decimal[] values)
|
internal bool TryGetNumericArray(string name, out decimal[] values)
|
||||||
=> numericArrayVariables.TryGetValue(name, out values!);
|
=> numericArrayVariables.TryGetValue(name, out values!);
|
||||||
|
|
||||||
|
/// <summary> Attempts to get an expression from the variable store with a given name. </summary>
|
||||||
|
/// <param name="name"> The name. </param>
|
||||||
|
/// <param name="expr"> [out] The expression. </param>
|
||||||
|
/// <returns> True if it succeeds, false if it fails. </returns>
|
||||||
internal bool TryGetExpression(string name, out string expr)
|
internal bool TryGetExpression(string name, out string expr)
|
||||||
{
|
{
|
||||||
if (expressionVariables.TryGetValue(name, out expr!))
|
if (expressionVariables.TryGetValue(name, out expr!))
|
||||||
|
|
@ -142,9 +183,16 @@ namespace CSMic
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recursion tracking helpers managed by the parser when evaluating expression variables
|
/// <summary>
|
||||||
|
/// Recursion tracking helpers managed by the parser when evaluating expression variables.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name"> The name of the variable to check. </param>
|
||||||
|
/// <returns> True if currently evaluating, false if not. </returns>
|
||||||
internal bool IsEvaluating(string name) => evaluationStack.Contains(name);
|
internal bool IsEvaluating(string name) => evaluationStack.Contains(name);
|
||||||
|
|
||||||
|
/// <summary> Begins evaluating a named expression. </summary>
|
||||||
|
/// <param name="name"> The name of the expression variable. </param>
|
||||||
|
/// <returns> The current recurrsion depth. </returns>
|
||||||
internal int BeginEvaluating(string name)
|
internal int BeginEvaluating(string name)
|
||||||
{
|
{
|
||||||
int depth = evaluationStack.Count;
|
int depth = evaluationStack.Count;
|
||||||
|
|
@ -152,6 +200,8 @@ namespace CSMic
|
||||||
return depth;
|
return depth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Ends evaluating a named expression. </summary>
|
||||||
|
/// <param name="depth"> The recurrsion depth. </param>
|
||||||
internal void EndEvaluating(int depth)
|
internal void EndEvaluating(int depth)
|
||||||
{
|
{
|
||||||
while (evaluationStack.Count > depth)
|
while (evaluationStack.Count > depth)
|
||||||
|
|
@ -160,46 +210,67 @@ namespace CSMic
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recursion hit scoping across a single top-level expression evaluation
|
/// <summary> Recursion hit scoping across a single top-level expression evaluation. </summary>
|
||||||
|
/// <returns> An int. </returns>
|
||||||
internal int BeginRecursionScope()
|
internal int BeginRecursionScope()
|
||||||
{
|
{
|
||||||
return recursion.Hits;
|
return recursion.Hits;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if recursion occurred within this scope
|
/// <summary> Returns true if recursion occurred within this scope. </summary>
|
||||||
|
/// <param name="startHits"> The initial recurrsive hit counter. </param>
|
||||||
|
/// <returns> True if recurrsion occurred within this scope, false otherwise. </returns>
|
||||||
internal bool EndRecursionScope(int startHits)
|
internal bool EndRecursionScope(int startHits)
|
||||||
{
|
{
|
||||||
return recursion.Hits > startHits;
|
return recursion.Hits > startHits;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Mark a recursion hit. </summary>
|
||||||
internal void MarkRecursionHit()
|
internal void MarkRecursionHit()
|
||||||
{
|
{
|
||||||
recursion.Hits++;
|
recursion.Hits++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Assign a numeric value to a variable. </summary>
|
||||||
|
/// <param name="name"> The name of the variable. </param>
|
||||||
|
/// <param name="value"> [out] The value. </param>
|
||||||
internal void AssignNumeric(string name, decimal value)
|
internal void AssignNumeric(string name, decimal value)
|
||||||
{
|
{
|
||||||
numericVariables[name] = value;
|
numericVariables[name] = value;
|
||||||
// Remove conflicting bindings
|
// Remove conflicting bindings
|
||||||
expressionVariables.Remove(name);
|
expressionVariables.Remove(name);
|
||||||
|
numericArrayVariables.Remove(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Assign a numeric array set to a variable. </summary>
|
||||||
|
/// <param name="name"> The name of the variable. </param>
|
||||||
|
/// <param name="values"> [out] The array values. </param>
|
||||||
internal void AssignNumericArray(string name, decimal[] values)
|
internal void AssignNumericArray(string name, decimal[] values)
|
||||||
{
|
{
|
||||||
numericArrayVariables[name] = values;
|
numericArrayVariables[name] = values;
|
||||||
|
// Remove conflicting bindings
|
||||||
|
numericVariables.Remove(name);
|
||||||
|
expressionVariables.Remove(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Assign an expression to a variable. </summary>
|
||||||
|
/// <param name="name"> The name of the variable. </param>
|
||||||
|
/// <param name="expressionText"> The expression text. </param>
|
||||||
internal void AssignExpression(string name, string expressionText)
|
internal void AssignExpression(string name, string expressionText)
|
||||||
{
|
{
|
||||||
expressionVariables[name] = expressionText;
|
expressionVariables[name] = expressionText;
|
||||||
// Remove conflicting numeric value
|
// Remove conflicting numeric value
|
||||||
numericVariables.Remove(name);
|
numericVariables.Remove(name);
|
||||||
|
numericArrayVariables.Remove(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Expression Evaluation
|
#region Expression Evaluation
|
||||||
|
|
||||||
|
/// <summary> Evaluates an expression. </summary>
|
||||||
|
/// <param name="expressionText"> The expression text. </param>
|
||||||
|
/// <returns> The result of the expression. </returns>
|
||||||
internal FunctionValue EvaluateExpression(string expressionText)
|
internal FunctionValue EvaluateExpression(string expressionText)
|
||||||
{
|
{
|
||||||
// Create a child interpreter sharing stores, so ProduceOutput doesn't affect parent state
|
// Create a child interpreter sharing stores, so ProduceOutput doesn't affect parent state
|
||||||
|
|
@ -221,7 +292,10 @@ namespace CSMic
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Primary developer-facing API: interpret input and return numeric result
|
/// <summary> Interpret input and return a numeric result. </summary>
|
||||||
|
/// <param name="input"> The input text to parse. </param>
|
||||||
|
/// <returns> A decimal value representing the immediate result. </returns>
|
||||||
|
/// <remarks> This is the primary developer-facing API. </remarks>
|
||||||
public decimal Interpret(string input)
|
public decimal Interpret(string input)
|
||||||
{
|
{
|
||||||
DateTime start = DateTime.Now;
|
DateTime start = DateTime.Now;
|
||||||
|
|
@ -263,11 +337,24 @@ namespace CSMic
|
||||||
|
|
||||||
#region Functions
|
#region Functions
|
||||||
|
|
||||||
|
/// <summary> Registers a function described by <see cref="ICodedFunction"/> interface. </summary>
|
||||||
|
/// <param name="function"> The function. </param>
|
||||||
|
/// <seealso cref="FunctionArgument"/>
|
||||||
|
/// <seealso cref="FunctionValueType"/>
|
||||||
|
/// <seealso cref="FunctionValue"/>
|
||||||
public void RegisterFunction(ICodedFunction function)
|
public void RegisterFunction(ICodedFunction function)
|
||||||
{
|
{
|
||||||
functions[function.Name] = function;
|
functions[function.Name] = function;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Executes a named function. </summary>
|
||||||
|
/// <param name="name"> The name. </param>
|
||||||
|
/// <param name="args"> A variable-length parameters list containing arguments. </param>
|
||||||
|
/// <returns> The result of the function execution. </returns>
|
||||||
|
/// <seealso cref="FunctionArgument"/>
|
||||||
|
/// <seealso cref="FunctionValueType"/>
|
||||||
|
/// <seealso cref="FunctionValue"/>
|
||||||
|
/// <seealso cref="ICodedFunction"/>
|
||||||
internal FunctionValue ExecuteFunction(string name, params FunctionArgument[] args)
|
internal FunctionValue ExecuteFunction(string name, params FunctionArgument[] args)
|
||||||
{
|
{
|
||||||
if (functions.TryGetValue(name, out var fn))
|
if (functions.TryGetValue(name, out var fn))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue