public override void Visit(TernaryExpression ternary)
        {
            // Evaluates the left expression and saves the value
            ternary.LeftExpression.Accept(this);

            var left = ConversionUtility.Convert <bool>(Result);

            if (left)
            {
                ternary.MiddleExpression.Accept(this);
            }
            else
            {
                ternary.RightExpression.Accept(this);
            }
        }
        public override void Visit(UnaryExpression unary)
        {
            // Recursively evaluates the underlying expression
            unary.Expression.Accept(this);

            switch (unary.Type)
            {
            case UnaryExpressionType.Not:
                Result = !ConversionUtility.Convert <bool>(Result);
                break;

            case UnaryExpressionType.Negate:
                Result = OperatorUtility.Negate(Result);
                break;

            case UnaryExpressionType.BitwiseNot:
                Result = OperatorUtility.Not(Result);
                break;
            }
        }
Esempio n. 3
0
        private IEnumerable <Warning> ValueInputWarnings(ValueInput valueInput)
        {
            // We can disable null reference check if no self is available
            // and the port requires an owner, for example in macros.
            var trustFutureOwner = valueInput.nullMeansSelf && reference.self == null;

            var checkForNullReference = BoltFlow.Configuration.predictPotentialNullReferences && !valueInput.allowsNull && !trustFutureOwner;

            var checkForMissingComponent = BoltFlow.Configuration.predictPotentialMissingComponents && typeof(Component).IsAssignableFrom(valueInput.type);

            // Note that we cannot directly check the input's predicted value, because it
            // will return false for safeguard specifically because it might be missing requirements.
            // Therefore, we first check the connected value, then the default value.

            // If the port is connected to a predictable output, use the connected value to perform checks.
            if (valueInput.hasValidConnection)
            {
                var valueOutput = valueInput.validConnectedPorts.Single();

                if (Flow.CanPredict(valueOutput, reference))
                {
                    if (checkForNullReference)
                    {
                        if (Flow.Predict(valueOutput, reference) == null)
                        {
                            yield return(Warning.Severe($"{PortLabel(valueInput)} cannot be null."));
                        }
                    }

                    if (checkForMissingComponent)
                    {
                        var connectedPredictedValue = Flow.Predict(valueOutput, reference);

                        // This check is necessary, because the predicted value could be
                        // incompatible as connections with non-guaranteed conversions are allowed.
                        if (ConversionUtility.CanConvert(connectedPredictedValue, typeof(GameObject), true))
                        {
                            var gameObject = ConversionUtility.Convert <GameObject>(connectedPredictedValue);

                            if (gameObject != null)
                            {
                                var component = (Component)ConversionUtility.Convert(gameObject, valueInput.type);

                                if (component == null)
                                {
                                    yield return(Warning.Caution($"{PortLabel(valueInput)} is missing a {valueInput.type.DisplayName()} component."));
                                }
                            }
                        }
                    }
                }
            }
            // If the port isn't connected but has a default value, use the default value to perform checks.
            else if (valueInput.hasDefaultValue)
            {
                if (checkForNullReference)
                {
                    if (Flow.Predict(valueInput, reference) == null)
                    {
                        yield return(Warning.Severe($"{PortLabel(valueInput)} cannot be null."));
                    }
                }

                if (checkForMissingComponent)
                {
                    var unconnectedPredictedValue = Flow.Predict(valueInput, reference);

                    if (ConversionUtility.CanConvert(unconnectedPredictedValue, typeof(GameObject), true))
                    {
                        var gameObject = ConversionUtility.Convert <GameObject>(unconnectedPredictedValue);

                        if (gameObject != null)
                        {
                            var component = (Component)ConversionUtility.Convert(gameObject, valueInput.type);

                            if (component == null)
                            {
                                yield return(Warning.Caution($"{PortLabel(valueInput)} is missing a {valueInput.type.DisplayName()} component."));
                            }
                        }
                    }
                }
            }
            // The value isn't connected and has no default value,
            // therefore it is certain to be missing at runtime.
            else
            {
                yield return(Warning.Severe($"{PortLabel(valueInput)} is missing."));
            }
        }
        public override void Visit(BinaryExpression binary)
        {
            // Simulate Lazy<Func<>> behavior for late evaluation
            object        leftValue = null;
            Func <object> left      = () =>
            {
                if (leftValue == null)
                {
                    binary.LeftExpression.Accept(this);
                    leftValue = Result;
                }
                return(leftValue);
            };

            // Simulate Lazy<Func<>> behavior for late evaluation
            object        rightValue = null;
            Func <object> right      = () =>
            {
                if (rightValue == null)
                {
                    binary.RightExpression.Accept(this);
                    rightValue = Result;
                }
                return(rightValue);
            };

            switch (binary.Type)
            {
            case BinaryExpressionType.And:
                Result = ConversionUtility.Convert <bool>(left()) && ConversionUtility.Convert <bool>(right());
                break;

            case BinaryExpressionType.Or:
                Result = ConversionUtility.Convert <bool>(left()) || ConversionUtility.Convert <bool>(right());
                break;

            case BinaryExpressionType.Div:
                Result = OperatorUtility.Divide(left(), right());
                break;

            case BinaryExpressionType.Equal:
                Result = OperatorUtility.Equal(left(), right());
                break;

            case BinaryExpressionType.Greater:
                Result = OperatorUtility.GreaterThan(left(), right());
                break;

            case BinaryExpressionType.GreaterOrEqual:
                Result = OperatorUtility.GreaterThanOrEqual(left(), right());
                break;

            case BinaryExpressionType.Lesser:
                Result = OperatorUtility.LessThan(left(), right());
                break;

            case BinaryExpressionType.LesserOrEqual:
                Result = OperatorUtility.LessThanOrEqual(left(), right());
                break;

            case BinaryExpressionType.Minus:
                Result = OperatorUtility.Subtract(left(), right());
                break;

            case BinaryExpressionType.Modulo:
                Result = OperatorUtility.Modulo(left(), right());
                break;

            case BinaryExpressionType.NotEqual:
                Result = OperatorUtility.NotEqual(left(), right());
                break;

            case BinaryExpressionType.Plus:
                Result = OperatorUtility.Add(left(), right());
                break;

            case BinaryExpressionType.Times:
                Result = OperatorUtility.Multiply(left(), right());
                break;

            case BinaryExpressionType.BitwiseAnd:
                Result = OperatorUtility.And(left(), right());
                break;

            case BinaryExpressionType.BitwiseOr:
                Result = OperatorUtility.Or(left(), right());
                break;

            case BinaryExpressionType.BitwiseXOr:
                Result = OperatorUtility.ExclusiveOr(left(), right());
                break;

            case BinaryExpressionType.LeftShift:
                Result = OperatorUtility.LeftShift(left(), right());
                break;

            case BinaryExpressionType.RightShift:
                Result = OperatorUtility.RightShift(left(), right());
                break;
            }
        }
        public override void Visit(FunctionExpression function)
        {
            var args = new FunctionArgs
            {
                Parameters = new Expression[function.Expressions.Length]
            };

            // Don't call parameters right now, instead let the function do it as needed.
            // Some parameters shouldn't be called, for instance, in a if(), the "not" value might be a division by zero
            // Evaluating every value could produce unexpected behaviour
            for (var i = 0; i < function.Expressions.Length; i++)
            {
                args.Parameters[i] = new Expression(function.Expressions[i], options);
                args.Parameters[i].EvaluateFunction  += EvaluateFunction;
                args.Parameters[i].EvaluateParameter += EvaluateParameter;

                // Assign the parameters of the Expression to the arguments so that custom Functions and Parameters can use them
                args.Parameters[i].Parameters = Parameters;
            }

            // Calls external implementation
            OnEvaluateFunction(IgnoreCase ? function.Identifier.Name.ToLower() : function.Identifier.Name, args);

            // If an external implementation was found get the result back
            if (args.HasResult)
            {
                Result = args.Result;
                return;
            }

            switch (function.Identifier.Name.ToLower(CultureInfo.InvariantCulture))
            {
            case "abs":
                CheckCase(function, "Abs");
                CheckExactArgumentCount(function, 1);
                Result = Mathf.Abs(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])));
                break;

            case "acos":
                CheckCase(function, "Acos");
                CheckExactArgumentCount(function, 1);
                Result = Mathf.Acos(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])));
                break;

            case "asin":
                CheckCase(function, "Asin");
                CheckExactArgumentCount(function, 1);
                Result = Mathf.Asin(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])));
                break;

            case "atan":
                CheckCase(function, "Atan");
                CheckExactArgumentCount(function, 1);
                Result = Mathf.Atan(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])));
                break;

            case "ceil":
                CheckCase(function, "Ceil");
                CheckExactArgumentCount(function, 1);
                Result = Mathf.Ceil(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])));
                break;

            case "cos":
                CheckCase(function, "Cos");
                CheckExactArgumentCount(function, 1);
                Result = Mathf.Cos(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])));
                break;

            case "exp":
                CheckCase(function, "Exp");
                CheckExactArgumentCount(function, 1);
                Result = Mathf.Exp(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])));
                break;

            case "floor":
                CheckCase(function, "Floor");
                CheckExactArgumentCount(function, 1);
                Result = Mathf.Floor(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])));
                break;

            case "log":
                CheckCase(function, "Log");
                CheckExactArgumentCount(function, 2);
                Result = Mathf.Log(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])), ConversionUtility.Convert <float>(Evaluate(function.Expressions[1])));
                break;

            case "log10":
                CheckCase(function, "Log10");
                CheckExactArgumentCount(function, 1);
                Result = Mathf.Log10(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])));
                break;

            case "pow":
                CheckCase(function, "Pow");
                CheckExactArgumentCount(function, 2);
                Result = Mathf.Pow(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])), ConversionUtility.Convert <float>(Evaluate(function.Expressions[1])));
                break;

            case "round":
                CheckCase(function, "Round");
                CheckExactArgumentCount(function, 1);
                //var rounding = (options & EvaluateOptions.RoundAwayFromZero) == EvaluateOptions.RoundAwayFromZero ? MidpointRounding.AwayFromZero : MidpointRounding.ToEven;
                Result = Mathf.Round(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])));
                break;

            case "sign":
                CheckCase(function, "Sign");
                CheckExactArgumentCount(function, 1);
                Result = Mathf.Sign(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])));

                break;

            case "sin":
                CheckCase(function, "Sin");
                CheckExactArgumentCount(function, 1);
                Result = Mathf.Sin(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])));
                break;

            case "sqrt":
                CheckCase(function, "Sqrt");
                CheckExactArgumentCount(function, 1);
                Result = Mathf.Sqrt(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])));

                break;

            case "tan":
                CheckCase(function, "Tan");
                CheckExactArgumentCount(function, 1);
                Result = Mathf.Tan(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])));

                break;

            case "max":
                CheckCase(function, "Max");
                CheckExactArgumentCount(function, 2);
                Result = Mathf.Max(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])), ConversionUtility.Convert <float>(Evaluate(function.Expressions[1])));
                break;

            case "min":
                CheckCase(function, "Min");
                CheckExactArgumentCount(function, 2);
                Result = Mathf.Min(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])), ConversionUtility.Convert <float>(Evaluate(function.Expressions[1])));
                break;

            case "in":
                CheckCase(function, "In");
                CheckExactArgumentCount(function, 2);

                var parameter = Evaluate(function.Expressions[0]);

                var evaluation = false;

                // Goes through any values, and stop whe one is found
                for (var i = 1; i < function.Expressions.Length; i++)
                {
                    var argument = Evaluate(function.Expressions[i]);

                    if (Equals(parameter, argument))
                    {
                        evaluation = true;
                        break;
                    }
                }

                Result = evaluation;
                break;

            default:
                throw new ArgumentException("Function not found", function.Identifier.Name);
            }
        }
Esempio n. 6
0
 public static object Predict(IUnitValuePort port, GraphReference reference, Type type)
 {
     return(ConversionUtility.Convert(Predict(port, reference), type));
 }
Esempio n. 7
0
 public static object FetchValue(ValueInput input, Type type, GraphReference reference)
 {
     return(ConversionUtility.Convert(FetchValue(input, reference), type));
 }
Esempio n. 8
0
 public object GetValue(ValueInput input, Type type)
 {
     return(ConversionUtility.Convert(GetValue(input), type));
 }