-
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
namespace xFunc.Maths.Analyzers2; | ||
Check failure on line 1 in xFunc.Maths/Analyzers2/ChainRuleBuilder.cs GitHub Actions / Analyze (csharp)
Check failure on line 1 in xFunc.Maths/Analyzers2/ChainRuleBuilder.cs Azure Pipelines / sys27.xFuncxFunc.Maths/Analyzers2/ChainRuleBuilder.cs#L1
|
||
|
||
internal class ChainRuleBuilder<TExpression> : | ||
IInitialChainRuleBuilder<TExpression>, | ||
IChainRuleBuilder<TExpression> | ||
where TExpression : IExpression | ||
{ | ||
private ChainRule initialRule; | ||
Check failure on line 8 in xFunc.Maths/Analyzers2/ChainRuleBuilder.cs GitHub Actions / Analyze (csharp)
Check failure on line 8 in xFunc.Maths/Analyzers2/ChainRuleBuilder.cs Azure Pipelines / sys27.xFuncxFunc.Maths/Analyzers2/ChainRuleBuilder.cs#L8
|
||
private ChainRule currentRule; | ||
Check failure on line 9 in xFunc.Maths/Analyzers2/ChainRuleBuilder.cs GitHub Actions / Analyze (csharp)
Check failure on line 9 in xFunc.Maths/Analyzers2/ChainRuleBuilder.cs Azure Pipelines / sys27.xFuncxFunc.Maths/Analyzers2/ChainRuleBuilder.cs#L9
|
||
|
||
public IChainRuleBuilder<TExpression> WithRule(IRule<TExpression> rule) | ||
{ | ||
initialRule = currentRule = new ChainRule(rule); | ||
|
||
return this; | ||
} | ||
|
||
public IChainRuleBuilder<TExpression> WithNext(IRule<TExpression> next) | ||
{ | ||
var chain = new ChainRule(next); | ||
currentRule.SetNext(chain); | ||
currentRule = chain; | ||
|
||
return this; | ||
} | ||
|
||
public IRule GetRule() | ||
=> initialRule.UnwrapIfEmpty(); | ||
|
||
private sealed class ChainRule : IRule<TExpression> | ||
{ | ||
private readonly IRule<TExpression> current; | ||
private IRule<TExpression>? next; | ||
|
||
public ChainRule(IRule<TExpression> rule) | ||
=> current = rule ?? throw new ArgumentNullException(nameof(rule)); | ||
|
||
public void SetNext(IRule<TExpression> rule) | ||
=> next = rule ?? throw new ArgumentNullException(nameof(rule)); | ||
|
||
public IRule UnwrapIfEmpty() | ||
=> next is null ? current : this; | ||
|
||
public Result Execute(IExpression expression, RuleContext context) | ||
{ | ||
var result = current.Execute(expression, context); | ||
if (result.IsHandled() || result.IsReAnalyze()) | ||
return result; | ||
|
||
if (result.IsContinue()) | ||
expression = result.Value; | ||
|
||
if (next is not null) | ||
return next.Execute(expression, context); | ||
|
||
return Result.NotHandled(); | ||
} | ||
|
||
public Result Execute(TExpression expression, RuleContext context) | ||
=> Execute(expression as IExpression, context); | ||
|
||
public string Name => "Chain Rule"; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
namespace xFunc.Maths.Analyzers2; | ||
Check failure on line 1 in xFunc.Maths/Analyzers2/ExecutionStep.cs GitHub Actions / Analyze (csharp)
Check failure on line 1 in xFunc.Maths/Analyzers2/ExecutionStep.cs Azure Pipelines / sys27.xFuncxFunc.Maths/Analyzers2/ExecutionStep.cs#L1
|
||
|
||
public readonly struct ExecutionStep | ||
{ | ||
public ExecutionStep(IRule rule, IExpression before, IExpression after) | ||
{ | ||
Name = rule.Name; | ||
Before = before; | ||
After = after; | ||
} | ||
|
||
public string Name { get; } | ||
|
||
public IExpression Before { get; } | ||
|
||
public IExpression After { get; } | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
namespace xFunc.Maths.Analyzers2; | ||
Check failure on line 1 in xFunc.Maths/Analyzers2/IAnalyzer2.cs GitHub Actions / Analyze (csharp)
|
||
|
||
public interface IAnalyzer2 | ||
{ | ||
IExpression Analyze(IExpression expression); | ||
|
||
IExpression Analyze(IExpression expression, RuleContext context); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
namespace xFunc.Maths.Analyzers2; | ||
Check failure on line 1 in xFunc.Maths/Analyzers2/IChainRuleBuilder.cs GitHub Actions / Analyze (csharp)
|
||
|
||
internal interface IChainRuleBuilder<out TExpression> | ||
where TExpression : IExpression | ||
{ | ||
IChainRuleBuilder<TExpression> WithNext(IRule<TExpression> next); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
namespace xFunc.Maths.Analyzers2; | ||
Check failure on line 1 in xFunc.Maths/Analyzers2/IInitialChainRuleBuilder.cs GitHub Actions / Analyze (csharp)
|
||
|
||
internal interface IInitialChainRuleBuilder<out TExpression> | ||
where TExpression : IExpression | ||
{ | ||
IChainRuleBuilder<TExpression> WithRule(IRule<TExpression> rule); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
namespace xFunc.Maths.Analyzers2; | ||
Check failure on line 1 in xFunc.Maths/Analyzers2/IRule.cs GitHub Actions / Analyze (csharp)
|
||
|
||
public interface IRule | ||
{ | ||
Result Execute(IExpression expression, RuleContext context); | ||
|
||
string Name { get; } | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
namespace xFunc.Maths.Analyzers2; | ||
Check failure on line 1 in xFunc.Maths/Analyzers2/IRule{TExpression}.cs GitHub Actions / Analyze (csharp)
|
||
|
||
public interface IRule<in TExpression> : IRule | ||
{ | ||
Result Execute(TExpression expression, RuleContext context); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
using System.Diagnostics.CodeAnalysis; | ||
Check failure on line 1 in xFunc.Maths/Analyzers2/Result.cs GitHub Actions / Analyze (csharp)
|
||
|
||
namespace xFunc.Maths.Analyzers2; | ||
|
||
public readonly struct Result | ||
{ | ||
private readonly ResultKind kind; | ||
|
||
private Result(ResultKind kind, IExpression? value) | ||
{ | ||
this.kind = kind; | ||
Value = value; | ||
} | ||
|
||
public static Result NotHandled() | ||
=> new Result(ResultKind.NotHandled, default); | ||
|
||
public static Result Handled(IExpression value) | ||
=> new Result(ResultKind.Handled, value); | ||
|
||
public static Result Continue(IExpression value) | ||
=> new Result(ResultKind.Continue, value); | ||
|
||
public static Result ReAnalyze(IExpression value) | ||
=> new Result(ResultKind.ReAnalyze, value); | ||
|
||
private bool IsKind(ResultKind kind) | ||
=> this.kind == kind; | ||
|
||
[MemberNotNullWhen(false, nameof(Value))] | ||
public bool IsNotHandled() | ||
=> IsKind(ResultKind.NotHandled); | ||
|
||
[MemberNotNullWhen(true, nameof(Value))] | ||
public bool IsHandled() | ||
=> IsKind(ResultKind.Handled); | ||
|
||
[MemberNotNullWhen(true, nameof(Value))] | ||
public bool IsContinue() | ||
=> IsKind(ResultKind.Continue); | ||
|
||
[MemberNotNullWhen(true, nameof(Value))] | ||
public bool IsReAnalyze() | ||
=> IsKind(ResultKind.ReAnalyze); | ||
|
||
public IExpression? Value { get; } | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
namespace xFunc.Maths.Analyzers2; | ||
|
||
public enum ResultKind | ||
{ | ||
NotHandled, | ||
Handled, | ||
Continue, | ||
ReAnalyze, | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
namespace xFunc.Maths.Analyzers2; | ||
|
||
public abstract class Rule<TExpression> : IRule<TExpression> | ||
where TExpression : IExpression | ||
{ | ||
Result IRule.Execute(IExpression expression, RuleContext context) | ||
=> Execute((TExpression)expression, context); | ||
|
||
public Result Execute(TExpression expression, RuleContext context) | ||
{ | ||
var result = ExecuteInternal(expression, context); | ||
if (result.IsHandled() || result.IsContinue() || result.IsReAnalyze()) | ||
context.AddStep(this, expression, result.Value); | ||
|
||
return result; | ||
} | ||
|
||
protected abstract Result ExecuteInternal(TExpression expression, RuleContext context); | ||
|
||
protected static Result Handled(IExpression value) | ||
=> Result.Handled(value); | ||
|
||
protected static Result Continue(IExpression value) | ||
=> Result.Continue(value); | ||
|
||
protected static Result ReAnalyze(IExpression value) | ||
=> Result.ReAnalyze(value); | ||
|
||
protected static Result NotHandled() | ||
=> Result.NotHandled(); | ||
|
||
public virtual string Name => GetType().Name; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
namespace xFunc.Maths.Analyzers2; | ||
|
||
public class RuleContext | ||
{ | ||
private readonly IAnalyzer2 analyzer; | ||
private readonly List<ExecutionStep> steps; | ||
|
||
public RuleContext(IAnalyzer2 analyzer) | ||
{ | ||
this.analyzer = analyzer; | ||
this.steps = new List<ExecutionStep>(); | ||
} | ||
|
||
public IExpression Analyze(IExpression expression) | ||
=> analyzer.Analyze(expression, this); | ||
|
||
public void AddStep(IRule rule, IExpression before, IExpression after) | ||
=> steps.Add(new ExecutionStep(rule, before, after)); | ||
|
||
public IEnumerable<ExecutionStep> Steps => steps; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
namespace xFunc.Maths.Analyzers2; | ||
|
||
internal class RuleStorage | ||
{ | ||
private readonly IReadOnlyDictionary<Type, IRule> rules; | ||
|
||
public RuleStorage(IReadOnlyDictionary<Type, IRule> rules) | ||
=> this.rules = rules; | ||
|
||
public IRule? GetRule(Type type) | ||
{ | ||
rules.TryGetValue(type, out var rule); | ||
|
||
return rule; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
namespace xFunc.Maths.Analyzers2; | ||
|
||
internal class RuleStorageBuilder | ||
{ | ||
private readonly Dictionary<Type, IRule> rules = new Dictionary<Type, IRule>(); | ||
|
||
public RuleStorageBuilder WithRule<TExpression>(IRule<TExpression> rule) | ||
where TExpression : IExpression | ||
{ | ||
rules[typeof(TExpression)] = rule; | ||
|
||
return this; | ||
} | ||
|
||
public RuleStorageBuilder WithChain<TExpression>( | ||
Action<IInitialChainRuleBuilder<TExpression>> builder) | ||
where TExpression : IExpression | ||
{ | ||
var ruleBuilder = new ChainRuleBuilder<TExpression>(); | ||
builder(ruleBuilder); | ||
var rule = ruleBuilder.GetRule(); | ||
rules[typeof(TExpression)] = rule; | ||
|
||
return this; | ||
} | ||
|
||
public RuleStorage Build() | ||
=> new RuleStorage(rules); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
namespace xFunc.Maths.Analyzers2.Rules.AbsRules; | ||
|
||
public class AbsNestedRule : Rule<Abs> | ||
{ | ||
protected override Result ExecuteInternal(Abs expression, RuleContext context) | ||
=> expression.Argument switch | ||
{ | ||
Abs abs => Handled(abs), | ||
_ => NotHandled(), | ||
}; | ||
|
||
public override string Name => "Abs Nested Rule"; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
namespace xFunc.Maths.Analyzers2.Rules.AbsRules; | ||
|
||
public class AbsUnaryMinusRule : Rule<Abs> | ||
{ | ||
protected override Result ExecuteInternal(Abs expression, RuleContext context) | ||
=> expression.Argument switch | ||
{ | ||
UnaryMinus minus => Handled(minus.Argument), | ||
_ => NotHandled(), | ||
}; | ||
|
||
public override string Name => "Abs Unary Minus"; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
namespace xFunc.Maths.Analyzers2.Rules.AbsRules; | ||
|
||
public class AbsUnaryRule : UnaryRule<Abs> | ||
{ | ||
protected override Abs Create(IExpression argument) | ||
=> new Abs(argument); | ||
|
||
public override string Name => "Abs Unary Rule"; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
namespace xFunc.Maths.Analyzers2.Rules.AddRules; | ||
|
||
public class AddBinaryRule : BinaryRule<Add> | ||
{ | ||
protected override Add Create(IExpression left, IExpression right) | ||
=> new Add(left, right); | ||
|
||
public override string Name => "Add Binary Rule"; | ||
} |