This commit is contained in:
2025-10-08 09:49:37 +08:00
commit 284e764345
99 changed files with 21742 additions and 0 deletions

View File

@@ -0,0 +1,350 @@
using Flee.CalcEngine.PublicTypes;
namespace Flee.CalcEngine.InternalTypes
{
/// <summary>
/// Keeps track of our dependencies
/// </summary>
/// <typeparam name="T"></typeparam>
internal class DependencyManager<T>
{
/// <summary>
/// Map of a node and the nodes that depend on it
/// </summary>
private readonly Dictionary<T, Dictionary<T, object>> _myDependentsMap;
private readonly IEqualityComparer<T> _myEqualityComparer;
/// <summary>
/// Map of a node and the number of nodes that point to it
/// </summary>
private readonly Dictionary<T, int> _myPrecedentsMap;
public DependencyManager(IEqualityComparer<T> comparer)
{
_myEqualityComparer = comparer;
_myDependentsMap = new Dictionary<T, Dictionary<T, object>>(_myEqualityComparer);
_myPrecedentsMap = new Dictionary<T, int>(_myEqualityComparer);
}
private IDictionary<T, object> CreateInnerDictionary()
{
return new Dictionary<T, object>(_myEqualityComparer);
}
private IDictionary<T, object> GetInnerDictionary(T tail)
{
Dictionary<T, object> value = null;
if (_myDependentsMap.TryGetValue(tail, out value) == true)
{
return value;
}
else
{
return null;
}
}
// Create a dependency list with only the dependents of the given tails
public DependencyManager<T> CloneDependents(T[] tails)
{
IDictionary<T, object> seenNodes = this.CreateInnerDictionary();
DependencyManager<T> copy = new DependencyManager<T>(_myEqualityComparer);
foreach (T tail in tails)
{
this.CloneDependentsInternal(tail, copy, seenNodes);
}
return copy;
}
private void CloneDependentsInternal(T tail, DependencyManager<T> target, IDictionary<T, object> seenNodes)
{
if (seenNodes.ContainsKey(tail) == true)
{
// We've already added this node so just return
return;
}
else
{
// Haven't seen this node yet; mark it as visited
seenNodes.Add(tail, null);
target.AddTail(tail);
}
IDictionary<T, object> innerDict = this.GetInnerDictionary(tail);
// Do the recursive add
foreach (T head in innerDict.Keys)
{
target.AddDepedency(tail, head);
this.CloneDependentsInternal(head, target, seenNodes);
}
}
public T[] GetTails()
{
T[] arr = new T[_myDependentsMap.Keys.Count];
_myDependentsMap.Keys.CopyTo(arr, 0);
return arr;
}
public void Clear()
{
_myDependentsMap.Clear();
_myPrecedentsMap.Clear();
}
public void ReplaceDependency(T old, T replaceWith)
{
Dictionary<T, object> value = _myDependentsMap[old];
_myDependentsMap.Remove(old);
_myDependentsMap.Add(replaceWith, value);
foreach (Dictionary<T, object> innerDict in _myDependentsMap.Values)
{
if (innerDict.ContainsKey(old) == true)
{
innerDict.Remove(old);
innerDict.Add(replaceWith, null);
}
}
}
public void AddTail(T tail)
{
if (_myDependentsMap.ContainsKey(tail) == false)
{
_myDependentsMap.Add(tail, (Dictionary<T, object>)this.CreateInnerDictionary());
}
}
public void AddDepedency(T tail, T head)
{
IDictionary<T, object> innerDict = this.GetInnerDictionary(tail);
if (innerDict.ContainsKey(head) == false)
{
innerDict.Add(head, head);
this.AddPrecedent(head);
}
}
public void RemoveDependency(T tail, T head)
{
IDictionary<T, object> innerDict = this.GetInnerDictionary(tail);
this.RemoveHead(head, innerDict);
}
private void RemoveHead(T head, IDictionary<T, object> dict)
{
if (dict.Remove(head) == true)
{
this.RemovePrecedent(head);
}
}
public void Remove(T[] tails)
{
foreach (Dictionary<T, object> innerDict in _myDependentsMap.Values)
{
foreach (T tail in tails)
{
this.RemoveHead(tail, innerDict);
}
}
foreach (T tail in tails)
{
_myDependentsMap.Remove(tail);
}
}
public void GetDirectDependents(T tail, List<T> dest)
{
Dictionary<T, object> innerDict = (Dictionary<T, object>)this.GetInnerDictionary(tail);
dest.AddRange(innerDict.Keys);
}
public T[] GetDependents(T tail)
{
Dictionary<T, object> dependents = (Dictionary<T, object>)this.CreateInnerDictionary();
this.GetDependentsRecursive(tail, dependents);
T[] arr = new T[dependents.Count];
dependents.Keys.CopyTo(arr, 0);
return arr;
}
private void GetDependentsRecursive(T tail, Dictionary<T, object> dependents)
{
dependents[tail] = null;
Dictionary<T, object> directDependents = (Dictionary<T, object>)this.GetInnerDictionary(tail);
foreach (T pair in directDependents.Keys)
{
this.GetDependentsRecursive(pair, dependents);
}
}
public void GetDirectPrecedents(T head, IList<T> dest)
{
foreach (T tail in _myDependentsMap.Keys)
{
Dictionary<T, object> innerDict = (Dictionary<T, object>)this.GetInnerDictionary(tail);
if (innerDict.ContainsKey(head) == true)
{
dest.Add(tail);
}
}
}
private void AddPrecedent(T head)
{
int count = 0;
_myPrecedentsMap.TryGetValue(head, out count);
_myPrecedentsMap[head] = count + 1;
}
private void RemovePrecedent(T head)
{
int count = _myPrecedentsMap[head] - 1;
if (count == 0)
{
_myPrecedentsMap.Remove(head);
}
else
{
_myPrecedentsMap[head] = count;
}
}
public bool HasPrecedents(T head)
{
return _myPrecedentsMap.ContainsKey(head);
}
public bool HasDependents(T tail)
{
Dictionary<T, object> innerDict = (Dictionary<T, object>)this.GetInnerDictionary(tail);
return innerDict.Count > 0;
}
private string FormatValues(ICollection<T> values)
{
string[] strings = new string[values.Count];
T[] keys = new T[values.Count];
values.CopyTo(keys, 0);
for (int i = 0; i <= keys.Length - 1; i++)
{
strings[i] = keys[i].ToString();
}
if (strings.Length == 0)
{
return "<empty>";
}
else
{
return string.Join(",", strings);
}
}
/// <summary>
/// Add all nodes that don't have any incoming edges into a queue
/// </summary>
/// <param name="rootTails"></param>
/// <returns></returns>
public Queue<T> GetSources(T[] rootTails)
{
Queue<T> q = new Queue<T>();
foreach (T rootTail in rootTails)
{
if (this.HasPrecedents(rootTail) == false)
{
q.Enqueue(rootTail);
}
}
return q;
}
public IList<T> TopologicalSort(Queue<T> sources)
{
IList<T> output = new List<T>();
List<T> directDependents = new List<T>();
while (sources.Count > 0)
{
T n = sources.Dequeue();
output.Add(n);
directDependents.Clear();
this.GetDirectDependents(n, directDependents);
foreach (T m in directDependents)
{
this.RemoveDependency(n, m);
if (this.HasPrecedents(m) == false)
{
sources.Enqueue(m);
}
}
}
if (output.Count != this.Count)
{
throw new CircularReferenceException();
}
return output;
}
#if DEBUG
public string Precedents
{
get
{
List<string> list = new List<string>();
foreach (KeyValuePair<T, int> pair in _myPrecedentsMap)
{
list.Add(pair.ToString());
}
return string.Join(System.Environment.NewLine, list.ToArray());
}
}
#endif
public string DependencyGraph
{
get
{
string[] lines = new string[_myDependentsMap.Count];
int index = 0;
foreach (KeyValuePair<T, Dictionary<T, object>> pair in _myDependentsMap)
{
T key = pair.Key;
string s = this.FormatValues(pair.Value.Keys);
lines[index] = $"{key} -> {s}";
index += 1;
}
return string.Join(System.Environment.NewLine, lines);
}
}
public int Count => _myDependentsMap.Count;
}
}

View File

@@ -0,0 +1,105 @@
using Flee.Parsing;
using Flee.PublicTypes;
namespace Flee.CalcEngine.InternalTypes
{
internal class IdentifierAnalyzer : Analyzer
{
private readonly IDictionary<int, string> _myIdentifiers;
private int _myMemberExpressionCount;
private bool _myInFieldPropertyExpression;
public IdentifierAnalyzer()
{
_myIdentifiers = new Dictionary<int, string>();
}
public override Node Exit(Node node)
{
switch (node.Id)
{
case (int)ExpressionConstants.IDENTIFIER:
this.ExitIdentifier((Token)node);
break;
case (int)ExpressionConstants.FIELD_PROPERTY_EXPRESSION:
this.ExitFieldPropertyExpression();
break;
}
return node;
}
public override void Enter(Node node)
{
switch (node.Id)
{
case (int)ExpressionConstants.MEMBER_EXPRESSION:
this.EnterMemberExpression();
break;
case (int)ExpressionConstants.FIELD_PROPERTY_EXPRESSION:
this.EnterFieldPropertyExpression();
break;
}
}
private void ExitIdentifier(Token node)
{
if (_myInFieldPropertyExpression == false)
{
return;
}
if (_myIdentifiers.ContainsKey(_myMemberExpressionCount) == false)
{
_myIdentifiers.Add(_myMemberExpressionCount, node.Image);
}
}
private void EnterMemberExpression()
{
_myMemberExpressionCount += 1;
}
private void EnterFieldPropertyExpression()
{
_myInFieldPropertyExpression = true;
}
private void ExitFieldPropertyExpression()
{
_myInFieldPropertyExpression = false;
}
public override void Reset()
{
_myIdentifiers.Clear();
_myMemberExpressionCount = -1;
}
public ICollection<string> GetIdentifiers(ExpressionContext context)
{
Dictionary<string, object> dict = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
ExpressionImports ei = context.Imports;
foreach (string identifier in _myIdentifiers.Values)
{
// Skip names registered as namespaces
if (ei.HasNamespace(identifier) == true)
{
continue;
}
else if (context.Variables.ContainsKey(identifier) == true)
{
// Identifier is a variable
continue;
}
// Get only the unique values
dict[identifier] = null;
}
return dict.Keys;
}
}
}

View File

@@ -0,0 +1,114 @@
using Flee.PublicTypes;
namespace Flee.CalcEngine.InternalTypes
{
internal class PairEqualityComparer : EqualityComparer<ExpressionResultPair>
{
public override bool Equals(ExpressionResultPair x, ExpressionResultPair y)
{
return string.Equals(x.Name, y.Name, StringComparison.OrdinalIgnoreCase);
}
public override int GetHashCode(ExpressionResultPair obj)
{
return StringComparer.OrdinalIgnoreCase.GetHashCode(obj.Name);
}
}
internal abstract class ExpressionResultPair
{
private string _myName;
protected IDynamicExpression MyExpression;
protected ExpressionResultPair()
{
}
public abstract void Recalculate();
public void SetExpression(IDynamicExpression e)
{
MyExpression = e;
}
public void SetName(string name)
{
_myName = name;
}
public override string ToString()
{
return _myName;
}
public string Name => _myName;
public abstract Type ResultType { get; }
public abstract object ResultAsObject { get; set; }
public IDynamicExpression Expression => MyExpression;
}
internal class GenericExpressionResultPair<T> : ExpressionResultPair
{
public T MyResult;
public GenericExpressionResultPair()
{
}
public override void Recalculate()
{
MyResult = (T)MyExpression.Evaluate();
}
public T Result => MyResult;
public override System.Type ResultType => typeof(T);
public override object ResultAsObject
{
get { return MyResult; }
set { MyResult = (T)value; }
}
}
internal class BatchLoadInfo
{
public string Name;
public string ExpressionText;
public ExpressionContext Context;
public BatchLoadInfo(string name, string text, ExpressionContext context)
{
this.Name = name;
this.ExpressionText = text;
this.Context = context;
}
}
public sealed class NodeEventArgs : EventArgs
{
private string _myName;
private object _myResult;
internal NodeEventArgs()
{
}
internal void SetData(string name, object result)
{
_myName = name;
_myResult = result;
}
public string Name => _myName;
public object Result => _myResult;
}
}