diff --git a/README.md b/README.md
index 80fb122..0abd16b 100644
--- a/README.md
+++ b/README.md
@@ -21,14 +21,6 @@ workflows and other language constructs.
* `StringFormatExpression`: An expression that creates a string using a supplied format string and parameters.
* `DebugExpression`: An expression that helps when debugging expression trees.
-* **Expression Optimizers**
- * `OptimizerBuilder`: An composite optimizer builder.
- * `ConstantFoldingOptimizer`: An optimizer that precomputes constant expressions.
- * `OperatorReductionOptimizer`: An optimizer that simplifies arithmetic and logical expressions.
- * `StructuralReductionOptimizer`: An optimizer that removes unreachable code and consolidates nested or redundant constructs.
- * `ValueBindingOptimizer`: An optimizer that simplifies and inlines, variable, constant, and member access operations.
- * `SubExpressionCachingOptimizer`: An optimizer that identifies and caches repeated subexpressions within a tree.
-
* Supports Fast Expression Compiler (FEC) for improved performance.
## Examples
diff --git a/docs/docs.projitems b/docs/docs.projitems
index c377965..fa849f7 100644
--- a/docs/docs.projitems
+++ b/docs/docs.projitems
@@ -9,14 +9,6 @@
docs
-
-
-
-
-
-
-
-
diff --git a/docs/index.md b/docs/index.md
index 5645aa4..38ce917 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -26,14 +26,6 @@ trees to handle asynchronous workflows and other language constructs.
* `StringFormatExpression`: An expression that creates a string using a supplied format string and parameters.
* `DebugExpression`: An expression that helps when debugging expression trees.
-* **Expression Optimizers**
- * `OptimizerBuilder`: An composite optimizer builder.
- * `ConstantFoldingOptimizer`: An optimizer that precomputes constant expressions.
- * `OperatorReductionOptimizer`: An optimizer that simplifies arithmetic and logical expressions.
- * `StructuralReductionOptimizer`: An optimizer that removes unreachable code and consolidates nested or redundant constructs.
- * `ValueBindingOptimizer`: An optimizer that simplifies and inlines, variable, constant, and member access operations.
- * `SubExpressionCachingOptimizer`: An optimizer that identifies and caches repeated subexpressions within a tree.
-
* Supports Fast Expression Compiler (FEC) for improved performance.
## Examples
diff --git a/docs/optimizers/constant-folding-optimizer.md b/docs/optimizers/constant-folding-optimizer.md
deleted file mode 100644
index 78344cb..0000000
--- a/docs/optimizers/constant-folding-optimizer.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-layout: default
-title: Constant Folding Optimizer
-parent: optimizers
-nav_order: 3
----
-# Constant Folding Optimizer
-The **Constant Folding Optimizer** precomputes constant expressions.
-
-## **Purpose**
-- **Issue**: Expressions involving only constants can unnecessarily consume runtime resources for evaluation.
-- **Solution**: Replaces constant expressions with their precomputed values.
-- **Result**: Simplifies trees and improves runtime performance by removing redundant evaluations.
-
-## **Usage Example**
-### **Before Optimization**
-```csharp
-.Lambda #Lambda1> {
- .Add(.Constant(3), .Constant(5))
-}
-```
-
-### **After Optimization**
-```csharp
-.Lambda #Lambda1> {
- .Constant(8)
-}
-```
\ No newline at end of file
diff --git a/docs/optimizers/operator-reduction-optimizer.md b/docs/optimizers/operator-reduction-optimizer.md
deleted file mode 100644
index d25f048..0000000
--- a/docs/optimizers/operator-reduction-optimizer.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-layout: default
-title: Operator Reduction Optimizer
-parent: optimizers
-nav_order: 4
----
-# Operator Reduction Optimizer
-The **Operator Reduction Optimizer** simplifies arithmetic and logical expressions.
-
-## **Purpose**
-- **Issue**: Expression trees often contain redundant operations, such as adding zero or multiplying by one.
-- **Solution**: By removing or simplifying these expressions, the optimizer reduces tree size and computation complexity.
-- **Result**: Improved runtime performance through reduced instruction execution and simplified interpretation.
-
-## **Usage Example**
-### **Before Optimization**
-```csharp
-.Lambda #Lambda1> {
- .Add(.Parameter(x), .Constant(0))
-}
-```
-
-### **After Optimization**
-```csharp
-.Lambda #Lambda1> {
- .Parameter(x)
-}
-```
\ No newline at end of file
diff --git a/docs/optimizers/optimizer-builder.md b/docs/optimizers/optimizer-builder.md
deleted file mode 100644
index 6816d6d..0000000
--- a/docs/optimizers/optimizer-builder.md
+++ /dev/null
@@ -1,40 +0,0 @@
----
-layout: default
-title: Optimizer Builder
-parent: optimizers
-nav_order: 2
----
-# Optimizer Builder
-The `OptimizerBuilder` constructs a composite optimizer, and orders optimizers based on their dependencies and priorities, ensuring proper execution.
-
-## **Dependency Ordering**
-The builder:
-1. Constructs a dependency graph based on declared dependencies.
-2. Topologically sorts the graph to resolve dependency order.
-3. Weaves standalone optimizers into the sequence based on priority.
-
-## **Workflow**
-- **Input Optimizers**:
- - `OperatorReductionOptimizer`: Depends on `ConstantFoldingVisitor` and `OperatorReductionVisitor`.
- - `StructuralReductionOptimizer`: Depends on `StructuralReductionVisitor`.
-
-- **Dependency Graph**:
- - Nodes: `{ConstantFoldingVisitor, OperatorReductionVisitor, StructuralReductionVisitor}`
- - Edges: `{ConstantFoldingVisitor -> OperatorReductionVisitor}`
-
-- **Sorted Execution Order**:
- 1. `ConstantFoldingVisitor`
- 2. `OperatorReductionVisitor`
- 3. `StructuralReductionVisitor`
-
-## **Usage Example**
-### **Builder Setup**
-```csharp
-var optimizer = new OptimizerBuilder()
- .With()
- .With()
- .With()
- .Build();
-
-var optimizedExpression = optimizer.Optimize(expression);
-```
diff --git a/docs/optimizers/optimizers.md b/docs/optimizers/optimizers.md
deleted file mode 100644
index 512b9cd..0000000
--- a/docs/optimizers/optimizers.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-layout: default
-title: Optimizers
-has_children: true
-nav_order: 1
----
-# Optimizers
-
-Expression optimization enhances the execution of expression trees by reducing redundancies, simplifying constructs,
-and eliminating unnecessary computations. By restructuring and minimizing expression complexity, optimizations
-improve runtime performance and reduce memory usage.
diff --git a/docs/optimizers/overview.md b/docs/optimizers/overview.md
deleted file mode 100644
index e0360fe..0000000
--- a/docs/optimizers/overview.md
+++ /dev/null
@@ -1,43 +0,0 @@
----
-layout: default
-title: Overview
-parent: optimizers
-nav_order: 1
----
-# Overview of Expression Optimization
-
-Expression optimization enhances the execution of expression trees by reducing redundancies, simplifying constructs,
-and eliminating unnecessary computations. By restructuring and minimizing expression complexity, optimizations
-improve runtime performance and reduce memory usage.
-
-## Optimization Categories
-
-Optimizations generally address one fo four categories of expression tree elements:
-
-### Structural Optimization
-
-Simplifies control flow structures like loops, conditionals, and blocks.
-
- - **How**: Removes unreachable code and consolidates nested blocks.
- - **Why**: Flattening nested blocks into a single sequence reduces interpreter overhead.
-
-### Expression-Level Optimization
-
-Optimizes arithmetic, logical, and constant expressions.
-
- - **How**: Eliminates trivial operations, such as adding zero or multiplying by one, and precomputes constant results.
- - **Why**: Folding constants reduces evaluation costs at runtime.
-
-### Inlining and Binding
-
-Inlines variables, constants, and member accesses to reduce overhead and memory usage.
-
- - **How**: Eliminates temporary variables and simplifies bindings.
- - **Why**: Replacing a single-use variable with its value directly reduces allocation and access overhead.
-
-### Subexpression Caching
-
-Identifies and caches reusable subexpressions to minimize repeated computations.
-
- - **How**: Prevents redundant evaluation of identical subexpressions in complex trees.
- - **Why**: Storing the result of a reused subexpression in a temporary variable minimizes redundant computation.
diff --git a/docs/optimizers/structural-reduction-optimizer.md b/docs/optimizers/structural-reduction-optimizer.md
deleted file mode 100644
index 450ad05..0000000
--- a/docs/optimizers/structural-reduction-optimizer.md
+++ /dev/null
@@ -1,32 +0,0 @@
----
-layout: default
-title: Structural Reduction Optimizer
-parent: optimizers
-nav_order: 5
----
-# Structural Reduction Optimizer
-The **Structural Reduction Optimizer** removes unreachable code and consolidates nested or redundant constructs.
-
-## **Purpose**
-- **Issue**: Control flow structures can introduce unnecessary branching and redundant constructs, increasing overhead.
-- **Solution**: Simplifies control flow by removing dead branches, collapsing nested blocks, and optimizing loops.
-- **Result**: Streamlined execution paths with reduced branching and improved readability.
-
-## **Usage Example**
-### **Before Optimization**
-```csharp
-.Lambda #Lambda1> {
- .IfThenElse(
- .Constant(true),
- .Constant(42),
- .Constant(0)
- )
-}
-```
-
-### **After Optimization**
-```csharp
-.Lambda #Lambda1> {
- .Constant(42)
-}
-```
\ No newline at end of file
diff --git a/docs/optimizers/subexpression-caching-optimizer.md b/docs/optimizers/subexpression-caching-optimizer.md
deleted file mode 100644
index 7010398..0000000
--- a/docs/optimizers/subexpression-caching-optimizer.md
+++ /dev/null
@@ -1,31 +0,0 @@
----
-layout: default
-title: Subexpression Caching Optimizer
-parent: optimizers
-nav_order: 7
----
-# Subexpression Caching Optimizer
-The **Subexpression Caching Optimizer** identifies and caches repeated subexpressions within a tree.
-
-## **Purpose**
-- **Issue**: Identical subexpressions evaluated multiple times can lead to redundant computations.
-- **Solution**: Creates temporary variables for reusable subexpressions and updates the tree to use these variables.
-- **Result**: Reduced computation time by minimizing repeated evaluation.
-
-## **Usage Example**
-### **Before Optimization**
-```csharp
-.Lambda #Lambda1> {
- .Add(.Multiply(5, (3 + 2)), .Multiply(5, (3 + 2)))
-}
-```
-
-### **After Optimization**
-```csharp
-.Lambda #Lambda1> {
- .Block(System.Int32 $cacheVar) {
- $cacheVar = .Multiply(5, (3 + 2));
- .Add($cacheVar, $cacheVar)
- }
-}
-```
diff --git a/docs/optimizers/value-binding-optimizer.md b/docs/optimizers/value-binding-optimizer.md
deleted file mode 100644
index f6cf764..0000000
--- a/docs/optimizers/value-binding-optimizer.md
+++ /dev/null
@@ -1,31 +0,0 @@
----
-layout: default
-title: Value Binding Optimizer
-parent: optimizers
-nav_order: 6
----
-# Value Binding Optimizer
-The **Value Binding Optimizer** simplifies and inlines, variable, constant, and member access operations.
-
-## **Purpose**
-- **Issue**: Expression trees often include temporary variables or member accesses that can be resolved to constants or direct values.
-- **Solution**: Inlines single-use variables, evaluates constant member accesses, and simplifies bindings.
-- **Result**: Reduced memory usage and improved evaluation speed.
-
-## **Usage Example**
-### **Before Optimization**
-```csharp
-.Lambda #Lambda1> {
- .Block(
- .Assign(.Parameter(x), .Constant(5)),
- .Parameter(x)
- )
-}
-```
-
-### **After Optimization**
-```csharp
-.Lambda #Lambda1> {
- .Constant(5)
-}
-```
\ No newline at end of file
diff --git a/src/Hyperbee.Expressions/Optimizers/ConstantFoldingOptimizer.cs b/src/Hyperbee.Expressions/Optimizers/ConstantFoldingOptimizer.cs
deleted file mode 100644
index 952e5a4..0000000
--- a/src/Hyperbee.Expressions/Optimizers/ConstantFoldingOptimizer.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using Hyperbee.Expressions.Optimizers.Visitors;
-
-namespace Hyperbee.Expressions.Optimizers;
-
-// ConstantFoldingOptimizer: Constant Evaluation and Simplification
-//
-// This optimizer evaluates constant expressions and simplifies them to their simplest form.
-
-public class ConstantFoldingOptimizer : ExpressionOptimizer
-{
- public override IExpressionTransformer[] Dependencies =>
- [
- new ConstantFoldingVisitor()
- ];
-}
diff --git a/src/Hyperbee.Expressions/Optimizers/ExpressionOptimizer.cs b/src/Hyperbee.Expressions/Optimizers/ExpressionOptimizer.cs
deleted file mode 100644
index 91fa66e..0000000
--- a/src/Hyperbee.Expressions/Optimizers/ExpressionOptimizer.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using System.Linq.Expressions;
-
-namespace Hyperbee.Expressions.Optimizers;
-
-public abstract class ExpressionOptimizer //: IExpressionOptimizer
-{
- public abstract IExpressionTransformer[] Dependencies { get; }
-
- public virtual Expression Optimize( Expression expression )
- {
- foreach ( var dependency in Dependencies )
- {
- expression = dependency.Transform( expression );
- }
-
- return expression;
- }
-
- public TExpr Optimize( TExpr expression ) where TExpr : LambdaExpression
- {
- foreach ( var dependency in Dependencies )
- {
- expression = (TExpr) dependency.Transform( expression );
- }
-
- return expression;
- }
-}
diff --git a/src/Hyperbee.Expressions/Optimizers/IExpressionTransformer.cs b/src/Hyperbee.Expressions/Optimizers/IExpressionTransformer.cs
deleted file mode 100644
index 7106d48..0000000
--- a/src/Hyperbee.Expressions/Optimizers/IExpressionTransformer.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using System.Linq.Expressions;
-
-namespace Hyperbee.Expressions.Optimizers;
-
-public interface IExpressionTransformer
-{
- int Priority { get; }
-
- Expression Transform( Expression expression );
-}
-
-public static class PriorityGroup
-{
- public const int ConstantEvaluationAndSimplification = 0x0100;
- public const int ControlFlowAndVariableSimplification = 0x0200;
- public const int StructuralReductionAndConsolidation = 0x0400;
- public const int ExpressionReductionAndCaching = 0x0800;
-}
diff --git a/src/Hyperbee.Expressions/Optimizers/InliningOptimizer.cs b/src/Hyperbee.Expressions/Optimizers/InliningOptimizer.cs
deleted file mode 100644
index f2fc366..0000000
--- a/src/Hyperbee.Expressions/Optimizers/InliningOptimizer.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using Hyperbee.Expressions.Optimizers.Visitors;
-
-namespace Hyperbee.Expressions.Optimizers;
-
-// InliningOptimizer: Inlining Functions, Constants, and Conditional Values
-//
-// This optimizer inlines constants and simplifies expressions by propagating known values.
-// It focuses on inlining lambda expressions, boolean short-circuiting, and simplifying conditional
-// expressions based on constant values.
-//
-// Before:
-// .Invoke(lambda, .Constant(5))
-//
-// After:
-// .LambdaExpression(
-// .Parameter(x),
-// .Add(.Constant(5), .Constant(5))
-// )
-//
-// Before:
-// .IfThenElse(.Constant(true), .Constant("True Branch"), .Constant("False Branch"))
-//
-// After:
-// .Constant("True Branch")
-//
-public class InliningOptimizer : ExpressionOptimizer
-{
- public override IExpressionTransformer[] Dependencies =>
- [
- new InliningVisitor()
- ];
-}
-
diff --git a/src/Hyperbee.Expressions/Optimizers/OperatorReductionOptimizer.cs b/src/Hyperbee.Expressions/Optimizers/OperatorReductionOptimizer.cs
deleted file mode 100644
index b965b3d..0000000
--- a/src/Hyperbee.Expressions/Optimizers/OperatorReductionOptimizer.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-using Hyperbee.Expressions.Optimizers.Visitors;
-
-namespace Hyperbee.Expressions.Optimizers;
-
-// ExpressionReduction: Arithmetic and Logical Reduction
-//
-// This optimizer removes trivial arithmetic and logical expressions that
-// have no effect, simplifies nested expressions, and combines sequential
-// expressions where possible.
-//
-// Examples:
-// Before:
-// .Add(.Parameter(x), .Constant(0))
-//
-// After:
-// .Parameter(x)
-//
-// Before:
-// .Multiply(.Parameter(x), .Constant(1))
-//
-// After:
-// .Parameter(x)
-//
-public class OperatorReductionOptimizer : ExpressionOptimizer
-{
- public override IExpressionTransformer[] Dependencies =>
- [
- new ConstantFoldingVisitor(),
- new OperatorReductionVisitor()
- ];
-}
-
diff --git a/src/Hyperbee.Expressions/Optimizers/OptimizerBuilder.cs b/src/Hyperbee.Expressions/Optimizers/OptimizerBuilder.cs
deleted file mode 100644
index 7d0c03f..0000000
--- a/src/Hyperbee.Expressions/Optimizers/OptimizerBuilder.cs
+++ /dev/null
@@ -1,180 +0,0 @@
-namespace Hyperbee.Expressions.Optimizers;
-
-public class OptimizerBuilder
-{
- private readonly List _optimizers = [];
-
- public OptimizerBuilder With() where T : ExpressionOptimizer, new()
- {
- _optimizers.Add( new T() );
- return this;
- }
-
- public ExpressionOptimizer Build()
- {
- // Separate optimizers based on dependency count
- var multiDependencyOptimizers = _optimizers.Where( opt => opt.Dependencies.Length > 1 ).ToList();
- var standaloneTransformers = _optimizers
- .Where( opt => opt.Dependencies.Length == 1 )
- .SelectMany( opt => opt.Dependencies )
- .OrderBy( tran => tran.Priority )
- .ToList();
-
- // Build and sort the dependency graph
- var dependencyGraph = BuildDependencyGraph( multiDependencyOptimizers );
- var sortedDependencies = TopologicalSort( dependencyGraph );
-
- // Weave standalone transformers into sorted dependencies to achieve a unified execution order
- var wovenTransformers = WeaveStandaloneTransformers( sortedDependencies, standaloneTransformers );
-
- return new CompositeOptimizer( wovenTransformers.ToArray() );
- }
-
- // Construct a dependency graph based on relative order within each optimizer's dependencies.
- // Each visitor type becomes a node, and edges are added to maintain the internal order of each optimizer’s dependencies.
- // This process ensures that dependencies are combined into a consistent order across optimizers without duplication.
- //
- // Example:
- // Optimizer 1: [A, B, C, D]
- // Optimizer 2: [S, C, E, F, D]
- //
- // Resulting Graph:
- // Nodes: [A, B, C, D, S, E, F]
- // Edges: [A → B, B → C, C → D, S → C, C → E, E → F, F → D]
- //
- // This ensures all relative dependencies are respected, creating a coherent dependency graph.
-
- private static Dictionary> BuildDependencyGraph( IEnumerable optimizers )
- {
- var graph = new Dictionary>();
-
- foreach ( var optimizer in optimizers )
- {
- var dependencies = optimizer.Dependencies;
- for ( var i = 0; i < dependencies.Length - 1; i++ )
- {
- var current = dependencies[i].GetType();
- var next = dependencies[i + 1].GetType();
-
- if ( !graph.ContainsKey( current ) )
- graph[current] = [];
-
- if ( !graph[current].Contains( next ) )
- graph[current].Add( next );
- }
-
- // Ensure each dependency type is represented as a node in the graph
- foreach ( var dep in dependencies.Select( d => d.GetType() ) )
- {
- if ( !graph.ContainsKey( dep ) )
- graph[dep] = [];
- }
- }
-
- return graph;
- }
-
- // Perform a topological sort on the dependency graph to ensure a globally consistent order that satisfies
- // all relative constraints from each optimizer's dependency list.
- //
- // Example:
- // Given a graph with edges: [A → B, B → C, C → D, S → C, C → E, E → F, F → D]
- //
- // Calling TopologicalSort on this graph would yield the sorted order: [A, S, B, C, E, F, D].
- // This order preserves dependencies across optimizers and avoids duplication.
- //
- // Before Sort:
- // Graph Edges: [A → B, B → C, C → D, S → C, C → E, E → F, F → D]
- //
- // After Sort:
- // Sorted Order: [A, S, B, C, E, F, D]
-
- private List TopologicalSort( Dictionary> graph )
- {
- var sorted = new List();
- var visited = new HashSet();
- var visiting = new HashSet();
-
- foreach ( var node in graph.Keys )
- {
- if ( !Visit( node ) )
- throw new InvalidOperationException( $"Cycle detected in dependencies involving {node}." );
- }
-
- return sorted.Select( type =>
- _optimizers.SelectMany( opt => opt.Dependencies )
- .First( dep => dep.GetType() == type )
- ).ToList();
-
- bool Visit( Type node )
- {
- if ( visited.Contains( node ) )
- return true;
-
- if ( !visiting.Add( node ) )
- return false; // Cycle detected
-
- foreach ( var neighbor in graph[node] )
- {
- if ( !Visit( neighbor ) )
- return false;
- }
-
- visiting.Remove( node );
- visited.Add( node );
- sorted.Add( node );
-
- return true;
- }
- }
-
- // Weave standalone transformers into the sorted list of multi-dependency transformers, based on priority.
- // This ensures that standalone transformers ordered according to priority, while respecting the sorted
- // execution order of multi-dependency transformers.
- //
- // Example:
- // Sorted Transformers: [A, B, C]
- // Standalone Transformers: [X (Priority: 1), Y (Priority: 2)]
- //
- // Resulting Order:
- // [X, A, B, Y, C]
- //
- // This interleaving ensures that the final list maintains dependency order while honoring standalone transformer priorities.
-
- private static List WeaveStandaloneTransformers( List sortedTransformers, List standaloneTransformers )
- {
- var finalTransformers = new List();
- int standaloneIndex = 0;
-
- for ( var index = 0; index < sortedTransformers.Count; index++ )
- {
- var transformer = sortedTransformers[index];
- while ( standaloneIndex < standaloneTransformers.Count && standaloneTransformers[standaloneIndex].Priority <= transformer.Priority )
- {
- finalTransformers.Add( standaloneTransformers[standaloneIndex] );
- standaloneIndex++;
- }
-
- finalTransformers.Add( transformer );
- }
-
- // Append any remaining standalone transformers
- while ( standaloneIndex < standaloneTransformers.Count )
- {
- finalTransformers.Add( standaloneTransformers[standaloneIndex] );
- standaloneIndex++;
- }
-
- return finalTransformers;
- }
-
- public class CompositeOptimizer : ExpressionOptimizer
- {
- public override IExpressionTransformer[] Dependencies { get; }
-
- internal CompositeOptimizer( IExpressionTransformer[] dependencies )
- {
- Dependencies = dependencies;
- }
- }
-}
diff --git a/src/Hyperbee.Expressions/Optimizers/StructuralReductionOptimizer.cs b/src/Hyperbee.Expressions/Optimizers/StructuralReductionOptimizer.cs
deleted file mode 100644
index 2257e2e..0000000
--- a/src/Hyperbee.Expressions/Optimizers/StructuralReductionOptimizer.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using Hyperbee.Expressions.Optimizers.Visitors;
-
-namespace Hyperbee.Expressions.Optimizers;
-
-// StructuralReductionOptimizer: Control Flow Simplification
-//
-// This optimizer manages blocks, labels, loops, and conditionals, removing unreachable
-// code and dead branches based on control flow and constant conditions.
-
-public class StructuralReductionOptimizer : ExpressionOptimizer
-{
- public override IExpressionTransformer[] Dependencies =>
- [
- new StructuralReductionVisitor()
- ];
-}
-
diff --git a/src/Hyperbee.Expressions/Optimizers/SubexpressionCachingOptimizer.cs b/src/Hyperbee.Expressions/Optimizers/SubexpressionCachingOptimizer.cs
deleted file mode 100644
index 8d1a28c..0000000
--- a/src/Hyperbee.Expressions/Optimizers/SubexpressionCachingOptimizer.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-using Hyperbee.Expressions.Optimizers.Visitors;
-
-namespace Hyperbee.Expressions.Optimizers;
-
-// ExpressionCachingOptimizer: Expression Subexpression Caching
-//
-// This optimizer performs subexpression caching to reduce repeated computation in complex expressions.
-// By identifying and reusing common subexpressions, it improves execution efficiency, especially in cases
-// where identical subexpressions are evaluated multiple times within an expression tree.
-//
-// Example:
-//
-// Before Optimization:
-//
-// .Lambda #Lambda1 {
-// 5 * (3 + 2) + 5 * (3 + 2)
-// }
-//
-// After Optimization:
-//
-// .Lambda #Lambda1 {
-// .Block(System.Int32 $cacheVar) {
-// $cacheVar = 5 * (3 + 2);
-// $cacheVar + $cacheVar
-// }
-// }
-//
-// In this example, the optimizer identifies the subexpression `5 * (3 + 2)` as a repeated, cacheable part.
-// It creates a variable `$cacheVar` to hold the computed value of `5 * (3 + 2)`, and replaces occurrences
-// of this subexpression with `$cacheVar` in the resulting `BlockExpression`. This optimization reduces
-// redundant calculations, resulting in a more efficient expression execution.
-
-public class SubexpressionCachingOptimizer : ExpressionOptimizer
-{
- public override IExpressionTransformer[] Dependencies =>
- [
- new SubexpressionCachingVisitor()
- ];
-}
-
diff --git a/src/Hyperbee.Expressions/Optimizers/ValueBindingOptimizer.cs b/src/Hyperbee.Expressions/Optimizers/ValueBindingOptimizer.cs
deleted file mode 100644
index 74a1e63..0000000
--- a/src/Hyperbee.Expressions/Optimizers/ValueBindingOptimizer.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using Hyperbee.Expressions.Optimizers.Visitors;
-
-namespace Hyperbee.Expressions.Optimizers;
-
-// VariableBindingOptimizer: Variable, Constant, and Member Access Optimization
-//
-// This optimizer handles optimizations related to variables, constants, and member accesses,
-// performing constant folding, variable inlining, and simplifying member access.
-
-public class ValueBindingOptimizer : ExpressionOptimizer
-{
- public override IExpressionTransformer[] Dependencies =>
- [
- new VariableReducerVisitor(),
- new ConstantFoldingVisitor(),
- new MemberAccessVisitor()
- ];
-}
diff --git a/src/Hyperbee.Expressions/Optimizers/Visitors/ConstantFoldingVisitor.cs b/src/Hyperbee.Expressions/Optimizers/Visitors/ConstantFoldingVisitor.cs
deleted file mode 100644
index 311f5f5..0000000
--- a/src/Hyperbee.Expressions/Optimizers/Visitors/ConstantFoldingVisitor.cs
+++ /dev/null
@@ -1,329 +0,0 @@
-using System.Linq.Expressions;
-using System.Numerics;
-
-namespace Hyperbee.Expressions.Optimizers.Visitors;
-
-// ConstantFoldingVisitor: Arithmetic, Logical, and Conditional Constant Folding
-//
-// This visitor evaluates constant expressions at compile-time, replacing them with their computed result.
-// It simplifies arithmetic, boolean, string, and conditional expressions when all operands are constants.
-//
-// Examples:
-//
-// Before:
-// .Add(.Constant(3), .Constant(5))
-//
-// After:
-// .Constant(8)
-//
-// Before:
-// .IfThenElse(.Constant(true), .Constant("True Branch"), .Constant("False Branch"))
-//
-// After:
-// .Constant("True Branch")
-//
-// Before:
-// .Negate(.Constant(5))
-//
-// After:
-// .Constant(-5)
-//
-public class ConstantFoldingVisitor : ExpressionVisitor, IExpressionTransformer
-{
- public int Priority => PriorityGroup.ConstantEvaluationAndSimplification + 10;
-
- public Expression Transform( Expression expression )
- {
- return Visit( expression );
- }
-
- protected override Expression VisitBinary( BinaryExpression node )
- {
- if ( node.Left is not ConstantExpression leftConst || node.Right is not ConstantExpression rightConst )
- {
- return base.VisitBinary( node );
- }
-
- var folded = FoldConstants( node.NodeType, leftConst, rightConst );
- return folded ?? base.VisitBinary( node );
- }
-
- protected override Expression VisitUnary( UnaryExpression node )
- {
- if ( node.Operand is ConstantExpression constOperand )
- {
- return FoldUnaryOperation( node.NodeType, constOperand ) ?? base.VisitUnary( node );
- }
-
- return base.VisitUnary( node );
- }
-
- protected override Expression VisitConditional( ConditionalExpression node )
- {
- var test = Visit( node.Test );
-
- if ( test is not ConstantExpression testConst )
- {
- return base.VisitConditional( node );
- }
-
- var condition = (bool) testConst.Value!;
- var result = condition ? node.IfTrue : node.IfFalse;
- return Visit( result );
-
- }
-
- private static ConstantExpression FoldUnaryOperation( ExpressionType nodeType, ConstantExpression operand )
- {
- // Unary folding: Supports negation, logical NOT, and bitwise NOT for constants.
- //
- // Examples:
- //
- // Before:
- // .Negate(.Constant(5))
- //
- // After:
- // .Constant(-5)
- //
- return nodeType switch
- {
- ExpressionType.Negate when operand.Value is int intValue => Expression.Constant( -intValue ),
- ExpressionType.Not when operand.Value is bool boolValue => Expression.Constant( !boolValue ),
- ExpressionType.OnesComplement when operand.Value is int intValue => Expression.Constant( ~intValue ),
- _ => null
- };
- }
-
- private static ConstantExpression FoldConstants( ExpressionType nodeType, ConstantExpression leftConst, ConstantExpression rightConst )
- {
- if ( !typeof( IConvertible ).IsAssignableFrom( leftConst.Type ) || !typeof( IConvertible ).IsAssignableFrom( rightConst.Type ) )
- return null;
-
- // Arithmetic and logical operations on constants
- if ( IsNumericType( leftConst.Type ) && IsNumericType( rightConst.Type ) )
- {
- return FoldNumericOperation( nodeType, leftConst, rightConst );
- }
-
- if ( leftConst.Type != rightConst.Type )
- {
- return null;
- }
-
- var type = leftConst.Type;
-
- return type switch
- {
- not null when type == typeof( bool ) => FoldBooleanOperation( nodeType, (bool) leftConst.Value!, (bool) rightConst.Value! ),
- not null when type == typeof( string ) => FoldStringOperation( nodeType, (string) leftConst.Value!, (string) rightConst.Value! ),
- not null when type == typeof( char ) => FoldCharOperation( nodeType, (char) leftConst.Value!, (char) rightConst.Value! ),
- not null when type == typeof( DateTime ) => FoldDateTimeOperation( nodeType, (DateTime) leftConst.Value!, rightConst.Value ),
- _ => null
- };
- }
-
- private static ConstantExpression FoldBooleanOperation( ExpressionType nodeType, bool left, bool right )
- {
- // Boolean folding: Simplifies operations like AND, OR, and comparisons.
- //
- // Examples:
- //
- // Before:
- // .And(.Constant(true), .Constant(false))
- //
- // After:
- // .Constant(false)
- //
- return nodeType switch
- {
- ExpressionType.And => Expression.Constant( left && right ),
- ExpressionType.Or => Expression.Constant( left || right ),
- ExpressionType.Equal => Expression.Constant( left == right ),
- ExpressionType.NotEqual => Expression.Constant( left != right ),
- _ => null
- };
- }
-
- private static ConstantExpression FoldCharOperation( ExpressionType nodeType, char left, char right )
- {
- // Char folding: Supports addition and subtraction on char constants.
- //
- // Examples:
- //
- // Before:
- // .Add(.Constant('A'), .Constant(1))
- //
- // After:
- // .Constant('B')
- //
- int leftInt = left;
- int rightInt = right;
-
- return nodeType switch
- {
- ExpressionType.Add => Expression.Constant( (char) (leftInt + rightInt) ),
- ExpressionType.Subtract => Expression.Constant( (char) (leftInt - rightInt) ),
- _ => null
- };
- }
-
- private static ConstantExpression FoldDateTimeOperation( ExpressionType nodeType, DateTime left, object rightValue )
- {
- // DateTime folding: Supports addition and subtraction of TimeSpan to DateTime.
- //
- // Examples:
- //
- // Before:
- // .Add(.Constant(new DateTime(2024, 1, 1)), .Constant(TimeSpan.FromDays(1)))
- //
- // After:
- // .Constant(new DateTime(2024, 1, 2))
- //
- if ( rightValue is not TimeSpan rightTimeSpan )
- return null;
-
- return nodeType switch
- {
- ExpressionType.Add => Expression.Constant( left + rightTimeSpan ),
- ExpressionType.Subtract => Expression.Constant( left - rightTimeSpan ),
- _ => null
- };
- }
-
- private static ConstantExpression FoldStringOperation( ExpressionType nodeType, string left, string right )
- {
- // String folding: Concatenates strings for `Add` operation.
- //
- // Examples:
- //
- // Before:
- // .Add(.Constant("Hello, "), .Constant("World!"))
- //
- // After:
- // .Constant("Hello, World!")
- //
- return nodeType != ExpressionType.Add ? null : Expression.Constant( left + right );
- }
-
- private static ConstantExpression FoldNumericOperation( ExpressionType nodeType, ConstantExpression leftConst, ConstantExpression rightConst )
- {
- Type commonType;
- object leftValue;
- object rightValue;
-
- if ( leftConst.Type == rightConst.Type )
- {
- commonType = leftConst.Type;
- leftValue = leftConst.Value!;
- rightValue = rightConst.Value!;
- }
- else
- {
- commonType = GetNumericType( leftConst.Type, rightConst.Type );
-
- if ( commonType == null )
- throw new InvalidOperationException( "Incompatible numeric types." );
-
- leftValue = Convert.ChangeType( leftConst.Value, commonType )!;
- rightValue = Convert.ChangeType( rightConst.Value, commonType )!;
- }
-
- return commonType switch
- {
- not null when commonType == typeof( byte ) => ApplyOperation( nodeType, (byte) leftValue, (byte) rightValue ),
- not null when commonType == typeof( sbyte ) => ApplyOperation( nodeType, (sbyte) leftValue, (sbyte) rightValue ),
- not null when commonType == typeof( short ) => ApplyOperation( nodeType, (short) leftValue, (short) rightValue ),
- not null when commonType == typeof( ushort ) => ApplyOperation( nodeType, (ushort) leftValue, (ushort) rightValue ),
- not null when commonType == typeof( int ) => ApplyOperation( nodeType, (int) leftValue, (int) rightValue ),
- not null when commonType == typeof( uint ) => ApplyOperation( nodeType, (uint) leftValue, (uint) rightValue ),
- not null when commonType == typeof( long ) => ApplyOperation( nodeType, (long) leftValue, (long) rightValue ),
- not null when commonType == typeof( ulong ) => ApplyOperation( nodeType, (ulong) leftValue, (ulong) rightValue ),
- not null when commonType == typeof( float ) => ApplyOperation( nodeType, (float) leftValue, (float) rightValue ),
- not null when commonType == typeof( double ) => ApplyOperation( nodeType, (double) leftValue, (double) rightValue ),
- not null when commonType == typeof( decimal ) => ApplyOperation( nodeType, (decimal) leftValue, (decimal) rightValue ),
- _ => throw new InvalidOperationException( "Unsupported type for promoted operation." )
- };
-
- static ConstantExpression ApplyOperation( ExpressionType nodeType, T left, T right ) where T : INumber
- {
- var constant = nodeType switch
- {
- ExpressionType.Add => left + right,
- ExpressionType.Subtract => left - right,
- ExpressionType.Multiply => left * right,
- ExpressionType.Divide => Divide( left, right ),
- _ => throw new InvalidOperationException( $"Unsupported operation {nodeType} for type {typeof( T )}." )
- };
-
- return Expression.Constant( constant );
-
- static T Divide( T left, T right )
- {
- if ( right == T.Zero )
- throw new DivideByZeroException();
-
- return left / right;
- }
- }
- }
-
- private static bool IsNumericType( Type type )
- {
- if ( type == null )
- return false;
-
- return Type.GetTypeCode( type ) switch
- {
- TypeCode.Byte or
- TypeCode.SByte or
- TypeCode.Int16 or
- TypeCode.UInt16 or
- TypeCode.Int32 or
- TypeCode.UInt32 or
- TypeCode.Int64 or
- TypeCode.UInt64 or
- TypeCode.Single or
- TypeCode.Double or
- TypeCode.Decimal => true,
- _ => false
- };
- }
-
- private static readonly TypeCode[] TypeCodePromotionOrder =
- [
- TypeCode.Byte,
- TypeCode.SByte,
- TypeCode.Int16,
- TypeCode.UInt16,
- TypeCode.Int32,
- TypeCode.UInt32,
- TypeCode.Int64,
- TypeCode.UInt64,
- TypeCode.Single,
- TypeCode.Double,
- TypeCode.Decimal
- ];
-
- private static Type GetNumericType( Type leftType, Type rightType )
- {
- var leftCode = Type.GetTypeCode( leftType );
- var rightCode = Type.GetTypeCode( rightType );
-
- if ( leftCode == rightCode )
- return leftType;
-
- var leftIndex = Array.IndexOf( TypeCodePromotionOrder, leftCode );
- var rightIndex = Array.IndexOf( TypeCodePromotionOrder, rightCode );
-
- if ( leftIndex < 0 || rightIndex < 0 )
- return null;
-
- var commonTypeCode = TypeCodePromotionOrder[Math.Max( leftIndex, rightIndex )];
-
- return Type.GetType( "System." + commonTypeCode );
- }
-}
-
-
-
-
diff --git a/src/Hyperbee.Expressions/Optimizers/Visitors/InliningVisitor.cs b/src/Hyperbee.Expressions/Optimizers/Visitors/InliningVisitor.cs
deleted file mode 100644
index 3f26f56..0000000
--- a/src/Hyperbee.Expressions/Optimizers/Visitors/InliningVisitor.cs
+++ /dev/null
@@ -1,117 +0,0 @@
-using System.Linq.Expressions;
-
-namespace Hyperbee.Expressions.Optimizers.Visitors;
-
-// InliningOptimizer: Inlining Functions, Constants, and Conditional Values
-//
-// This optimizer inlines constants and simplifies expressions by propagating known values.
-// It focuses on inlining lambda expressions, boolean short-circuiting, and simplifying conditional
-// expressions based on constant values.
-//
-// Before:
-// .Invoke(lambda, .Constant(5))
-//
-// After:
-// .LambdaExpression(
-// .Parameter(x),
-// .Add(.Constant(5), .Constant(5))
-// )
-//
-// Before:
-// .IfThenElse(.Constant(true), .Constant("True Branch"), .Constant("False Branch"))
-//
-// After:
-// .Constant("True Branch")
-//
-public class InliningVisitor : ExpressionVisitor, IExpressionTransformer
-{
- private ConstantFoldingVisitor ConstantFoldingVisitor { get; } = new();
-
- public int Priority => PriorityGroup.ControlFlowAndVariableSimplification + 30;
-
- public Expression Transform( Expression expression )
- {
- return Visit( expression );
- }
-
- protected override Expression VisitBinary( BinaryExpression node )
- {
- // Visit left and right nodes to apply inlining or other optimizations
- var left = Visit( node.Left );
- var right = Visit( node.Right );
-
- // Handle short-circuiting for `AndAlso` and `OrElse`
- if ( node.NodeType == ExpressionType.AndAlso || node.NodeType == ExpressionType.OrElse )
- {
- if ( left is ConstantExpression leftConst && leftConst.Value is bool leftBool )
- {
- // Short-circuit based on left value
- return (node.NodeType, leftBool) switch
- {
- (ExpressionType.AndAlso, true ) => ConstantFoldingVisitor.Visit( right ),
- (ExpressionType.AndAlso, false ) => Expression.Constant( false ),
- (ExpressionType.OrElse, true ) => Expression.Constant( true ),
- (ExpressionType.OrElse, false ) => ConstantFoldingVisitor.Visit( right ),
- _ => node.Update( left, node.Conversion, right )
- };
- }
- }
-
- // If both sides are constants, and it's not a logical short-circuit case, try folding directly
- if ( left is ConstantExpression && right is ConstantExpression )
- {
- return ConstantFoldingVisitor.Visit( Expression.MakeBinary( node.NodeType, left, right ) );
- }
-
- return node.Update( left, node.Conversion, right );
- }
-
- protected override Expression VisitInvocation( InvocationExpression node )
- {
- if ( node.Expression is LambdaExpression lambda )
- {
- // Inline lambda expressions by replacing parameters with arguments
- var argumentMap = lambda.Parameters
- .Zip( node.Arguments, ( parameter, argument ) => (parameter, argument) )
- .ToDictionary( pair => pair.parameter, pair => pair.argument );
-
- var inlinedBody = new ParameterReplacer( argumentMap ).Visit( lambda.Body );
- return ConstantFoldingVisitor.Visit( inlinedBody ); // Apply folding after inlining
- }
-
- return base.VisitInvocation( node );
- }
-
- protected override Expression VisitConditional( ConditionalExpression node )
- {
- // Evaluate conditional expressions with constant test conditions
- var test = Visit( node.Test );
- var ifTrue = Visit( node.IfTrue );
- var ifFalse = Visit( node.IfFalse );
-
- if ( test is ConstantExpression constTest && constTest.Value is bool condition )
- {
- var result = condition ? ifTrue : ifFalse;
- return ConstantFoldingVisitor.Visit( result ); // Apply folding after resolving the condition
- }
-
- return node.Update( test, ifTrue, ifFalse );
- }
-
- // Helper class for inlining: replaces parameters with arguments
- private class ParameterReplacer : ExpressionVisitor
- {
- private readonly Dictionary _replacements;
-
- public ParameterReplacer( Dictionary replacements )
- {
- _replacements = replacements;
- }
-
- protected override Expression VisitParameter( ParameterExpression node )
- {
- return _replacements.TryGetValue( node, out var replacement ) ? replacement : base.VisitParameter( node );
- }
- }
-}
-
diff --git a/src/Hyperbee.Expressions/Optimizers/Visitors/MemberAccessVisitor.cs b/src/Hyperbee.Expressions/Optimizers/Visitors/MemberAccessVisitor.cs
deleted file mode 100644
index 12cf05b..0000000
--- a/src/Hyperbee.Expressions/Optimizers/Visitors/MemberAccessVisitor.cs
+++ /dev/null
@@ -1,73 +0,0 @@
-using System.Linq.Expressions;
-using System.Reflection;
-
-namespace Hyperbee.Expressions.Optimizers.Visitors;
-
-// MemberAccessVisitor: Constant Field and Property Access Simplification
-//
-// This visitor simplifies member access by precomputing values for constant fields or
-// properties. When a field or property is accessed through a constant object, it evaluates
-// the expression and replaces it with the value.
-//
-// Before:
-// .MemberAccess(.Constant(obj), Property)
-//
-// After:
-// .Constant(value)
-//
-public class MemberAccessVisitor : ExpressionVisitor, IExpressionTransformer
-{
- public int Priority => PriorityGroup.ConstantEvaluationAndSimplification + 20;
-
- public Expression Transform( Expression expression )
- {
- return Visit( expression );
- }
-
- protected override Expression VisitMember( MemberExpression node )
- {
- node = (MemberExpression) base.VisitMember( node );
-
- if ( node.Expression is not ConstantExpression constExpr )
- {
- return node;
- }
-
- switch ( node.Member )
- {
- case FieldInfo fieldInfo:
- var fieldValue = fieldInfo.GetValue( constExpr.Value );
- return Expression.Constant( fieldValue, node.Type );
-
- case PropertyInfo propertyInfo when propertyInfo.CanRead:
- var propertyValue = propertyInfo.GetMethod!.IsStatic
- ? propertyInfo.GetValue( null )
- : propertyInfo.GetValue( constExpr.Value );
- return Expression.Constant( propertyValue, node.Type );
-
- default:
- return node;
- }
- }
-
- protected override Expression VisitBinary( BinaryExpression node )
- {
- if ( node.NodeType != ExpressionType.Coalesce || node.Left is not ConstantExpression leftConst || leftConst.Value != null )
- {
- return base.VisitBinary( node );
- }
-
- return Visit( node.Right );
- }
-
- protected override Expression VisitIndex( IndexExpression node )
- {
- if ( node.Object is not ConstantExpression constantArray || constantArray.Value is not Array array || node.Arguments[0] is not ConstantExpression indexExpr )
- {
- return base.VisitIndex( node );
- }
-
- var index = (int) indexExpr.Value!;
- return Expression.Constant( array.GetValue( index ), node.Type );
- }
-}
diff --git a/src/Hyperbee.Expressions/Optimizers/Visitors/OperatorReductionVisitor.cs b/src/Hyperbee.Expressions/Optimizers/Visitors/OperatorReductionVisitor.cs
deleted file mode 100644
index 5b57370..0000000
--- a/src/Hyperbee.Expressions/Optimizers/Visitors/OperatorReductionVisitor.cs
+++ /dev/null
@@ -1,176 +0,0 @@
-using System.Linq.Expressions;
-
-namespace Hyperbee.Expressions.Optimizers.Visitors;
-
-// OperatorReductionVisitor: Arithmetic and Logical Operator Reduction
-//
-// This visitor eliminates trivial arithmetic expressions (like adding zero, multiplying by one),
-// simplifies logical identities (like x && true or x || false), and flattens nested expressions
-// where applicable.
-//
-// Examples:
-//
-// Before:
-// .Add(.Parameter(x), .Constant(0))
-//
-// After:
-// .Parameter(x)
-//
-// Before:
-// .Multiply(.Parameter(x), .Constant(1))
-//
-// After:
-// .Parameter(x)
-//
-// Before:
-// .Add(.Add(.Parameter(x), .Parameter(y)), .Parameter(z))
-//
-// After:
-// .Add(.Parameter(x), .Parameter(y), .Parameter(z))
-//
-public class OperatorReductionVisitor : ExpressionVisitor, IExpressionTransformer
-{
- public int Priority => PriorityGroup.ExpressionReductionAndCaching + 60;
-
- public Expression Transform( Expression expression )
- {
- return Visit( expression );
- }
-
- protected override Expression VisitBinary( BinaryExpression node )
- {
- // Recursively visit left and right nodes to ensure optimizations
- // are applied in subexpressions first
-
- var left = Visit( node.Left );
- var right = Visit( node.Right );
-
- // Apply trivial arithmetic and logical simplifications
-
- switch ( node.NodeType )
- {
- // Arithmetic simplifications
- case ExpressionType.Add:
- case ExpressionType.Subtract:
- {
- if ( right is ConstantExpression rightConst && rightConst.Value is int rightVal )
- {
- // x + 0 or x - 0
- if ( rightVal == 0 )
- return left;
- }
-
- if ( node.NodeType == ExpressionType.Add && left is ConstantExpression leftConst && leftConst.Value is int leftValue )
- {
- // 0 + x
- if ( leftValue == 0 )
- return right;
- }
-
- break;
- }
-
- case ExpressionType.Multiply:
- {
- if ( right is ConstantExpression rightConst && rightConst.Value is int rightValue )
- {
- // x * 1
- if ( rightValue == 1 )
- return left;
-
- // x * 0
- if ( rightValue == 0 )
- return Expression.Constant( 0 );
- }
-
- if ( left is ConstantExpression leftConst && leftConst.Value is int leftValue )
- {
- // 1 * x
- if ( leftValue == 1 )
- return right;
-
- // 0 * x
- if ( leftValue == 0 )
- return Expression.Constant( 0 );
- }
-
- break;
- }
-
- // Logical short-circuiting for `&& true`, `|| false`, etc.
- case ExpressionType.AndAlso:
- {
- // x && true or true && x
- if ( right is ConstantExpression rightConst && rightConst.Value is bool rightValue && rightValue )
- return left;
-
- if ( left is ConstantExpression leftConst && leftConst.Value is bool leftValue && leftValue )
- return right;
-
- // false && x or x && false
- if ( left is ConstantExpression lConstAndFalse && lConstAndFalse.Value is bool leftValAndFalse && !leftValAndFalse ||
- right is ConstantExpression rConstAndFalse && rConstAndFalse.Value is bool rightValAndFalse && !rightValAndFalse )
- return Expression.Constant( false );
-
- break;
- }
-
- case ExpressionType.OrElse:
- {
- // x || false or false || x
- if ( right is ConstantExpression rightConst && rightConst.Value is bool rightValue && !rightValue )
- return left;
-
- if ( left is ConstantExpression leftConst && leftConst.Value is bool leftValue && !leftValue )
- return right;
-
- // true || x or x || true
- if ( left is ConstantExpression lConstOrTrue && lConstOrTrue.Value is bool leftValOrTrue && leftValOrTrue ||
- right is ConstantExpression rConstOrTrue && rConstOrTrue.Value is bool rightValOrTrue && rightValOrTrue )
- return Expression.Constant( true );
-
- break;
- }
- }
-
- if ( node.NodeType != ExpressionType.Add && node.NodeType != ExpressionType.Multiply )
- {
- return node.Update( left, node.Conversion, right );
- }
-
- // Handle nested expression flattening specifically for `Add` and `Multiply`
-
- // Collect terms for the node and recursively flatten if necessary
- var allTerms = FlattenBinaryExpression( node, node.NodeType ).ToList();
-
- // Aggregate constants in the list (e.g., sum all constants for `Add`)
- var constants = allTerms.OfType().ToList();
- var otherTerms = allTerms.Except( constants ).ToList();
-
- if ( constants.Count <= 0 )
- {
- return otherTerms.Aggregate( ( acc, term ) => Expression.MakeBinary( node.NodeType, acc, term ) );
- }
-
- // Sum or multiply the constant values based on node type
- var constantResult = node.NodeType switch
- {
- ExpressionType.Add => constants.Sum( c => (int) c.Value! ),
- _ => constants.Aggregate( 1, ( acc, c ) => acc * (int) c.Value! )
- };
-
- otherTerms.Insert( 0, Expression.Constant( constantResult ) );
-
- return otherTerms.Aggregate( ( acc, term ) => Expression.MakeBinary( node.NodeType, acc, term ) );
- }
-
- private static IEnumerable FlattenBinaryExpression( Expression expr, ExpressionType type )
- {
- if ( expr is BinaryExpression binary && binary.NodeType == type )
- {
- return FlattenBinaryExpression( binary.Left, type ).Concat( FlattenBinaryExpression( binary.Right, type ) );
- }
-
- return [expr];
- }
-}
diff --git a/src/Hyperbee.Expressions/Optimizers/Visitors/StructuralReductionVisitor.cs b/src/Hyperbee.Expressions/Optimizers/Visitors/StructuralReductionVisitor.cs
deleted file mode 100644
index f970b47..0000000
--- a/src/Hyperbee.Expressions/Optimizers/Visitors/StructuralReductionVisitor.cs
+++ /dev/null
@@ -1,127 +0,0 @@
-using System.Linq.Expressions;
-
-namespace Hyperbee.Expressions.Optimizers.Visitors;
-
-public class StructuralReductionVisitor : ExpressionVisitor, IExpressionTransformer
-{
- public int Priority => PriorityGroup.StructuralReductionAndConsolidation + 50;
-
- public Expression Transform( Expression expression )
- {
- return Visit( expression );
- }
-
- // Visit BlockExpression, handling block flattening and reduction
- protected override Expression VisitBlock( BlockExpression node )
- {
- var variables = new List();
- var expressions = new List();
-
- foreach ( var expr in node.Expressions )
- {
- var visitedExpr = Visit( expr );
-
- // Skip over no-op expressions and empty blocks
- if ( IsNoOpExpression( visitedExpr ) )
- continue;
-
- // Flatten nested blocks
- if ( visitedExpr is BlockExpression nestedBlock )
- {
- variables.AddRange( nestedBlock.Variables );
- expressions.AddRange( nestedBlock.Expressions );
- }
- else
- {
- expressions.Add( visitedExpr );
- }
- }
-
- // Remove single-use blocks
- return expressions.Count == 1 ? expressions[0] : Expression.Block( variables, expressions );
- }
-
- // Visit GotoExpression, eliminating redundant Goto expressions
- protected override Expression VisitGoto( GotoExpression node )
- {
- if ( IsNoOpExpression( node.Value ) )
- {
- return Expression.Empty(); // Skip no-op Gotos
- }
-
- return base.VisitGoto( node );
- }
-
- // Visit LoopExpression, optimizing based on loop content
- protected override Expression VisitLoop( LoopExpression node )
- {
- var visitedBody = Visit( node.Body );
-
- if ( IsFalsyConstant( visitedBody ) || IsNoOpExpression( visitedBody ) || IsEffectivelyInfiniteNoOpLoop( visitedBody ) )
- {
- return node.Type == typeof( void ) ? Expression.Empty() : Expression.Default( node.Type );
- }
-
- return ReferenceEquals( node.Body, visitedBody )
- ? node
- : Expression.Loop( visitedBody, node.BreakLabel, node.ContinueLabel );
- }
-
- // Visit ConditionalExpression, simplifying based on constant conditions
- protected override Expression VisitConditional( ConditionalExpression node )
- {
- var test = Visit( node.Test );
-
- if ( test is ConstantExpression constantTest && constantTest.Value is bool boolTest )
- {
- // Replace based on constant true or false
- return boolTest ? Visit( node.IfTrue ) : Visit( node.IfFalse );
- }
-
- return node.Update( test, Visit( node.IfTrue ), Visit( node.IfFalse ) );
- }
-
- // Visit TryCatchExpression, simplifying empty or no-op TryCatch blocks
- protected override Expression VisitTry( TryExpression node )
- {
- var body = Visit( node.Body );
-
- // Remove Try if catches are no-ops or finally has no effect
- if ( node.Handlers.All( handler => IsNoOpExpression( handler.Body ) ) && (node.Finally == null || IsNoOpExpression( node.Finally )) )
- {
- return body;
- }
-
- return node.Update( body, node.Handlers, node.Finally, node.Fault );
- }
-
- // Helper methods for loop reduction and simplification
- private static bool IsFalsyConstant( Expression expression )
- {
- return expression is ConstantExpression constant && constant.Value switch
- {
- null => true,
- bool boolValue => !boolValue,
- int intValue => intValue == 0,
- double doubleValue => doubleValue == 0.0,
- float floatValue => floatValue == 0.0f,
- _ => false
- };
- }
-
- private static bool IsNoOpExpression( Expression expression )
- {
- return expression is DefaultExpression ||
- (expression is BlockExpression block && block.Expressions.All( IsNoOpExpression ));
- }
-
- private static bool IsEffectivelyInfiniteNoOpLoop( Expression expression )
- {
- return expression is ConstantExpression && !HasControlFlowOrSideEffects( expression );
- }
-
- private static bool HasControlFlowOrSideEffects( Expression expression )
- {
- return expression is not ConstantExpression;
- }
-}
diff --git a/src/Hyperbee.Expressions/Optimizers/Visitors/SubexpressionCachingVisitor.cs b/src/Hyperbee.Expressions/Optimizers/Visitors/SubexpressionCachingVisitor.cs
deleted file mode 100644
index 74b1a49..0000000
--- a/src/Hyperbee.Expressions/Optimizers/Visitors/SubexpressionCachingVisitor.cs
+++ /dev/null
@@ -1,181 +0,0 @@
-using System.Linq.Expressions;
-using Hyperbee.Expressions.Visitors;
-
-namespace Hyperbee.Expressions.Optimizers.Visitors;
-
-// SubexpressionCachingVisitor: Subexpression Caching
-//
-// This optimizer performs subexpression caching to reduce repeated computation in complex expressions.
-// By identifying and reusing common subexpressions, it improves execution efficiency, especially in cases
-// where identical subexpressions are evaluated multiple times within an expression tree.
-//
-// This optimizer works in multiple phases:
-// * Fingerprinting: Each expression is traversed to create a unique "fingerprint" for subexpressions.
-// * Deferred Caching: Subexpressions deemed "complex enough" are queued for caching. This ensures
-// that only the necessary subexpressions are cached and that simple expressions remain unchanged.
-// * Block Wrapping: Cached expressions are assigned to variables in a `BlockExpression`, which groups
-// these assignments and ensures variables are reused wherever possible.
-//
-// Example:
-//
-// Before Optimization:
-//
-// .Lambda #Lambda1 {
-// 5 * (3 + 2) + 5 * (3 + 2)
-// }
-//
-// After Optimization:
-//
-// .Lambda #Lambda1 {
-// .Block(System.Int32 $cacheVar) {
-// $cacheVar = 5 * (3 + 2);
-// $cacheVar + $cacheVar
-// }
-// }
-//
-// In this example, the optimizer identifies the subexpression `5 * (3 + 2)` as a repeated, cacheable part.
-// It creates a variable `$cacheVar` to hold the computed value of `5 * (3 + 2)`, and replaces occurrences
-// of this subexpression with `$cacheVar` in the resulting `BlockExpression`. This optimization reduces
-// redundant calculations, resulting in a more efficient expression execution.
-
-public class SubexpressionCachingVisitor : ExpressionVisitor, IExpressionTransformer
-{
- private readonly Dictionary _fingerprintCache = new( new ByteArrayComparer() );
- private readonly Dictionary _cacheVariables = new( new ByteArrayComparer() );
- private readonly Queue<(Expression Original, ParameterExpression Variable)> _deferredReplacements = new();
-
- private readonly ExpressionFingerprinter _fingerprinter = new();
-
- public int Priority => PriorityGroup.ExpressionReductionAndCaching + 70;
-
- public Expression Transform( Expression expression )
- {
- _deferredReplacements.Clear();
- var visitedExpression = Visit( expression );
-
- if ( _deferredReplacements.Count == 0 )
- {
- return visitedExpression;
- }
-
- var blockExpressions = new List();
- var variables = new List();
-
- while ( _deferredReplacements.Count > 0 )
- {
- var (original, cacheVariable) = _deferredReplacements.Dequeue();
-
- if ( variables.Contains( cacheVariable ) )
- {
- continue;
- }
-
- variables.Add( cacheVariable );
- blockExpressions.Add( Expression.Assign( cacheVariable, original ) );
- }
-
- if ( visitedExpression is LambdaExpression lambda )
- {
- blockExpressions.Add( lambda.Body );
- var lambdaResult = Expression.Lambda( lambda.Type, Expression.Block( variables, blockExpressions ), lambda.Parameters );
- return lambdaResult;
- }
-
- blockExpressions.Add( visitedExpression );
- return Expression.Block( variables, blockExpressions );
- }
-
- public override Expression Visit( Expression node )
- {
- var visited = base.Visit( node );
- return ResolveExpression( node, visited );
- }
-
- private Expression ResolveExpression( Expression original, Expression visitedNode )
- {
- if ( !ReferenceEquals( original, visitedNode ) || !IsComplexEnoughToCache( visitedNode ) )
- {
- return visitedNode;
- }
-
- var fingerprint = _fingerprinter.ComputeFingerprint( visitedNode );
-
- if ( !_fingerprintCache.TryGetValue( fingerprint, out var cachedNode ) )
- {
- _fingerprintCache[fingerprint] = visitedNode;
- cachedNode = visitedNode;
- }
-
- if ( _cacheVariables.TryGetValue( fingerprint, out var cacheVariable ) )
- {
- return cacheVariable;
- }
-
- cacheVariable = Expression.Variable( cachedNode.Type, "cacheVar" );
- _cacheVariables[fingerprint] = cacheVariable;
- _deferredReplacements.Enqueue( (visitedNode, cacheVariable) );
-
- return cacheVariable;
- }
-
- private static bool IsComplexEnoughToCache( Expression node )
- {
- return node switch
- {
- BinaryExpression binary =>
- (binary.Left is not ConstantExpression || binary.Right is not ConstantExpression) &&
- (IsComplexEnoughToCache( binary.Left ) ||
- IsComplexEnoughToCache( binary.Right ) ||
- binary.NodeType is
- ExpressionType.Add or
- ExpressionType.Multiply or
- ExpressionType.Divide or
- ExpressionType.Subtract
- ),
-
- MethodCallExpression or MemberExpression or InvocationExpression => true,
- UnaryExpression unary => unary.Operand is not ConstantExpression && IsComplexEnoughToCache( unary.Operand ),
- BlockExpression block => block.Expressions.Count > 1,
- ConditionalExpression or NewExpression or NewArrayExpression => true,
- LambdaExpression lambda => lambda.Parameters.Count > 0 || IsComplexEnoughToCache( lambda.Body ),
- MemberInitExpression or ListInitExpression or IndexExpression => true,
- ConstantExpression => false,
- _ => false
- };
- }
-
- private class ByteArrayComparer : IEqualityComparer
- {
- public bool Equals( byte[] x, byte[] y )
- {
- if ( ReferenceEquals( x, y ) )
- return true;
-
- if ( x == null || y == null )
- return false;
-
- if ( x.Length != y.Length )
- return false;
-
- for ( var i = 0; i < x.Length; i++ )
- {
- if ( x[i] != y[i] )
- return false;
- }
-
- return true;
- }
-
- public int GetHashCode( byte[] bytes )
- {
- var hash = 17;
-
- foreach ( var x in bytes )
- {
- hash = hash * 31 + x;
- }
-
- return hash;
- }
- }
-}
diff --git a/src/Hyperbee.Expressions/Optimizers/Visitors/VariableReducerVisitor.cs b/src/Hyperbee.Expressions/Optimizers/Visitors/VariableReducerVisitor.cs
deleted file mode 100644
index cf3727a..0000000
--- a/src/Hyperbee.Expressions/Optimizers/Visitors/VariableReducerVisitor.cs
+++ /dev/null
@@ -1,126 +0,0 @@
-using System.Linq.Expressions;
-
-namespace Hyperbee.Expressions.Optimizers.Visitors;
-
-// VariableReducerVisitor: Inlining and Memory Optimization
-//
-// This visitor combines inlining and memory optimization by inlining single-use variables, removing unused
-// variables, and reusing parameters where possible. This helps in reducing both memory usage and
-// unnecessary assignments, making the code more efficient.
-//
-// Example Transformations:
-// Before:
-// .Block(
-// .Assign(.Parameter(x), .Constant(5)),
-// .Add(.Parameter(x), .Parameter(x))
-// )
-//
-// After:
-// .Add(.Constant(5), .Constant(5))
-//
-// Before:
-// .Block(
-// .Assign(.Parameter(temp), .Constant(42)),
-// .Parameter(temp)
-// )
-//
-// After:
-// .Constant(42)
-
-public class VariableReducerVisitor : ExpressionVisitor, IExpressionTransformer
-{
- private readonly Dictionary _replacements = new();
- private readonly Dictionary _reusedParameters = new();
- private readonly HashSet _uniqueVariables = [];
-
- public int Priority => PriorityGroup.ControlFlowAndVariableSimplification + 40;
-
- public Expression Transform( Expression expression )
- {
- _replacements.Clear();
- _reusedParameters.Clear();
- _uniqueVariables.Clear();
-
- return Visit( expression );
- }
-
- protected override Expression VisitBlock( BlockExpression node )
- {
- //var variables = new List();
- var expressions = new List();
- var variableUsageCount = new Dictionary();
-
- // Count usages and track replacements for inlining
- foreach ( var expr in node.Expressions )
- {
- if ( expr is BinaryExpression binaryExpr && binaryExpr.NodeType == ExpressionType.Assign &&
- binaryExpr.Left is ParameterExpression variable )
- {
- variableUsageCount.TryAdd( variable, 0 );
- variableUsageCount[variable]++;
- _replacements[variable] = binaryExpr.Right;
- }
- }
-
- // Inline or retain variables based on usage
- foreach ( var expr in node.Expressions )
- {
- switch ( expr )
- {
- case BinaryExpression binaryExpr when binaryExpr.NodeType == ExpressionType.Assign &&
- binaryExpr.Left is ParameterExpression variable:
- if ( variableUsageCount[variable] == 1 && _replacements[variable] is ConstantExpression )
- {
- // Inline single-use constant assignments
- expressions.Add( Visit( _replacements[variable] ) );
- }
- else
- {
- _uniqueVariables.Add( variable );
- //variables.Add(variable);
- expressions.Add( Visit( expr ) );
- }
- break;
- default:
- expressions.Add( Visit( expr ) );
- break;
- }
- }
-
- // Remove unused variables and consolidate variable declarations
- var finalVariables = new List( _uniqueVariables );
-
- return finalVariables.Count == 0 ? expressions.Last() : Expression.Block( finalVariables, expressions );
- }
-
- protected override Expression VisitParameter( ParameterExpression node )
- {
- // Reuse parameters if already processed
- if ( _reusedParameters.TryGetValue( node, out var reusedParam ) )
- {
- return reusedParam;
- }
-
- if ( _replacements.TryGetValue( node, out var replacement ) )
- {
- return Visit( replacement );
- }
-
- _reusedParameters[node] = node;
- return base.VisitParameter( node );
- }
-
- protected override Expression VisitLoop( LoopExpression node )
- {
- var visitedBody = Visit( node.Body );
-
- if ( ReferenceEquals( visitedBody, node.Body ) )
- return node;
-
- if ( visitedBody is ConstantExpression constantBody )
- return constantBody;
-
- return visitedBody;
- }
-}
-
diff --git a/src/Hyperbee.Expressions/Transformation/NodeExpression.cs b/src/Hyperbee.Expressions/Transformation/NodeExpression.cs
index d5b38b3..dfd62ec 100644
--- a/src/Hyperbee.Expressions/Transformation/NodeExpression.cs
+++ b/src/Hyperbee.Expressions/Transformation/NodeExpression.cs
@@ -39,33 +39,19 @@ public NodeExpression( int stateId, int scopeId, int groupId )
public bool IsNoOp => Expressions.Count == 0 && ResultVariable == null;
- protected override Expression VisitChildren( ExpressionVisitor visitor )
- {
- return Update(
- Expressions.Select( visitor.Visit ).ToList(),
- visitor.Visit( ResultValue ),
- visitor.Visit( ResultVariable ),
- (Transition) visitor.Visit( Transition )
- );
- }
-
- private Expression Update( List expressions, Expression resultValue, Expression resultVariable, Transition transition )
- {
- Expressions = expressions;
- ResultValue = resultValue;
- ResultVariable = resultVariable;
- Transition = transition;
-
- return this;
- }
-
public override Expression Reduce()
{
if ( StateMachineSource == null )
throw new InvalidOperationException( $"Reduce requires an {nameof( Transformation.StateMachineSource )} instance." );
- Transition.Parent = this;
- return Transition.Reduce();
+ var expressions = new List( 8 ) { Label( NodeLabel ) };
+ expressions.AddRange( Expressions );
+
+ Transition.AddExpressions( this, expressions );
+
+ return expressions.Count == 1
+ ? expressions[0]
+ : Block( expressions );
}
internal static List Merge( List nodes ) //BF ME - not sure if this is the right place or not
diff --git a/src/Hyperbee.Expressions/Transformation/StateMachineBuilder.cs b/src/Hyperbee.Expressions/Transformation/StateMachineBuilder.cs
index edc9068..29b9b8e 100644
--- a/src/Hyperbee.Expressions/Transformation/StateMachineBuilder.cs
+++ b/src/Hyperbee.Expressions/Transformation/StateMachineBuilder.cs
@@ -331,16 +331,6 @@ FieldInfo[] fields
var exitLabel = Label( "ST_EXIT" );
- // Optimize source nodes
-
- StateMachineOptimizer.Optimize( source );
-
- // Variable Hoisting
-
- HoistVariables( source, fields, stateMachine );
-
- // Assign state-machine source to nodes
-
var stateMachineSource = new StateMachineSource(
stateMachine,
exitLabel,
@@ -350,14 +340,9 @@ FieldInfo[] fields
source.ReturnValue
);
- foreach ( var node in source.Nodes )
- {
- node.StateMachineSource = stateMachineSource; // required for node reducers
- }
-
- // Add the state-nodes
+ // Create the body expressions
- var bodyExpressions = CreateBody( stateField, source );
+ var bodyExpressions = CreateBody( fields, source, stateMachineSource );
// Add the final builder result assignment
@@ -374,70 +359,86 @@ FieldInfo[] fields
)
] );
- // Create a try-catch block to handle exceptions
+ // Create final lambda with try-catch block
var exceptionParam = Parameter( typeof( Exception ), "ex" );
- var tryCatchBlock = TryCatch(
- Block(
- typeof( void ),
- source.ReturnValue != null
- ? [source.ReturnValue]
- : [],
- bodyExpressions
- ),
- Catch(
- exceptionParam,
- Block(
- Assign( stateField, Constant( -2 ) ),
- Call(
- builderField,
- nameof( AsyncTaskMethodBuilder.SetException ),
- null,
- exceptionParam
- )
- )
- )
- );
-
- // Create the final lambda expression
-
return Lambda(
typeof( MoveNextDelegate<> ).MakeGenericType( stateMachineType ),
Block(
- tryCatchBlock,
+ TryCatch(
+ Block(
+ typeof( void ),
+ source.ReturnValue != null
+ ? [source.ReturnValue]
+ : [],
+ bodyExpressions
+ ),
+ Catch(
+ exceptionParam,
+ Block(
+ Assign( stateField, Constant( -2 ) ),
+ Call(
+ builderField,
+ nameof( AsyncTaskMethodBuilder.SetException ),
+ null,
+ exceptionParam
+ )
+ )
+ )
+ ),
Label( exitLabel )
),
stateMachine
);
}
- private static List CreateBody( MemberExpression stateField, LoweringResult source )
+ private static List CreateBody( FieldInfo[] fields, LoweringResult source, StateMachineSource stateMachineSource )
{
+ // Optimize source nodes
+
+ StateMachineOptimizer.Optimize( source );
+
+ // Assign state-machine source to nodes (required for node reducers)
+
+ foreach ( var node in source.Nodes )
+ {
+ node.StateMachineSource = stateMachineSource;
+ }
+
+ // Create the body expressions
+
var firstScope = source.Scopes.First();
var jumpTable = JumpTableBuilder.Build(
firstScope,
source.Scopes,
- stateField
+ stateMachineSource.StateIdField
);
- return [jumpTable, Block( NodeExpression.Merge( firstScope.Nodes ) )]; //BF ME
+ var bodyBlock = Block( NodeExpression.Merge( firstScope.Nodes ) );
+
+ // hoist variables
+
+ var bodyExpressions = HoistVariables(
+ [jumpTable, bodyBlock],
+ fields,
+ stateMachineSource.StateMachine
+ );
+
+ return bodyExpressions;
}
- [MethodImpl( MethodImplOptions.AggressiveInlining )]
- private static void HoistVariables( LoweringResult source, FieldInfo[] fields, ParameterExpression stateMachine )
+ private static List HoistVariables( List expressions, FieldInfo[] fields, ParameterExpression stateMachine )
{
var fieldMembers = fields
.Select( field => Field( stateMachine, field ) )
.ToDictionary( x => x.Member.Name );
var hoistingVisitor = new HoistingVisitor( fieldMembers );
+ var hoisted = expressions.Select( hoistingVisitor.Visit ).ToList();
- foreach ( var node in source.Nodes )
- {
- hoistingVisitor.Visit( node );
- }
+ return hoisted;
}
private sealed class HoistingVisitor( IDictionary memberExpressions ) : ExpressionVisitor
diff --git a/src/Hyperbee.Expressions/Transformation/Transitions/AwaitResultTransition.cs b/src/Hyperbee.Expressions/Transformation/Transitions/AwaitResultTransition.cs
index 7753ddb..d5b4f7f 100644
--- a/src/Hyperbee.Expressions/Transformation/Transitions/AwaitResultTransition.cs
+++ b/src/Hyperbee.Expressions/Transformation/Transitions/AwaitResultTransition.cs
@@ -1,4 +1,5 @@
using System.Linq.Expressions;
+using static System.Linq.Expressions.Expression;
namespace Hyperbee.Expressions.Transformation.Transitions;
@@ -11,33 +12,12 @@ internal class AwaitResultTransition : Transition
internal override NodeExpression FallThroughNode => TargetNode;
- protected override Expression VisitChildren( ExpressionVisitor visitor )
+ protected override void SetBody( List expressions, NodeExpression parent )
{
- return Update(
- visitor.Visit( AwaiterVariable ),
- visitor.Visit( ResultVariable )
- );
- }
-
- internal AwaitResultTransition Update( Expression awaiterVariable, Expression resultVariable )
- {
- if ( awaiterVariable == AwaiterVariable && resultVariable == ResultVariable )
- return this;
-
- return new AwaitResultTransition
- {
- AwaiterVariable = awaiterVariable,
- ResultVariable = resultVariable,
- TargetNode = TargetNode,
- AwaitBinder = AwaitBinder
- };
- }
-
- protected override List GetBody()
- {
- return GetExpressions();
+ expressions.AddRange( Expressions() );
+ return;
- List GetExpressions()
+ List Expressions()
{
var getResultMethod = AwaitBinder.GetResultMethod;
@@ -47,20 +27,49 @@ List GetExpressions()
if ( ResultVariable == null )
{
- var transition = GotoOrFallThrough( Parent.StateOrder, TargetNode );
+ var transition = GotoOrFallThrough( parent.StateOrder, TargetNode );
return transition == Empty()
? [getResultCall]
: [getResultCall, transition];
}
- return [
+ return
+ [
Assign( ResultVariable, getResultCall ),
- GotoOrFallThrough( Parent.StateOrder, TargetNode )
+ GotoOrFallThrough( parent.StateOrder, TargetNode )
];
}
}
+ //protected override List GetBody(NodeExpression parent )
+ //{
+ // return GetExpressions();
+
+ // List GetExpressions()
+ // {
+ // var getResultMethod = AwaitBinder.GetResultMethod;
+
+ // var getResultCall = getResultMethod.IsStatic
+ // ? Call( getResultMethod, AwaiterVariable )
+ // : Call( Constant( AwaitBinder ), getResultMethod, AwaiterVariable );
+
+ // if ( ResultVariable == null )
+ // {
+ // var transition = GotoOrFallThrough( parent.StateOrder, TargetNode );
+
+ // return transition == Empty()
+ // ? [getResultCall]
+ // : [getResultCall, transition];
+ // }
+
+ // return [
+ // Assign( ResultVariable, getResultCall ),
+ // GotoOrFallThrough( parent.StateOrder, TargetNode )
+ // ];
+ // }
+ //}
+
internal override void Optimize( HashSet references )
{
TargetNode = OptimizeGotos( TargetNode );
diff --git a/src/Hyperbee.Expressions/Transformation/Transitions/AwaitTransition.cs b/src/Hyperbee.Expressions/Transformation/Transitions/AwaitTransition.cs
index 6a0b2bf..6e88943 100644
--- a/src/Hyperbee.Expressions/Transformation/Transitions/AwaitTransition.cs
+++ b/src/Hyperbee.Expressions/Transformation/Transitions/AwaitTransition.cs
@@ -1,4 +1,5 @@
using System.Linq.Expressions;
+using static System.Linq.Expressions.Expression;
namespace Hyperbee.Expressions.Transformation.Transitions;
@@ -14,37 +15,14 @@ internal class AwaitTransition : Transition
internal override NodeExpression FallThroughNode => CompletionNode;
- protected override Expression VisitChildren( ExpressionVisitor visitor )
+ protected override void SetBody( List expressions, NodeExpression parent )
{
- return Update(
- visitor.Visit( Target ),
- visitor.Visit( AwaiterVariable )
- );
- }
-
- internal AwaitTransition Update( Expression target, Expression awaiterVariable )
- {
- if ( target == Target && awaiterVariable == AwaiterVariable )
- return this;
-
- return new AwaitTransition
- {
- StateId = StateId,
- Target = target,
- AwaiterVariable = awaiterVariable,
- CompletionNode = CompletionNode,
- AwaitBinder = AwaitBinder,
- ConfigureAwait = ConfigureAwait
- };
- }
-
- protected override List GetBody()
- {
- return GetExpressions();
+ expressions.AddRange( Expressions() );
+ return;
- List GetExpressions()
+ List Expressions()
{
- var resolverSource = Parent.StateMachineSource;
+ var resolverSource = parent.StateMachineSource;
var getAwaiterMethod = AwaitBinder.GetAwaiterMethod;
var getAwaiterCall = getAwaiterMethod.IsStatic
@@ -78,7 +56,7 @@ List GetExpressions()
)
};
- var fallThrough = GotoOrFallThrough( Parent.StateOrder, CompletionNode, true );
+ var fallThrough = GotoOrFallThrough( parent.StateOrder, CompletionNode, true );
if ( fallThrough != null )
body.Add( fallThrough );
diff --git a/src/Hyperbee.Expressions/Transformation/Transitions/ConditionalTransition.cs b/src/Hyperbee.Expressions/Transformation/Transitions/ConditionalTransition.cs
index 954c14e..fd92a64 100644
--- a/src/Hyperbee.Expressions/Transformation/Transitions/ConditionalTransition.cs
+++ b/src/Hyperbee.Expressions/Transformation/Transitions/ConditionalTransition.cs
@@ -1,4 +1,5 @@
using System.Linq.Expressions;
+using static System.Linq.Expressions.Expression;
namespace Hyperbee.Expressions.Transformation.Transitions;
@@ -10,31 +11,14 @@ internal class ConditionalTransition : Transition
internal override NodeExpression FallThroughNode => IfFalse;
- protected override Expression VisitChildren( ExpressionVisitor visitor )
+ protected override void SetBody( List expressions, NodeExpression parent )
{
- return Update( visitor.Visit( Test ) );
- }
-
- internal ConditionalTransition Update( Expression test )
- {
- if ( test == Test )
- return this;
-
- return new ConditionalTransition
- {
- Test = test,
- IfTrue = IfTrue,
- IfFalse = IfFalse
- };
- }
-
- protected override List GetBody()
- {
- return [GetExpression()];
+ expressions.Add( Expression() );
+ return;
- Expression GetExpression()
+ Expression Expression()
{
- var fallThrough = GotoOrFallThrough( Parent.StateOrder, IfFalse, true );
+ var fallThrough = GotoOrFallThrough( parent.StateOrder, IfFalse, true );
if ( fallThrough == null )
return IfThen( Test, Goto( IfTrue.NodeLabel ) );
diff --git a/src/Hyperbee.Expressions/Transformation/Transitions/FinalTransition.cs b/src/Hyperbee.Expressions/Transformation/Transitions/FinalTransition.cs
index 202a98d..0edce5a 100644
--- a/src/Hyperbee.Expressions/Transformation/Transitions/FinalTransition.cs
+++ b/src/Hyperbee.Expressions/Transformation/Transitions/FinalTransition.cs
@@ -1,4 +1,5 @@
using System.Linq.Expressions;
+using static System.Linq.Expressions.Expression;
namespace Hyperbee.Expressions.Transformation.Transitions;
@@ -10,15 +11,14 @@ internal override void Optimize( HashSet references )
{
}
- protected override List GetBody()
+ protected override void SetBody( List expressions, NodeExpression parent )
{
- return EmptyBody;
}
- protected override void AssignResult( List expressions )
+ protected override void SetResult( List expressions, NodeExpression parent )
{
- var resultField = Parent.StateMachineSource.ResultField;
- var returnValue = Parent.StateMachineSource.ReturnValue;
+ var resultField = parent.StateMachineSource.ResultField;
+ var returnValue = parent.StateMachineSource.ReturnValue;
if ( returnValue != null )
{
@@ -46,7 +46,7 @@ protected override void AssignResult( List expressions )
}
expressions.Add(
- Assign( resultField, Parent.ResultValue ?? Constant( null, typeof( IVoidResult ) ) )
+ Assign( resultField, parent.ResultValue ?? Constant( null, typeof( IVoidResult ) ) )
);
}
}
diff --git a/src/Hyperbee.Expressions/Transformation/Transitions/GotoTransition.cs b/src/Hyperbee.Expressions/Transformation/Transitions/GotoTransition.cs
index f7351f1..f978ee3 100644
--- a/src/Hyperbee.Expressions/Transformation/Transitions/GotoTransition.cs
+++ b/src/Hyperbee.Expressions/Transformation/Transitions/GotoTransition.cs
@@ -7,9 +7,9 @@ internal class GotoTransition : Transition
public NodeExpression TargetNode { get; set; }
internal override NodeExpression FallThroughNode => TargetNode;
- protected override List GetBody()
+ protected override void SetBody( List expressions, NodeExpression parent )
{
- return [GotoOrFallThrough( Parent.StateOrder, TargetNode )];
+ expressions.Add( GotoOrFallThrough( parent.StateOrder, TargetNode ) );
}
internal override void Optimize( HashSet references )
diff --git a/src/Hyperbee.Expressions/Transformation/Transitions/LoopTransition.cs b/src/Hyperbee.Expressions/Transformation/Transitions/LoopTransition.cs
index 00388b4..14d44e6 100644
--- a/src/Hyperbee.Expressions/Transformation/Transitions/LoopTransition.cs
+++ b/src/Hyperbee.Expressions/Transformation/Transitions/LoopTransition.cs
@@ -10,9 +10,8 @@ internal class LoopTransition : Transition
internal override NodeExpression FallThroughNode => BodyNode;
- protected override List GetBody()
+ protected override void SetBody( List expressions, NodeExpression parent )
{
- return EmptyBody;
}
internal override void Optimize( HashSet references )
diff --git a/src/Hyperbee.Expressions/Transformation/Transitions/SwitchTransition.cs b/src/Hyperbee.Expressions/Transformation/Transitions/SwitchTransition.cs
index 1df3ff7..a9badcc 100644
--- a/src/Hyperbee.Expressions/Transformation/Transitions/SwitchTransition.cs
+++ b/src/Hyperbee.Expressions/Transformation/Transitions/SwitchTransition.cs
@@ -1,4 +1,5 @@
using System.Linq.Expressions;
+using static System.Linq.Expressions.Expression;
namespace Hyperbee.Expressions.Transformation.Transitions;
@@ -10,39 +11,19 @@ internal class SwitchTransition : Transition
internal override NodeExpression FallThroughNode => DefaultNode;
- protected override Expression VisitChildren( ExpressionVisitor visitor )
+ protected override void SetBody( List expressions, NodeExpression parent )
{
- return Update(
- visitor.Visit( SwitchValue ),
- CaseNodes.Select( x => x.Update( x.TestValues.Select( visitor.Visit ).ToList() ) ).ToList()
- );
- }
-
- internal SwitchTransition Update( Expression switchValue, List caseNodes )
- {
- if ( switchValue == SwitchValue )
- return this;
-
- return new SwitchTransition
- {
- DefaultNode = DefaultNode,
- SwitchValue = switchValue,
- CaseNodes = caseNodes
- };
- }
-
- protected override List GetBody()
- {
- return [GetExpression()];
+ expressions.Add( Expression() );
+ return;
- Expression GetExpression()
+ Expression Expression()
{
Expression defaultBody;
if ( DefaultNode != null )
{
defaultBody = GotoOrFallThrough(
- Parent.StateOrder,
+ parent.StateOrder,
DefaultNode,
allowNull: true
);
@@ -53,7 +34,7 @@ Expression GetExpression()
}
var cases = CaseNodes
- .Select( switchCase => switchCase.Reduce( Parent.StateOrder ) )
+ .Select( switchCase => switchCase.Reduce( parent.StateOrder ) )
.ToArray();
return Switch( SwitchValue, defaultBody, cases );
diff --git a/src/Hyperbee.Expressions/Transformation/Transitions/Transition.cs b/src/Hyperbee.Expressions/Transformation/Transitions/Transition.cs
index d256b46..c47c52a 100644
--- a/src/Hyperbee.Expressions/Transformation/Transitions/Transition.cs
+++ b/src/Hyperbee.Expressions/Transformation/Transitions/Transition.cs
@@ -1,63 +1,28 @@
using System.Diagnostics;
using System.Linq.Expressions;
+using static System.Linq.Expressions.Expression;
+
namespace Hyperbee.Expressions.Transformation.Transitions;
[DebuggerDisplay( "Transition = {GetType().Name,nq}" )]
-internal abstract class Transition : Expression
+internal abstract class Transition
{
- protected static readonly List EmptyBody = [Empty()];
-
- public override ExpressionType NodeType => ExpressionType.Extension;
- public override Type Type => typeof( void );
- public override bool CanReduce => true;
-
- protected override Expression VisitChildren( ExpressionVisitor visitor ) => this;
-
internal abstract NodeExpression FallThroughNode { get; }
- internal abstract void Optimize( HashSet references );
-
- internal NodeExpression Parent { get; set; }
-
- public override Expression Reduce()
+ public void AddExpressions( NodeExpression parent, List expressions )
{
- if ( Parent == null )
- throw new InvalidOperationException( $"Transition Reduce requires a {nameof( Parent )} instance." );
-
- var reduced = Reduce( Parent );
+ if ( parent == null )
+ throw new InvalidOperationException( $"Transition {nameof( AddExpressions )} requires a {nameof( parent )} instance." );
- return (reduced.Count == 1)
- ? reduced[0]
- : Block( reduced );
+ SetResult( expressions, parent );
+ SetBody( expressions, parent );
}
- private List Reduce( NodeExpression node )
+ protected virtual void SetResult( List expressions, NodeExpression parent )
{
- var expressions = new List( 8 ) // Label, Expressions, AssignResult, Transition
- {
- Label( node.NodeLabel )
- };
-
- expressions.AddRange( node.Expressions );
-
- // add result assignment
-
- AssignResult( expressions );
-
- // add transition body
-
- expressions.AddRange( GetBody() );
-
- return expressions;
- }
-
- protected abstract List GetBody();
-
- protected virtual void AssignResult( List expressions )
- {
- var resultValue = Parent.ResultValue;
- var resultVariable = Parent.ResultVariable;
+ var resultValue = parent.ResultValue;
+ var resultVariable = parent.ResultVariable;
if ( resultValue != null && resultVariable != null && resultValue.Type == resultVariable.Type )
{
@@ -69,12 +34,9 @@ protected virtual void AssignResult( List expressions )
}
}
- protected static Expression GotoOrFallThrough( int order, NodeExpression node, bool allowNull = false )
- {
- return order + 1 == node.StateOrder
- ? allowNull ? null : Empty()
- : Goto( node.NodeLabel );
- }
+ protected abstract void SetBody( List expressions, NodeExpression parent );
+
+ internal abstract void Optimize( HashSet references );
protected static NodeExpression OptimizeGotos( NodeExpression node )
{
@@ -85,5 +47,15 @@ protected static NodeExpression OptimizeGotos( NodeExpression node )
return node;
}
+
+ protected static Expression GotoOrFallThrough( int order, NodeExpression node, bool allowNull = false )
+ {
+ if ( order + 1 == node.StateOrder )
+ {
+ return allowNull ? null : Empty();
+ }
+
+ return Goto( node.NodeLabel );
+ }
}
diff --git a/src/Hyperbee.Expressions/Transformation/Transitions/TryCatchTransition.cs b/src/Hyperbee.Expressions/Transformation/Transitions/TryCatchTransition.cs
index f2b8ae7..e9d0e38 100644
--- a/src/Hyperbee.Expressions/Transformation/Transitions/TryCatchTransition.cs
+++ b/src/Hyperbee.Expressions/Transformation/Transitions/TryCatchTransition.cs
@@ -1,4 +1,5 @@
using System.Linq.Expressions;
+using static System.Linq.Expressions.Expression;
namespace Hyperbee.Expressions.Transformation.Transitions;
@@ -16,54 +17,26 @@ internal class TryCatchTransition : Transition
internal override NodeExpression FallThroughNode => TryNode;
- protected override Transition VisitChildren( ExpressionVisitor visitor )
+ protected override void SetBody( List expressions, NodeExpression parent )
{
- return Update(
- CatchBlocks.Select( c => new CatchBlockDefinition( c.Handler, visitor.Visit( c.UpdateBody ), c.CatchState ) ).ToList(),
- visitor.Visit( TryStateVariable ),
- visitor.Visit( ExceptionVariable )
- );
- }
-
- internal TryCatchTransition Update(
- List catchBlocks,
- Expression tryStateVariable,
- Expression exceptionVariable )
- {
- if ( catchBlocks == CatchBlocks && tryStateVariable == TryStateVariable && exceptionVariable == ExceptionVariable )
- return this;
-
- return new TryCatchTransition
- {
- TryNode = TryNode,
- FinallyNode = FinallyNode,
- CatchBlocks = catchBlocks,
- TryStateVariable = tryStateVariable,
- ExceptionVariable = exceptionVariable,
- StateScope = StateScope,
- Scopes = Scopes
- };
- }
-
- protected override List GetBody()
- {
- return GetExpressions();
+ expressions.AddRange( Expressions() );
+ return;
- List GetExpressions()
+ List Expressions()
{
var body = new List
{
JumpTableBuilder.Build(
StateScope,
Scopes,
- Parent.StateMachineSource.StateIdField
+ parent.StateMachineSource.StateIdField
)
};
//body.AddRange( StateScope.Nodes ); //BF ME - merge nodes here
body.AddRange( NodeExpression.Merge( StateScope.Nodes ) );
- MapCatchBlock( Parent.StateOrder, out var catches, out var switchCases );
+ MapCatchBlock( parent.StateOrder, out var catches, out var switchCases );
return [
TryCatch(
diff --git a/test/Hyperbee.Expressions.Tests/Optimizers/InliningOptimizerTests.cs b/test/Hyperbee.Expressions.Tests/Optimizers/InliningOptimizerTests.cs
deleted file mode 100644
index ac78248..0000000
--- a/test/Hyperbee.Expressions.Tests/Optimizers/InliningOptimizerTests.cs
+++ /dev/null
@@ -1,110 +0,0 @@
-using System.Linq.Expressions;
-using Hyperbee.Expressions.Optimizers;
-
-namespace Hyperbee.Expressions.Tests.Optimizers;
-
-[TestClass]
-public class InliningOptimizerTests
-{
- [TestMethod]
- public void Inlining_ShouldInlineSimpleConstant()
- {
- // Before: .Add(.Constant(10), .Constant(5))
- // After: .Constant(15)
-
- // Arrange
- var expression = Expression.Add( Expression.Constant( 10 ), Expression.Constant( 5 ) );
- var optimizer = new InliningOptimizer();
-
- // Act
- var result = optimizer.Optimize( expression );
- var value = ((ConstantExpression) result).Value;
-
- // Assert
- Assert.AreEqual( 15, value );
- }
-
- [TestMethod]
- public void Inlining_ShouldInlineLambdaExpression()
- {
- // Before: .Invoke((x) => x + 5, .Constant(3))
- // After: .Constant(8)
-
- // Arrange
- var parameter = Expression.Parameter( typeof( int ), "x" );
- var lambda = Expression.Lambda( Expression.Add( parameter, Expression.Constant( 5 ) ), parameter );
- var invocation = Expression.Invoke( lambda, Expression.Constant( 3 ) );
- var optimizer = new InliningOptimizer();
-
- // Act
- var result = optimizer.Optimize( invocation );
- var value = ((ConstantExpression) result).Value;
-
- // Assert
- Assert.AreEqual( 8, value );
- }
-
- [TestMethod]
- public void Inlining_ShouldShortCircuitBoolean()
- {
- // Before: .AndAlso(.Constant(true), .Constant(false))
- // After: .Constant(false)
-
- // Arrange
- var expression = Expression.AndAlso( Expression.Constant( true ), Expression.Constant( false ) );
- var optimizer = new InliningOptimizer();
-
- // Act
- var result = optimizer.Optimize( expression );
- var value = (bool) ((ConstantExpression) result).Value!;
-
- // Assert
- Assert.IsFalse( value );
- }
-
- [TestMethod]
- public void Inlining_ShouldInlineConditionalExpression()
- {
- // Before: .Conditional(.Constant(true), .Constant("True"), .Constant("False"))
- // After: .Constant("True")
-
- // Arrange
- var condition = Expression.Constant( true );
- var conditional = Expression.Condition( condition, Expression.Constant( "True" ), Expression.Constant( "False" ) );
- var optimizer = new InliningOptimizer();
-
- // Act
- var result = optimizer.Optimize( conditional );
- var value = ((ConstantExpression) result).Value;
-
- // Assert
- Assert.AreEqual( "True", value );
- }
-
- [TestMethod]
- public void Inlining_ShouldSimplifyNestedConditionalExpression()
- {
- // Before: .Conditional(.Constant(true), .Conditional(.Constant(false), .Constant("A"), .Constant("B")), .Constant("C"))
- // After: .Constant("B")
-
- // Arrange
- var innerCondition = Expression.Condition(
- Expression.Constant( false ),
- Expression.Constant( "A" ),
- Expression.Constant( "B" )
- );
- var outerCondition = Expression.Condition(
- Expression.Constant( true ),
- innerCondition,
- Expression.Constant( "C" )
- );
- var optimizer = new InliningOptimizer();
-
- // Act
- var result = optimizer.Optimize( outerCondition );
- var value = ((ConstantExpression) result).Value;
-
- // Assert
- Assert.AreEqual( "B", value );
- }
-}
diff --git a/test/Hyperbee.Expressions.Tests/Optimizers/OperatorReductionOptimizerTests.cs b/test/Hyperbee.Expressions.Tests/Optimizers/OperatorReductionOptimizerTests.cs
deleted file mode 100644
index 87c7f1d..0000000
--- a/test/Hyperbee.Expressions.Tests/Optimizers/OperatorReductionOptimizerTests.cs
+++ /dev/null
@@ -1,118 +0,0 @@
-using System.Linq.Expressions;
-using Hyperbee.Expressions.Optimizers;
-
-namespace Hyperbee.Expressions.Tests.Optimizers;
-
-[TestClass]
-public class OperatorReductionOptimizerTests
-{
- [TestMethod]
- public void OperatorReduction_ShouldRemoveAddZero()
- {
- // Before: .Add(.Parameter(x), .Constant(0))
- // After: .Parameter(x)
-
- // Arrange
- var expression = Expression.Add( Expression.Parameter( typeof( int ), "x" ), Expression.Constant( 0 ) );
- var optimizer = new OperatorReductionOptimizer();
-
- // Act
- var result = optimizer.Optimize( expression );
-
- // Assert
- Assert.IsInstanceOfType( result, typeof( ParameterExpression ) );
- }
-
- [TestMethod]
- public void OperatorReduction_ShouldRemoveMultiplyByOne()
- {
- // Before: .Multiply(.Parameter(x), .Constant(1))
- // After: .Parameter(x)
-
- // Arrange
- var expression = Expression.Multiply( Expression.Parameter( typeof( int ), "x" ), Expression.Constant( 1 ) );
- var optimizer = new OperatorReductionOptimizer();
-
- // Act
- var result = optimizer.Optimize( expression );
-
- // Assert
- Assert.IsInstanceOfType( result, typeof( ParameterExpression ) );
- }
-
- [TestMethod]
- public void OperatorReduction_ShouldSimplifyLogicalIdentity()
- {
- // Before: .AndAlso(.Constant(true), .Parameter(x))
- // After: .Parameter(x)
-
- // Arrange
- var andExpression = Expression.AndAlso( Expression.Constant( true ), Expression.Parameter( typeof( bool ), "x" ) );
- var optimizer = new OperatorReductionOptimizer();
-
- // Act
- var result = optimizer.Optimize( andExpression );
-
- // Assert
- Assert.IsInstanceOfType( result, typeof( ParameterExpression ) );
- }
-
- [TestMethod]
- public void OperatorReduction_ShouldFlattenNestedExpressions()
- {
- // Before: .Add(.Add(.Constant(1), .Constant(2)), .Constant(3))
- // After: .Constant(6)
-
- // Arrange
- var nestedExpression = Expression.Add( Expression.Add( Expression.Constant( 1 ), Expression.Constant( 2 ) ), Expression.Constant( 3 ) );
- var optimizer = new OperatorReductionOptimizer();
-
- // Act
- var result = optimizer.Optimize( nestedExpression );
- var constant = result as ConstantExpression;
- var value = constant?.Value;
-
- // Assert
- Assert.IsInstanceOfType( result, typeof( ConstantExpression ), "Expected a ConstantExpression after optimization." );
- Assert.IsNotNull( constant, "Expected a non-null ConstantExpression." );
- Assert.AreEqual( 6, value );
- }
-
- [TestMethod]
- public void OperatorReduction_ShouldSimplifyMultiOperationReduction()
- {
- // Before: .Multiply(.Add(.Parameter(x), .Constant(0)), .Constant(1))
- // After: .Parameter(x)
-
- // Arrange
- var parameter = Expression.Parameter( typeof( int ), "x" );
- var addZero = Expression.Add( parameter, Expression.Constant( 0 ) );
- var multiplyByOne = Expression.Multiply( addZero, Expression.Constant( 1 ) );
- var optimizer = new OperatorReductionOptimizer();
-
- // Act
- var result = optimizer.Optimize( multiplyByOne );
-
- // Assert
- Assert.IsInstanceOfType( result, typeof( ParameterExpression ) );
- }
-
- [TestMethod]
- public void OperatorReduction_ShouldSimplifyComplexBooleanReduction()
- {
- // Before: .AndAlso(.OrElse(.Constant(true), .Constant(false)), .Constant(true))
- // After: .Constant(true)
-
- // Arrange
- var orExpression = Expression.OrElse( Expression.Constant( true ), Expression.Constant( false ) );
- var andExpression = Expression.AndAlso( orExpression, Expression.Constant( true ) );
- var optimizer = new OperatorReductionOptimizer();
-
- // Act
- var result = optimizer.Optimize( andExpression );
- var value = (bool) ((ConstantExpression) result).Value!;
-
- // Assert
- Assert.IsTrue( value );
- }
-}
diff --git a/test/Hyperbee.Expressions.Tests/Optimizers/StructuralReductionOptimizerTests.cs b/test/Hyperbee.Expressions.Tests/Optimizers/StructuralReductionOptimizerTests.cs
deleted file mode 100644
index 1e180ce..0000000
--- a/test/Hyperbee.Expressions.Tests/Optimizers/StructuralReductionOptimizerTests.cs
+++ /dev/null
@@ -1,113 +0,0 @@
-using System.Linq.Expressions;
-using Hyperbee.Expressions.Optimizers;
-
-namespace Hyperbee.Expressions.Tests.Optimizers;
-
-[TestClass]
-public class StructuralReductionOptimizerTests
-{
- [TestMethod]
- public void StructuralReduction_ShouldRemoveUnreachableCode()
- {
- // Before: .Block(.Constant(1), .Constant(2))
- // After: .Constant(1)
-
- // Arrange
- var block = Expression.Block( Expression.Constant( 1 ), Expression.Constant( 2 ) );
- var optimizer = new StructuralReductionOptimizer();
-
- // Act
- var result = optimizer.Optimize( block );
- var value = ((ConstantExpression) ((BlockExpression) result).Expressions[0]).Value;
-
- // Assert
- Assert.AreEqual( 1, value );
- }
-
- [TestMethod]
- public void StructuralReduction_ShouldSimplifyEmptyTryCatch()
- {
- // Before: .TryCatch(.Empty(), .Catch(...))
- // After: .Empty()
-
- // Arrange
- var tryCatch = Expression.TryCatch(
- Expression.Empty(),
- Expression.Catch( Expression.Parameter( typeof( Exception ) ), Expression.Empty() )
- );
- var optimizer = new StructuralReductionOptimizer();
-
- // Act
- var result = optimizer.Optimize( tryCatch );
-
- // Assert
- Assert.IsInstanceOfType( result, typeof( DefaultExpression ) );
- }
-
- [TestMethod]
- public void StructuralReduction_ShouldRemoveInfiniteLoop()
- {
- // Before: .Loop(.Constant(1))
- // After: .Empty()
-
- // Arrange
- var loop = Expression.Loop( Expression.Constant( 1 ) );
- var optimizer = new StructuralReductionOptimizer();
-
- // Act
- var result = optimizer.Optimize( loop );
-
- // Assert
- Assert.IsInstanceOfType( result, typeof( DefaultExpression ) );
- }
-
- [TestMethod]
- public void StructuralReduction_ShouldSimplifyNestedConditionalExpression()
- {
- // Before: .Block(.IfThenElse(.Constant(true), .IfThenElse(.Constant(false), .Break(), .Constant("B"))))
- // After: .Constant("B")
-
- // Arrange
- var innerCondition = Expression.IfThenElse(
- Expression.Constant( false ),
- Expression.Break( Expression.Label() ),
- Expression.Constant( "B" )
- );
- var outerCondition = Expression.IfThenElse(
- Expression.Constant( true ),
- innerCondition,
- Expression.Constant( "C" )
- );
- var block = Expression.Block( outerCondition );
- var optimizer = new StructuralReductionOptimizer();
-
- // Act
- var result = optimizer.Optimize( block );
- var value = ((ConstantExpression) result).Value;
-
- // Assert
- Assert.AreEqual( "B", value );
- }
-
- [TestMethod]
- public void StructuralReduction_ShouldSimplifyLoopWithComplexCondition()
- {
- // Before: .Loop(.IfThenElse(.Constant(false), .Break(), .Constant(1)))
- // After: .Empty()
-
- // Arrange
- var loopCondition = Expression.IfThenElse(
- Expression.Constant( false ),
- Expression.Break( Expression.Label() ),
- Expression.Constant( 1 )
- );
- var loop = Expression.Loop( loopCondition );
- var optimizer = new StructuralReductionOptimizer();
-
- // Act
- var result = optimizer.Optimize( loop );
-
- // Assert
- Assert.IsInstanceOfType( result, typeof( DefaultExpression ) );
- }
-}
diff --git a/test/Hyperbee.Expressions.Tests/Optimizers/SubexpressionCachingOptimizerTests.cs b/test/Hyperbee.Expressions.Tests/Optimizers/SubexpressionCachingOptimizerTests.cs
deleted file mode 100644
index f9ebb63..0000000
--- a/test/Hyperbee.Expressions.Tests/Optimizers/SubexpressionCachingOptimizerTests.cs
+++ /dev/null
@@ -1,146 +0,0 @@
-using System.Linq.Expressions;
-using Hyperbee.Expressions.Optimizers;
-using Hyperbee.Expressions.Tests.TestSupport;
-
-namespace Hyperbee.Expressions.Tests.Optimizers;
-
-[TestClass]
-public class SubexpressionCachingOptimizerTests
-{
- public class TestClass
- {
- public string Method() => "Result";
- }
-
- [TestMethod]
- public void SubexpressionCaching_ShouldNotCacheSimpleExpressions()
- {
- // Before: .Add(.Constant(2), .Constant(3)) + .Add(.Constant(2), .Constant(3))
- // After: .Add(.Constant(2), .Constant(3)) + .Add(.Constant(2), .Constant(3))
-
- // Arrange
- var simpleExpr = Expression.Add( Expression.Constant( 2 ), Expression.Constant( 3 ) );
- var referenceExpr = Expression.Lambda>(
- Expression.Add( simpleExpr, simpleExpr )
- );
-
- var optimizer = new SubexpressionCachingOptimizer();
-
- // Act
- var optimizedExpr = optimizer.Optimize( referenceExpr );
- var reference = referenceExpr.Compile();
- var result = reference();
- var optimized = optimizedExpr.Compile();
- var comparand = optimized();
-
- // Assert
- Assert.AreEqual( result, comparand );
- Assert.IsTrue( optimizedExpr.GetDebugView().Contains( "2 + 3 + 2 + 3" ), "Simple expression should not be cached." );
- }
-
- [TestMethod]
- public void SubexpressionCaching_ShouldCacheComplexExpressions()
- {
- // Before: .Add(.Multiply(.Constant(5), .Add(.Constant(3), .Constant(2))), .Multiply(.Constant(5), .Add(.Constant(3), .Constant(2))))
- // After: .Block(.Assign(variable, .Multiply(.Constant(5), .Add(.Constant(3), .Constant(2)))), .Add(variable, variable))
-
- // Arrange
- var complexExpr = Expression.Multiply( Expression.Constant( 5 ), Expression.Add( Expression.Constant( 3 ), Expression.Constant( 2 ) ) );
- var referenceExpr = Expression.Lambda>(
- Expression.Add( complexExpr, complexExpr )
- );
-
- var optimizer = new SubexpressionCachingOptimizer();
-
- // Act
- var optimizedExpr = optimizer.Optimize( referenceExpr );
- var reference = referenceExpr.Compile();
- var result = reference();
- var optimized = optimizedExpr.Compile();
- var comparand = optimized();
-
- // Assert
- Assert.AreEqual( result, comparand );
- Assert.IsTrue( optimizedExpr.GetDebugView().Contains( "Block" ), "Complex expression should be cached with a block." );
- }
-
- [TestMethod]
- public void SubexpressionCaching_ShouldCacheRepeatedMethodCalls()
- {
- // Before: .Add(.Call(Method), .Call(Method))
- // After: .Block(.Assign(variable, .Call(Method)), .Add(variable, variable))
-
- // Arrange
- Expression> referenceExpr = () => Math.Abs( -5 ) + Math.Abs( -5 );
- var optimizer = new SubexpressionCachingOptimizer();
-
- // Act
- var optimizedExpr = optimizer.Optimize( referenceExpr );
- var reference = referenceExpr.Compile();
- var result = reference();
- var optimized = optimizedExpr.Compile();
- var comparand = optimized();
-
- // Assert
- Assert.AreEqual( result, comparand );
- Assert.IsTrue( optimizedExpr.GetDebugView().Contains( "Block" ), "Method call should be cached with a block." );
- }
-
- [TestMethod]
- public void SubexpressionCaching_ShouldCacheRepeatedExpressions()
- {
- // Before: .Add(.Add(x, .Constant(5)), .Add(x, .Constant(5)))
- // After: .Block(.Assign(variable, .Add(x, .Constant(5))), .Add(variable, variable))
-
- // Arrange
- var x = Expression.Parameter( typeof( int ), "x" );
- var repeatedExpr = Expression.Add( x, Expression.Constant( 5 ) );
- var complexExpression = Expression.Add( repeatedExpr, repeatedExpr );
- var optimizer = new SubexpressionCachingOptimizer();
-
- // Act
- var result = optimizer.Optimize( complexExpression );
-
- // Assert
- Assert.IsInstanceOfType( result, typeof( BlockExpression ) );
- Assert.AreEqual( 2, ((BlockExpression) result).Expressions.Count );
- }
-
- [TestMethod]
- public void SubexpressionCaching_ShouldCacheCrossScopeExpression()
- {
- // Before: .Block(.Call(obj.Method), .Block(.Call(obj.Method)))
- // After: .Block(.Assign(variable, .Call(obj.Method)), .Variable(variable), .Block(.Variable(variable)))
-
- // Arrange
- var methodCall = Expression.Call( Expression.Constant( new TestClass() ), "Method", null );
- var innerBlock = Expression.Block( methodCall );
- var outerBlock = Expression.Block( methodCall, innerBlock );
- var optimizer = new SubexpressionCachingOptimizer();
-
- // Act
- var result = optimizer.Optimize( outerBlock );
-
- // Assert
- Assert.IsInstanceOfType( result, typeof( BlockExpression ) );
- }
-
- [TestMethod]
- public void SubexpressionCaching_ShouldCacheParameterizedSubexpression()
- {
- // Before: .Block(.Add(.Parameter(x), .Constant(5)), .Add(.Parameter(x), .Constant(5)))
- // After: .Block(.Assign(variable, .Add(.Parameter(x), .Constant(5))), .Variable(variable), .Variable(variable))
-
- // Arrange
- var parameter = Expression.Parameter( typeof( int ), "x" );
- var addExpression = Expression.Add( parameter, Expression.Constant( 5 ) );
- var block = Expression.Block( addExpression, addExpression );
- var optimizer = new SubexpressionCachingOptimizer();
-
- // Act
- var result = optimizer.Optimize( block );
-
- // Assert
- Assert.IsInstanceOfType( result, typeof( BlockExpression ) );
- }
-}
diff --git a/test/Hyperbee.Expressions.Tests/Optimizers/ValueBindingOptimizerTests.cs b/test/Hyperbee.Expressions.Tests/Optimizers/ValueBindingOptimizerTests.cs
deleted file mode 100644
index 7ff0ae5..0000000
--- a/test/Hyperbee.Expressions.Tests/Optimizers/ValueBindingOptimizerTests.cs
+++ /dev/null
@@ -1,174 +0,0 @@
-using System.Linq.Expressions;
-using Hyperbee.Expressions.Optimizers;
-
-namespace Hyperbee.Expressions.Tests.Optimizers;
-
-[TestClass]
-public class ValueBindingOptimizerTests
-{
- public class Container
- {
- public NestedClass Nested { get; } = new();
- }
-
- public class NestedClass
- {
- public string Value => "ExpectedValue";
- }
-
- [TestMethod]
- public void ValueBinding_ShouldFoldConstants()
- {
- // Before: .Add(.Constant(2), .Constant(3))
- // After: .Constant(5)
-
- // Arrange
- var expression = Expression.Add( Expression.Constant( 2 ), Expression.Constant( 3 ) );
- var optimizer = new ValueBindingOptimizer();
-
- // Act
- var result = optimizer.Optimize( expression );
- var value = ((ConstantExpression) result).Value;
-
- // Assert
- Assert.AreEqual( 5, value );
- }
-
- [TestMethod]
- public void ValueBinding_ShouldInlineSingleUseVariable()
- {
- // Before: .Block(.Assign(.Parameter(x), .Constant(10)), .Parameter(x))
- // After: .Constant(10)
-
- // Arrange
- var parameter = Expression.Parameter( typeof( int ), "x" );
- var block = Expression.Block( [parameter], Expression.Assign( parameter, Expression.Constant( 10 ) ), parameter );
- var optimizer = new ValueBindingOptimizer();
-
- // Act
- var result = optimizer.Optimize( block );
- var value = ((ConstantExpression) result).Value;
-
- // Assert
- Assert.AreEqual( 10, value );
- }
-
- [TestMethod]
- public void ValueBinding_ShouldSimplifyConstantMemberAccess()
- {
- // Before: .Property(.Constant(new DateTime(2024, 1, 1)), "Year")
- // After: .Constant(2024)
-
- // Arrange
- var date = Expression.Constant( new DateTime( 2024, 1, 1 ) );
- var memberAccess = Expression.Property( date, "Year" );
- var optimizer = new ValueBindingOptimizer();
-
- // Act
- var result = optimizer.Optimize( memberAccess );
- var value = ((ConstantExpression) result).Value;
-
- // Assert
- Assert.AreEqual( 2024, value );
- }
-
- [TestMethod]
- public void ValueBinding_ShouldInlineVariableInNestedScope()
- {
- // Before: .Block(.Assign(.Parameter(x), .Constant(10)), .Block(.Parameter(x)))
- // After: .Constant(10)
-
- // Arrange
- var parameter = Expression.Parameter( typeof( int ), "x" );
- var nestedBlock = Expression.Block( parameter );
- var outerBlock = Expression.Block( [parameter], Expression.Assign( parameter, Expression.Constant( 10 ) ), nestedBlock );
- var optimizer = new ValueBindingOptimizer();
-
- // Act
- var result = optimizer.Optimize( outerBlock );
- var value = ((ConstantExpression) result).Value;
-
- // Assert
- Assert.AreEqual( 10, value );
- }
-
- [TestMethod]
- public void ValueBinding_ShouldSimplifyComplexMemberAccess()
- {
- // Before: .Property(.Property(.Constant(new Container()), "Nested"), "Value")
- // After: .Constant("ExpectedValue")
-
- // Arrange
- var container = Expression.Constant( new Container() );
- var nestedMember = Expression.Property( container, nameof( Container.Nested ) );
- var memberAccess = Expression.Property( nestedMember, nameof( Container.Nested.Value ) );
- var optimizer = new ValueBindingOptimizer();
-
- // Act
- var result = optimizer.Optimize( memberAccess );
- var value = ((ConstantExpression) result).Value;
-
- // Assert
- Assert.AreEqual( "ExpectedValue", value );
- }
-
- [TestMethod]
- public void ValueBinding_ShouldReduceRedundantAllocations()
- {
- // Before: .Block(.Assign(.Parameter(x), .Constant(1)), .Parameter(x))
- // After: .Constant(1)
-
- // Arrange
- var param = Expression.Parameter( typeof( int ), "x" );
- var redundantAlloc = Expression.Block( [param], Expression.Assign( param, Expression.Constant( 1 ) ), param );
- var optimizer = new ValueBindingOptimizer();
-
- // Act
- var result = optimizer.Optimize( redundantAlloc );
- var constant = (ConstantExpression) result;
- var value = constant.Value;
-
- // Assert
- Assert.AreEqual( 1, value );
- }
-
- [TestMethod]
- public void ValueBinding_ShouldReuseTemporaryVariableInLoop()
- {
- // Before: .Loop(.Block(.Assign(.Parameter(temp), .Constant(42)), .Parameter(temp)))
- // After: .Constant(42)
-
- // Arrange
- var tempVar = Expression.Parameter( typeof( int ), "temp" );
- var loop = Expression.Loop( Expression.Block( [tempVar], Expression.Assign( tempVar, Expression.Constant( 42 ) ), tempVar ) );
- var optimizer = new ValueBindingOptimizer();
-
- // Act
- var result = optimizer.Optimize( loop );
-
- // Assert
- var resultValue = (result as ConstantExpression)?.Value;
-
- Assert.IsInstanceOfType( result, typeof( ConstantExpression ) );
- Assert.AreEqual( 42, resultValue, "Expected the loop body constant to have value 42." );
- }
-
- [TestMethod]
- public void ValueBinding_ShouldReduceAllocationsInNestedBlocks()
- {
- // Before: .Block(.Block(.Assign(.Parameter(temp), .Constant(10)), .Parameter(temp)), .Parameter(temp))
- // After: .Constant(10)
-
- // Arrange
- var tempVar = Expression.Parameter( typeof( int ), "temp" );
- var innerBlock = Expression.Block( [tempVar], Expression.Assign( tempVar, Expression.Constant( 10 ) ), tempVar );
- var outerBlock = Expression.Block( innerBlock, tempVar );
- var optimizer = new ValueBindingOptimizer();
-
- // Act
- var result = optimizer.Optimize( outerBlock );
-
- // Assert
- Assert.IsInstanceOfType( result, typeof( ConstantExpression ) );
- }
-}