/// <summary> /// Add to the current pattern a new pattern symbol that matches all elements /// </summary> /// <typeparam name="TKey">Key type</typeparam> /// <typeparam name="TPayload">Payload type</typeparam> /// <typeparam name="TRegister">Result type (output of matcher is the register at an accepting state of the AFA)</typeparam> /// <typeparam name="TAccumulator">Accumulator type</typeparam> /// <param name="source">Input pattern</param> /// <param name="accumulatorInitialization">Initializer function for the accumulator</param> /// <param name="accumulatorBoolField"></param> /// <param name="fence">Condition that must be true for the transition to occur</param> /// <returns>The newly constructed pattern</returns> public static IPattern <TKey, TPayload, TRegister, TAccumulator> AllElement <TKey, TPayload, TRegister, TAccumulator>( this IAbstractPatternRoot <TKey, TPayload, TRegister, TAccumulator> source, Expression <Func <TAccumulator> > accumulatorInitialization, Expression <Func <TAccumulator, bool> > accumulatorBoolField, Expression <Func <long, TPayload, TRegister, bool> > fence) { return(CreateMultiElementFunctions(source, accumulatorInitialization, accumulatorBoolField, fence, true, b => !b)); }
/// <summary> /// Add to the current pattern a new pattern symbol that matches any element /// </summary> /// <typeparam name="TKey">Key type</typeparam> /// <typeparam name="TPayload">Payload type</typeparam> /// <typeparam name="TRegister">Result type (output of matcher is the register at an accepting state of the AFA)</typeparam> /// <param name="source">Input pattern</param> /// <param name="fence">Condition that must be true for the transition to occur</param> /// <returns>The newly constructed pattern</returns> public static IPattern <TKey, TPayload, TRegister, bool> AnyElement <TKey, TPayload, TRegister>( this IAbstractPatternRoot <TKey, TPayload, TRegister, bool> source, Expression <Func <long, TPayload, TRegister, bool> > fence) { Expression <Func <long, TPayload, TRegister, bool, bool> > fenceTemplate = (ts, ev, reg, acc) => CallInliner.Call(fence, ts, ev, reg); return(source.MultiElement((ts, reg) => false, fenceTemplate.InlineCalls(), (ts, ev, acc) => acc, (ts, acc, reg) => acc, null, null)); }
private static IPattern <TKey, TPayload, TRegister, TAccumulator> CreateMultiElementFunctions <TKey, TPayload, TRegister, TAccumulator>(IAbstractPatternRoot <TKey, TPayload, TRegister, TAccumulator> source, Expression <Func <TAccumulator> > accumulatorInitialization, Expression <Func <TAccumulator, bool> > accumulatorboolField, Expression <Func <long, TPayload, TRegister, bool> > fence, bool initialValueForBooleanField, Expression <Func <bool, bool> > shortCircuitCondition) { if (!(accumulatorboolField.Body is MemberExpression memberExpression)) { throw new InvalidOperationException("accumulatorboolField must be a lambda that picks out one field from its parameter"); } if (!(memberExpression.Expression is ParameterExpression parameter)) { throw new InvalidOperationException("accumulatorboolField must be a lambda that picks out one field from its parameter"); } var memberInfo = memberExpression.Member; if (memberInfo is System.Reflection.PropertyInfo propertyInfo && !propertyInfo.CanWrite) { throw new InvalidOperationException("accumulatorboolField is specifying a property, " + propertyInfo.Name + "' that does not have a setter"); } // "f" is the field specified by the accumulatorboolField lambda. // Create the Initialize function as (ts, reg) => { var acc = accumulatorInitialization(); acc.f = initialValueForBooleanField; return acc; } Expression <Func <long, TRegister, TAccumulator> > initializeTemplate = (ts, reg) => CallInliner.Call(accumulatorInitialization); var userInitializeFunction = initializeTemplate.InlineCalls(); var accumulatorLocalForInitialize = Expression.Parameter(typeof(TAccumulator), "acc"); var initializeBody = new List <Expression>() { Expression.Assign(accumulatorLocalForInitialize, userInitializeFunction.Body), Expression.Assign(Expression.MakeMemberAccess(accumulatorLocalForInitialize, memberInfo), Expression.Constant(initialValueForBooleanField, typeof(bool))), accumulatorLocalForInitialize }; var initializeFunction = (Expression <Func <long, TRegister, TAccumulator> >)Expression.Lambda( Expression.Block(new[] { accumulatorLocalForInitialize }, initializeBody), Expression.Parameter(typeof(long), "ts"), Expression.Parameter(typeof(TRegister), "reg")); // Create the Accumulate function as (ts, ev, reg, acc) => { acc.f = fence(ts, ev, reg); return acc; } Expression <Func <long, TPayload, TRegister, TAccumulator, bool> > userAccumulatorFunctionTemplate = (ts, ev, reg, acc) => CallInliner.Call(fence, ts, ev, reg); var userAccumulatorFunction = userAccumulatorFunctionTemplate.InlineCalls(); var accParmeter = userAccumulatorFunction.Parameters[3]; var accumulateBody = new List <Expression>() { Expression.Assign(Expression.MakeMemberAccess(accParmeter, memberInfo), userAccumulatorFunction.Body), accParmeter, }; var parameters = new ParameterExpression[] { userAccumulatorFunction.Parameters[0], userAccumulatorFunction.Parameters[1], userAccumulatorFunction.Parameters[2], accParmeter, }; var accumulateFunction = (Expression <Func <long, TPayload, TRegister, TAccumulator, TAccumulator> >)Expression.Lambda(Expression.Block(accumulateBody), parameters); // Create the SkipToEnd function as (ts, ev, acc) => acc.f Expression <Func <long, TPayload, TAccumulator, bool> > skipToEndTemplate = (ts, ev, acc) => CallInliner.Call(shortCircuitCondition, CallInliner.Call(accumulatorboolField, acc)); var skipToEndFunction = skipToEndTemplate.InlineCalls(); // Create the fence function as (ts, acc, reg) => acc.f Expression <Func <long, TAccumulator, TRegister, bool> > fenceTemplate = (ts, acc, reg) => CallInliner.Call(accumulatorboolField, acc); var fenceFunction = fenceTemplate.InlineCalls(); return(source.MultiElement(initializeFunction, accumulateFunction, skipToEndFunction, fenceFunction, null, null)); }