<PackageReference Include="NUnit" Version="3.7.1" />

ConstraintBuilder

ConstraintBuilder maintains the stacks that are used in processing a ConstraintExpression. An OperatorStack is used to hold operators that are waiting for their operands to be reorganized. a ConstraintStack holds input constraints as well as the results of each operator applied.
using System; using System.Collections.Generic; namespace NUnit.Framework.Constraints { public class ConstraintBuilder : IResolveConstraint { public class OperatorStack { private readonly Stack<ConstraintOperator> stack = new Stack<ConstraintOperator>(); public bool Empty => stack.Count == 0; public ConstraintOperator Top => stack.Peek(); public OperatorStack(ConstraintBuilder builder) { } public void Push(ConstraintOperator op) { stack.Push(op); } public ConstraintOperator Pop() { return stack.Pop(); } } public class ConstraintStack { private readonly Stack<IConstraint> stack = new Stack<IConstraint>(); private readonly ConstraintBuilder builder; public bool Empty => stack.Count == 0; public ConstraintStack(ConstraintBuilder builder) { this.builder = builder; } public void Push(IConstraint constraint) { stack.Push(constraint); constraint.Builder = builder; } public IConstraint Pop() { IConstraint constraint = stack.Pop(); constraint.Builder = null; return constraint; } } private readonly OperatorStack ops; private readonly ConstraintStack constraints; private object lastPushed; private bool IsResolvable { get { if (!(lastPushed is Constraint)) return lastPushed is SelfResolvingOperator; return true; } } public ConstraintBuilder() { ops = new OperatorStack(this); constraints = new ConstraintStack(this); } public void Append(ConstraintOperator op) { op.LeftContext = lastPushed; if (lastPushed is ConstraintOperator) SetTopOperatorRightContext(op); ReduceOperatorStack(op.LeftPrecedence); ops.Push(op); lastPushed = op; } public void Append(Constraint constraint) { if (lastPushed is ConstraintOperator) SetTopOperatorRightContext(constraint); constraints.Push(constraint); lastPushed = constraint; constraint.Builder = this; } private void SetTopOperatorRightContext(object rightContext) { int leftPrecedence = ops.Top.LeftPrecedence; ops.Top.RightContext = rightContext; if (ops.Top.LeftPrecedence > leftPrecedence) { ConstraintOperator constraintOperator = ops.Pop(); ReduceOperatorStack(constraintOperator.LeftPrecedence); ops.Push(constraintOperator); } } private void ReduceOperatorStack(int targetPrecedence) { while (!ops.Empty && ops.Top.RightPrecedence < targetPrecedence) { ops.Pop().Reduce(constraints); } } public IConstraint Resolve() { if (!IsResolvable) throw new InvalidOperationException("A partial expression may not be resolved"); while (!ops.Empty) { ops.Pop().Reduce(constraints); } return constraints.Pop(); } } }