From b41270e23c7b391d3208d43022965f3359300f0f Mon Sep 17 00:00:00 2001 From: Devin Duanne Date: Thu, 16 Nov 2023 15:35:41 -0600 Subject: [PATCH 1/2] Expose types. Add AddAssign, DecrementAssign, Increment, and Decrement expressions --- .../Expressions/AddAssign.cs | 98 +++++++++++++++ .../Expressions/BinaryExpressionHelper.cs | 23 +++- .../Expressions/Decrement.cs | 76 ++++++++++++ .../Expressions/Increment.cs | 76 ++++++++++++ .../Expressions/SubtractAssign.cs | 117 ++++++++++++++++++ .../Expressions/UnaryExpressionHelper.cs | 38 +++++- 6 files changed, 426 insertions(+), 2 deletions(-) create mode 100644 src/UiPath.Workflow.Runtime/Expressions/AddAssign.cs create mode 100644 src/UiPath.Workflow.Runtime/Expressions/Decrement.cs create mode 100644 src/UiPath.Workflow.Runtime/Expressions/Increment.cs create mode 100644 src/UiPath.Workflow.Runtime/Expressions/SubtractAssign.cs diff --git a/src/UiPath.Workflow.Runtime/Expressions/AddAssign.cs b/src/UiPath.Workflow.Runtime/Expressions/AddAssign.cs new file mode 100644 index 00000000..ca1261c0 --- /dev/null +++ b/src/UiPath.Workflow.Runtime/Expressions/AddAssign.cs @@ -0,0 +1,98 @@ +// This file is part of Core WF which is licensed under the MIT license. +// See LICENSE file in the project root for full license information. + +using System.Activities.Validation; +using System.ComponentModel; +using System.Linq.Expressions; +using System.Numerics; + +namespace System.Activities.Expressions +{ + /// + /// A code activity which incrementally assigns a numeral. + /// + /// + /// int myNum = 5; + /// myNum += 5; // 10. + /// + /// The operand to modify. + /// The operand with which to modify . + /// The resulting type of hte operation. + public sealed class AddAssign : CodeActivity +#if NET7_0_OR_GREATER + where TLeft : INumber + where TRight : INumber + where TResult : INumber +#endif + { + private static Func? checkedOperationFunction = null; + private static Func? uncheckedOperationFunction = null; + + /// + /// Gets or sets the left operand which will be modified by this operation. + /// + [RequiredArgument] + public InArgument Left { get; set; } = new(); + + /// + /// Gets or sets the right operand which will be the modifier for this operation. + /// + [RequiredArgument] + public InArgument Right { get; set; } = new(); + + /// + /// Gets or sets a value indicating whether this operation will happen in a checked or unchecked context. + /// + [DefaultValue(true)] + public bool IsChecked { get; set; } = true; + + /// + protected override void CacheMetadata(CodeActivityMetadata metadata) + { + BinaryExpressionHelper.OnGetArguments(metadata, Left, Right); + + if (IsChecked) + { + EnsureOperationFunction(metadata, ref checkedOperationFunction, ExpressionType.AddAssignChecked); + } + else + { + EnsureOperationFunction(metadata, ref uncheckedOperationFunction, ExpressionType.AddAssign); + } + } + + private static void EnsureOperationFunction + ( + CodeActivityMetadata metadata, + ref Func? operationFunction, + ExpressionType operatorType + ) + { + if (operationFunction == null) + { + if (!BinaryExpressionHelper.TryGenerateLinqDelegate( + operatorType, + out operationFunction, + out ValidationError? validationError)) + { + metadata.AddValidationError(validationError); + } + } + } + + /// + protected override TResult Execute(CodeActivityContext context) + { + TLeft leftValue = Left.Get(context); + TRight rightValue = Right.Get(context); + + // If user changed checked flag between open and execution, an NRE may be thrown. + // This is by design. + // Nullability check silenced because the corresponding value is guaranteed to be + // non-null + return IsChecked + ? checkedOperationFunction!(leftValue, rightValue) + : uncheckedOperationFunction!(leftValue, rightValue); + } + } +} diff --git a/src/UiPath.Workflow.Runtime/Expressions/BinaryExpressionHelper.cs b/src/UiPath.Workflow.Runtime/Expressions/BinaryExpressionHelper.cs index 8bec8c78..abc96584 100644 --- a/src/UiPath.Workflow.Runtime/Expressions/BinaryExpressionHelper.cs +++ b/src/UiPath.Workflow.Runtime/Expressions/BinaryExpressionHelper.cs @@ -8,8 +8,19 @@ namespace System.Activities.Expressions; -internal static class BinaryExpressionHelper +/// +/// Helpers for binary expressions. +/// +public static class BinaryExpressionHelper { + /// + /// Binds metadata when getting arguments. + /// + /// The type of the left argument. + /// The type of the right argument. + /// The metadata. + /// The left argument. + /// The right argument. public static void OnGetArguments(CodeActivityMetadata metadata, InArgument left, InArgument right) { RuntimeArgument rightArgument = new("Right", typeof(TRight), ArgumentDirection.In, true); @@ -26,6 +37,16 @@ internal static class BinaryExpressionHelper }); } + /// + /// Generates a delegate. + /// + /// The type of the left argument. + /// The type of the right argument. + /// The return type of the operation. + /// The type of expression. + /// The resulting . + /// If the operation failed, the error. + /// if the operation was successful; otherwise, . public static bool TryGenerateLinqDelegate(ExpressionType operatorType, out Func function, out ValidationError validationError) { function = null; diff --git a/src/UiPath.Workflow.Runtime/Expressions/Decrement.cs b/src/UiPath.Workflow.Runtime/Expressions/Decrement.cs new file mode 100644 index 00000000..224d702d --- /dev/null +++ b/src/UiPath.Workflow.Runtime/Expressions/Decrement.cs @@ -0,0 +1,76 @@ +// +// Decrement.cs +// +// Author: +// Devin Duanne +// +// Copyright (c) TAFS, LLC. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// + +using System.Activities.Validation; +using System.Linq.Expressions; +using System.Numerics; + +namespace System.Activities.Expressions +{ + /// + /// A code activity which decrements a numeral. + /// + /// A numeric value, such as or . + public sealed class Decrement : CodeActivity +#if NET7_0_OR_GREATER + where TNumeral : IIncrementOperators +#endif + { + private static Func? operationFunction = null!; + + /// + /// Gets or sets the numeral value that will be incremented. + /// + [RequiredArgument] + public InOutArgument Numeral { get; set; } = new(); + + /// + protected override void CacheMetadata(CodeActivityMetadata metadata) + { + UnaryExpressionHelper.OnGetArguments(metadata, Numeral); + EnsureOperationFunction(metadata, ref operationFunction!, ExpressionType.Decrement); + } + + private static void EnsureOperationFunction + ( + CodeActivityMetadata metadata, + ref Func operationFunction, + ExpressionType operatorType + ) + { + if (operationFunction is null) + { + if (!UnaryExpressionHelper.TryGenerateLinqDelegate(operatorType, out operationFunction!, out ValidationError? validationError)) + { + metadata.AddValidationError(validationError); + } + } + } + + /// + protected override TNumeral Execute(CodeActivityContext context) + { + TNumeral value = Numeral.Get(context); + return operationFunction!.Invoke(value); + } + } +} diff --git a/src/UiPath.Workflow.Runtime/Expressions/Increment.cs b/src/UiPath.Workflow.Runtime/Expressions/Increment.cs new file mode 100644 index 00000000..b8a9caef --- /dev/null +++ b/src/UiPath.Workflow.Runtime/Expressions/Increment.cs @@ -0,0 +1,76 @@ +// +// Increment.cs +// +// Author: +// Devin Duanne +// +// Copyright (c) TAFS, LLC. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// + +using System.Activities.Validation; +using System.Linq.Expressions; +using System.Numerics; + +namespace System.Activities.Expressions +{ + /// + /// A code activity which increments a numeral. + /// + /// A numeric value, such as or . + public sealed class Increment : CodeActivity +#if NET7_0_OR_GREATER + where TNumeral : IIncrementOperators +#endif + { + private static Func? operationFunction = null!; + + /// + /// Gets or sets the numeral value that will be incremented. + /// + [RequiredArgument] + public InOutArgument Numeral { get; set; } = new(); + + /// + protected override void CacheMetadata(CodeActivityMetadata metadata) + { + UnaryExpressionHelper.OnGetArguments(metadata, Numeral); + EnsureOperationFunction(metadata, ref operationFunction!, ExpressionType.Increment); + } + + private static void EnsureOperationFunction + ( + CodeActivityMetadata metadata, + ref Func operationFunction, + ExpressionType operatorType + ) + { + if (operationFunction is null) + { + if (!UnaryExpressionHelper.TryGenerateLinqDelegate(operatorType, out operationFunction!, out ValidationError? validationError)) + { + metadata.AddValidationError(validationError); + } + } + } + + /// + protected override TNumeral Execute(CodeActivityContext context) + { + TNumeral value = Numeral.Get(context); + return operationFunction!.Invoke(value); + } + } +} diff --git a/src/UiPath.Workflow.Runtime/Expressions/SubtractAssign.cs b/src/UiPath.Workflow.Runtime/Expressions/SubtractAssign.cs new file mode 100644 index 00000000..dab74a36 --- /dev/null +++ b/src/UiPath.Workflow.Runtime/Expressions/SubtractAssign.cs @@ -0,0 +1,117 @@ +// +// SubtractAssign.cs +// +// Author: +// Devin Duanne +// +// Copyright (c) TAFS, LLC. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// + +using System.Activities.Validation; +using System.ComponentModel; +using System.Linq.Expressions; +using System.Numerics; + +namespace System.Activities.Expressions +{ + /// + /// A code activity which deccrementally assigns a numeral. + /// + /// + /// int myNum = 5; + /// myNum += 5; // 10. + /// + /// The operand to modify. + /// The operand with which to modify . + /// The resulting type of hte operation. + public sealed class SubtractAssign : CodeActivity +#if NET7_0_OR_GREATER + where TLeft : INumber + where TRight : INumber + where TResult : INumber +#endif + { + private static Func? checkedOperationFunction = null; + private static Func? uncheckedOperationFunction = null; + + /// + /// Gets or sets the left operand which will be modified by this operation. + /// + [RequiredArgument] + public InArgument Left { get; set; } = new(); + + /// + /// Gets or sets the right operand which will be the modifier for this operation. + /// + [RequiredArgument] + public InArgument Right { get; set; } = new(); + + /// + /// Gets or sets a value indicating whether this operation will happen in a checked or unchecked context. + /// + [DefaultValue(true)] + public bool IsChecked { get; set; } = true; + + /// + protected override void CacheMetadata(CodeActivityMetadata metadata) + { + BinaryExpressionHelper.OnGetArguments(metadata, Left, Right); + + if (IsChecked) + { + EnsureOperationFunction(metadata, ref checkedOperationFunction, ExpressionType.SubtractAssignChecked); + } + else + { + EnsureOperationFunction(metadata, ref uncheckedOperationFunction, ExpressionType.SubtractAssign); + } + } + + private static void EnsureOperationFunction + ( + CodeActivityMetadata metadata, + ref Func? operationFunction, + ExpressionType operatorType + ) + { + if (operationFunction == null) + { + if (!BinaryExpressionHelper.TryGenerateLinqDelegate( + operatorType, + out operationFunction, + out ValidationError? validationError)) + { + metadata.AddValidationError(validationError); + } + } + } + + /// + protected override TResult Execute(CodeActivityContext context) + { + TLeft leftValue = Left.Get(context); + TRight rightValue = Right.Get(context); + + // If user changed checked flag between open and execution, an NRE may be thrown. + // This is by design. + // Nullability check silenced because the corresponding value is guaranteed to be + // non-null + return IsChecked + ? checkedOperationFunction!(leftValue, rightValue) + : uncheckedOperationFunction!(leftValue, rightValue); + } + } +} diff --git a/src/UiPath.Workflow.Runtime/Expressions/UnaryExpressionHelper.cs b/src/UiPath.Workflow.Runtime/Expressions/UnaryExpressionHelper.cs index 714f1879..977ce3f7 100644 --- a/src/UiPath.Workflow.Runtime/Expressions/UnaryExpressionHelper.cs +++ b/src/UiPath.Workflow.Runtime/Expressions/UnaryExpressionHelper.cs @@ -8,8 +8,17 @@ namespace System.Activities.Expressions; -internal static class UnaryExpressionHelper +/// +/// Helpers for unary expressions. +/// +public static class UnaryExpressionHelper { + /// + /// Binds the metadata for the argument. + /// + /// The type of the argument. + /// The metadata. + /// The argument. public static void OnGetArguments(CodeActivityMetadata metadata, InArgument operand) { RuntimeArgument operandArgument = new("Operand", typeof(TOperand), ArgumentDirection.In, true); @@ -22,6 +31,33 @@ public static void OnGetArguments(CodeActivityMetadata metadata, InArg }); } + /// + /// Binds the metadata for the argument. + /// + /// The type of the argument. + /// The metadata. + /// The argument. + public static void OnGetArguments(CodeActivityMetadata metadata, InOutArgument operand) + { + RuntimeArgument operandArgument = new("Operand", typeof(TOperand), ArgumentDirection.InOut, true); + metadata.Bind(operand, operandArgument); + + metadata.SetArgumentsCollection( + new Collection + { + operandArgument + }); + } + + /// + /// Generates a delegate. + /// + /// The type of the argument. + /// The return type of the operation. + /// The type of expression. + /// The resulting . + /// If the operation failed, the error. + /// if the operation was successful; otherwise, . public static bool TryGenerateLinqDelegate(ExpressionType operatorType, out Func operation, out ValidationError validationError) { operation = null; From 13ddf5c1b7516b690b66cbca11644a64d832bc03 Mon Sep 17 00:00:00 2001 From: Devin Duanne Date: Thu, 16 Nov 2023 15:42:13 -0600 Subject: [PATCH 2/2] Fix license headers --- .../Expressions/Decrement.cs | 23 ++----------------- .../Expressions/Increment.cs | 23 ++----------------- .../Expressions/SubtractAssign.cs | 23 ++----------------- 3 files changed, 6 insertions(+), 63 deletions(-) diff --git a/src/UiPath.Workflow.Runtime/Expressions/Decrement.cs b/src/UiPath.Workflow.Runtime/Expressions/Decrement.cs index 224d702d..c9a93dcf 100644 --- a/src/UiPath.Workflow.Runtime/Expressions/Decrement.cs +++ b/src/UiPath.Workflow.Runtime/Expressions/Decrement.cs @@ -1,24 +1,5 @@ -// -// Decrement.cs -// -// Author: -// Devin Duanne -// -// Copyright (c) TAFS, LLC. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see . -// +// This file is part of Core WF which is licensed under the MIT license. +// See LICENSE file in the project root for full license information. using System.Activities.Validation; using System.Linq.Expressions; diff --git a/src/UiPath.Workflow.Runtime/Expressions/Increment.cs b/src/UiPath.Workflow.Runtime/Expressions/Increment.cs index b8a9caef..5837056b 100644 --- a/src/UiPath.Workflow.Runtime/Expressions/Increment.cs +++ b/src/UiPath.Workflow.Runtime/Expressions/Increment.cs @@ -1,24 +1,5 @@ -// -// Increment.cs -// -// Author: -// Devin Duanne -// -// Copyright (c) TAFS, LLC. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see . -// +// This file is part of Core WF which is licensed under the MIT license. +// See LICENSE file in the project root for full license information. using System.Activities.Validation; using System.Linq.Expressions; diff --git a/src/UiPath.Workflow.Runtime/Expressions/SubtractAssign.cs b/src/UiPath.Workflow.Runtime/Expressions/SubtractAssign.cs index dab74a36..0fe57915 100644 --- a/src/UiPath.Workflow.Runtime/Expressions/SubtractAssign.cs +++ b/src/UiPath.Workflow.Runtime/Expressions/SubtractAssign.cs @@ -1,24 +1,5 @@ -// -// SubtractAssign.cs -// -// Author: -// Devin Duanne -// -// Copyright (c) TAFS, LLC. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see . -// +// This file is part of Core WF which is licensed under the MIT license. +// See LICENSE file in the project root for full license information. using System.Activities.Validation; using System.ComponentModel;