Exemple #1
0
        public override BoundNode VisitPrefixUnaryExpression(PrefixUnaryExpressionSyntax node)
        {
            MethodSymbol unaryMethodSymbol = (MethodSymbol)GetSymbol(node);

            BoundExpression expression = VisitExpression(node.Operand, unaryMethodSymbol.Parameters[0].Type);

            // + operator is a no-op on builtins so ignore it until we allow user operator overloads
            if (node.OperatorToken.Kind() == SyntaxKind.PlusToken)
            {
                return(expression);
            }

            BoundExpression constantResult = ConstantExpressionOptimizer.FoldConstantUnaryPrefixExpression(Context, node, unaryMethodSymbol, expression);

            if (constantResult != null)
            {
                return(constantResult);
            }

            if (node.Kind() == SyntaxKind.PreIncrementExpression ||
                node.Kind() == SyntaxKind.PreDecrementExpression)
            {
                return(new BoundInvocationExpression.BoundPrefixOperatorExpression(Context, node,
                                                                                   (BoundAccessExpression)expression, unaryMethodSymbol));
            }

            return(BoundInvocationExpression.CreateBoundInvocation(Context, node, unaryMethodSymbol, null, new[] { expression }));
        }
Exemple #2
0
        public override BoundNode VisitObjectCreationExpression(ObjectCreationExpressionSyntax node)
        {
            if (node.Initializer != null)
            {
                throw new NotSupportedException(LocStr.CE_InitializerListsNotSupported, node);
            }

            MethodSymbol constructorSymbol = (MethodSymbol)GetSymbol(node);

            BoundExpression[] boundArguments = new BoundExpression[node.ArgumentList.Arguments.Count];

            bool isConstant = true;

            for (int i = 0; i < boundArguments.Length; ++i)
            {
                boundArguments[i] = VisitExpression(node.ArgumentList.Arguments[i].Expression, constructorSymbol.Parameters[i].Type);
                isConstant       &= boundArguments[i].IsConstant;
            }

            // Constant folding on struct creation when possible
            // Also implicitly handles parameterless constructors on value types, which Udon does not expose constructors for
            if (isConstant && constructorSymbol.IsExtern && constructorSymbol.ContainingType.IsValueType)
            {
                var constArgs = boundArguments.Select(e => e.ConstantValue.Value).ToArray();

                object constantValue = Activator.CreateInstance(constructorSymbol.ContainingType.UdonType.SystemType, constArgs);

                IConstantValue constantStore = (IConstantValue)Activator.CreateInstance(typeof(ConstantValue <>).MakeGenericType(constantValue.GetType()), constantValue);

                return(new BoundConstantExpression(constantStore, constructorSymbol.ContainingType, node));
            }

            return(BoundInvocationExpression.CreateBoundInvocation(Context, node, constructorSymbol, null, boundArguments));
        }
Exemple #3
0
        public override BoundNode VisitAssignmentExpression(AssignmentExpressionSyntax node)
        {
            BoundAccessExpression assignmentTarget = VisitAccessExpression(node.Left);

            if (node.Kind() != SyntaxKind.SimpleAssignmentExpression)
            {
                MethodSymbol operatorSymbol = (MethodSymbol)GetSymbol(node);

                BoundExpression rhsExpression = VisitExpression(node.Right);

                // Apparently Roslyn returns string + string for string += char, but returns string + object for string + char /shrug
                // Do ToString here if the constant folding can't convert the char
                if (assignmentTarget.ValueType == Context.GetTypeSymbol(SpecialType.System_String) &&
                    rhsExpression.ValueType == Context.GetTypeSymbol(SpecialType.System_Char))
                {
                    if (rhsExpression.IsConstant)
                    {
                        rhsExpression = new BoundConstantExpression(rhsExpression.ConstantValue.Value.ToString(), Context.GetTypeSymbol(SpecialType.System_String));
                    }
                    else
                    {
                        rhsExpression = BoundInvocationExpression.CreateBoundInvocation(Context, node, Context.GetTypeSymbol(SpecialType.System_Char).GetMember <MethodSymbol>("ToString", Context), rhsExpression, Array.Empty <BoundExpression>());
                    }
                }
                if (operatorSymbol is ExternBuiltinOperatorSymbol builtinOperatorSymbol)
                {
                    operatorSymbol = new ExternSynthesizedOperatorSymbol(builtinOperatorSymbol.OperatorType,
                                                                         assignmentTarget.ValueType, Context);
                }

                return(BoundInvocationExpression.CreateBoundInvocation(Context, node, operatorSymbol, null,
                                                                       new[] { assignmentTarget, ConvertExpression(node, rhsExpression, operatorSymbol.Parameters[1].Type) }));
            }
            return(new BoundAssignmentExpression(node, assignmentTarget, VisitExpression(node.Right, assignmentTarget.ValueType)));
        }
Exemple #4
0
        public override BoundNode VisitBinaryExpression(BinaryExpressionSyntax node)
        {
            if (node.Kind() == SyntaxKind.LogicalOrExpression ||
                node.Kind() == SyntaxKind.LogicalAndExpression)
            {
                return(HandleShortCircuitOperator(node));
            }

            if (node.Kind() == SyntaxKind.CoalesceExpression)
            {
                return(HandleNullCoalescingExpression(node));
            }

            MethodSymbol binaryMethodSymbol = (MethodSymbol)GetSymbol(node);

            BoundExpression lhs = VisitExpression(node.Left, binaryMethodSymbol.Parameters[0].Type);
            BoundExpression rhs = VisitExpression(node.Right, binaryMethodSymbol.Parameters[1].Type);

            BoundExpression constantResult = ConstantExpressionOptimizer.FoldConstantBinaryExpression(Context, node, binaryMethodSymbol, lhs, rhs);

            if (constantResult != null)
            {
                return(constantResult);
            }

            return(BoundInvocationExpression.CreateBoundInvocation(Context, node, binaryMethodSymbol, null, new[] { lhs, rhs }));
        }
            public override Value EmitSet(EmitContext context, BoundExpression valueExpression)
            {
                if (SourceExpression == null || SourceExpression.IsThis)
                {
                    return(context.EmitValueAssignment(context.GetUserValue(Field), valueExpression));
                }

                if (Field.HasAttribute <FieldChangeCallbackAttribute>())
                {
                    throw new CompilerException("Cannot set field on U# behaviour by reference when that field has a FieldChangeCallback attribute.");
                }

                TypeSymbol   stringType = context.GetTypeSymbol(SpecialType.System_String);
                MethodSymbol setProgramVariableMethod = context.GetTypeSymbol(typeof(UdonSharpBehaviour))
                                                        .GetMembers <MethodSymbol>("SetProgramVariable", context)
                                                        .First(e => e.Parameters.Length == 2 &&
                                                               e.Parameters[0].Type == stringType);

                Value value = context.EmitValue(valueExpression);

                context.Emit(BoundInvocationExpression.CreateBoundInvocation(context, SyntaxNode,
                                                                             setProgramVariableMethod, SourceExpression,
                                                                             new BoundExpression[]
                {
                    BindAccess(context.GetConstantValue(stringType, Field.Name)),
                    BindAccess(value)
                }));

                return(value);
            }
        public override Value EmitValue(EmitContext context)
        {
            // We don't want any references outside the flow control to be dirtied conditionally
            context.TopTable.DirtyAllValues();

            Value returnValue = context.GetReturnValue(ValueType);

            context.EmitValueAssignment(returnValue, Lhs);

            TypeSymbol systemObjectType = context.GetTypeSymbol(SpecialType.System_Object);

            MethodSymbol objectEquality = new ExternSynthesizedOperatorSymbol(BuiltinOperatorType.Equality, systemObjectType, context);

            Value conditionCheck = context.EmitValue(BoundInvocationExpression.CreateBoundInvocation(context, null,
                                                                                                     objectEquality, null,
                                                                                                     new BoundExpression[]
            {
                BoundAccessExpression.BindAccess(returnValue),
                BoundAccessExpression.BindAccess(context.GetConstantValue(systemObjectType, null))
            }));

            JumpLabel notNullLabel = context.Module.CreateLabel();

            context.Module.AddJumpIfFalse(notNullLabel, conditionCheck);

            context.EmitValueAssignment(returnValue, Rhs);

            context.Module.LabelJump(notNullLabel);

            return(returnValue);
        }
        public override Value EmitSet(EmitContext context, BoundExpression valueExpression)
        {
            BoundExpression instanceValue = GetInstanceExpression(context);

            BoundInvocationExpression invocationExpression = BoundInvocationExpression.CreateBoundInvocation(context, SyntaxNode,
                                                                                                             Property.SetMethod,
                                                                                                             instanceValue, GetParameters(context, valueExpression));

            if (_isBaseCall)
            {
                invocationExpression.MarkForcedBaseCall();
            }

            invocationExpression.MarkPropertySetter();

            Value resultVal = context.EmitValue(invocationExpression);

            if (resultVal == null)
            {
                throw new NullReferenceException();
            }

            if (instanceValue != null &&
                SourceExpression.ValueType.IsValueType &&
                SourceExpression is BoundArrayAccessExpression sourceAccessExpression)
            {
                context.EmitSet(sourceAccessExpression, instanceValue);
            }

            return(resultVal);
        }
        public override Value EmitValue(EmitContext context)
        {
            BoundInvocationExpression invocationExpression = BoundInvocationExpression.CreateBoundInvocation(context, SyntaxNode,
                                                                                                             Property.GetMethod,
                                                                                                             GetInstanceExpression(context), GetParameters(context));

            if (_isBaseCall)
            {
                invocationExpression.MarkForcedBaseCall();
            }

            return(context.EmitValue(invocationExpression));
        }
            public override Value EmitValue(EmitContext context)
            {
                if (SourceExpression == null || SourceExpression.IsThis)
                {
                    return(context.GetUserValue(Field));
                }

                TypeSymbol   stringType = context.GetTypeSymbol(SpecialType.System_String);
                MethodSymbol setProgramVariableMethod = context.GetTypeSymbol(typeof(UdonSharpBehaviour))
                                                        .GetMembers <MethodSymbol>("GetProgramVariable", context)
                                                        .First(e => e.Parameters.Length == 1 &&
                                                               e.Parameters[0].Type == stringType);

                return(context.CastValue(context.EmitValue(BoundInvocationExpression.CreateBoundInvocation(context, SyntaxNode,
                                                                                                           setProgramVariableMethod, SourceExpression,
                                                                                                           new BoundExpression[]
                {
                    BindAccess(context.GetConstantValue(stringType, Field.Name))
                })), Field.Type, true));
            }
        public override Value EmitValue(EmitContext context)
        {
            Value returnValue = context.GetReturnValue(ValueType);

            var charArray = BoundInvocationExpression.CreateBoundInvocation(context, SyntaxNode, _toCharArraySymbol,
                                                                            BindAccess(context.EmitValue(SourceExpression)), new[]
            {
                IndexerExpression,
                BindAccess(context.GetConstantValue(context.GetTypeSymbol(SpecialType.System_Int32), 1))
            });

            context.EmitValueAssignment(returnValue,
                                        BindElementAccess(context, SyntaxNode, charArray,
                                                          new BoundExpression[]
            {
                BindAccess(context.GetConstantValue(context.GetTypeSymbol(SpecialType.System_Int32), 0))
            }));

            return(returnValue);
        }
        public override Value EmitValue(EmitContext context)
        {
            BoundInvocationExpression formatInvoke;

            if (InterpolationExpressions.Length > 3)
            {
                BoundConstArrayCreationExpression interpolationArray =
                    new BoundConstArrayCreationExpression(SyntaxNode, ObjectArr, InterpolationExpressions);

                BoundAccessExpression arrayAccess =
                    BoundAccessExpression.BindAccess(context.EmitValue(interpolationArray));

                formatInvoke = BoundInvocationExpression.CreateBoundInvocation(context, SyntaxNode, StringFormatMethod,
                                                                               null, new BoundExpression[] { BuiltStr, arrayAccess });
            }
            else
            {
                formatInvoke = BoundInvocationExpression.CreateBoundInvocation(context, SyntaxNode, StringFormatMethod,
                                                                               null, new BoundExpression[] { BuiltStr }.Concat(InterpolationExpressions).ToArray());
            }

            return(context.EmitValue(formatInvoke));
        }
Exemple #12
0
        public override BoundNode VisitInvocationExpression(InvocationExpressionSyntax node)
        {
            MethodSymbol methodSymbol = (MethodSymbol)GetSymbol(node);

            // Check if the symbol is null because you can technically have methods named nameof since it is not reserved
            if (methodSymbol == null &&
                node.Expression is IdentifierNameSyntax nameSyntax &&
                nameSyntax.Identifier.Text == "nameof")
            {
                return(HandleNameOfExpression(node));
            }

            BoundExpression instanceExpression = null;

            if (node.Expression is MemberAccessExpressionSyntax accessExpressionSyntax)
            {
                instanceExpression = VisitExpression(accessExpressionSyntax.Expression);
            }

            // Implicit this on member functions for this behaviour
            if (instanceExpression == null &&
                !methodSymbol.IsStatic &&
                methodSymbol.IsExtern)
            {
                instanceExpression = BoundAccessExpression.BindThisAccess(OwningSymbol.ContainingType);
            }

            BoundExpression[] boundArguments = new BoundExpression[methodSymbol.Parameters.Length];
            var argumentsList = node.ArgumentList.Arguments;

            int startIdx = 0;

            if (instanceExpression != null && methodSymbol.RoslynSymbol.IsExtensionMethod)
            {
                boundArguments[0]  = instanceExpression;
                instanceExpression = null;
                startIdx           = 1;
            }

            bool           hasParams        = false;
            int            handledArgsCount = startIdx;
            ArgumentSyntax paramsNamedArg   = null;

            for (int i = startIdx; i < boundArguments.Length; ++i)
            {
                if (methodSymbol.Parameters[i].IsParams)
                {
                    hasParams      = true;
                    paramsNamedArg = argumentsList.FirstOrDefault(x => x.NameColon?.Name.Identifier.ValueText == methodSymbol.Parameters[i].Name);

                    break;
                }

                ArgumentSyntax argument;

                if (i - startIdx >= argumentsList.Count)
                {
                    argument = null;
                }
                else if (argumentsList[i - startIdx].NameColon != null)
                {
                    argument = argumentsList.FirstOrDefault(x => x.NameColon?.Name.Identifier.ValueText == methodSymbol.Parameters[i].Name);
                }
                else
                {
                    argument = argumentsList[i - startIdx];
                }

                if (argument == null) // Default argument handling
                {
                    boundArguments[i] = new BoundConstantExpression(methodSymbol.Parameters[i].DefaultValue, methodSymbol.Parameters[i].Type, node);
                    continue;
                }

                boundArguments[i] = VisitExpression(argument.Expression, methodSymbol.Parameters[i].Type);
                handledArgsCount++;
            }

            if (hasParams)
            {
                int paramCount;

                BoundExpression[] paramExpressions;

                if (paramsNamedArg != null)
                {
                    paramCount       = 1;
                    paramExpressions = new BoundExpression[paramCount];

                    paramExpressions[0] = VisitExpression(paramsNamedArg.Expression);
                }
                else
                {
                    paramCount       = argumentsList.Count - handledArgsCount;
                    paramExpressions = new BoundExpression[paramCount];

                    int idx = 0;
                    for (int i = handledArgsCount; i < argumentsList.Count; ++i)
                    {
                        paramExpressions[idx++] = VisitExpression(argumentsList[i].Expression);
                    }
                }

                void SetParamsArray()
                {
                    TypeSymbol paramType = methodSymbol.Parameters.Last().Type;

                    boundArguments[boundArguments.Length - 1] = new BoundConstArrayCreationExpression(node, paramType,
                                                                                                      paramExpressions.Select(e => ConvertExpression(node, e, paramType.ElementType)).ToArray());
                }

                void SetDirectParam()
                {
                    boundArguments[boundArguments.Length - 1] = paramExpressions[0];
                }

                if (paramCount != 1)
                {
                    SetParamsArray();
                }
                else if (paramExpressions[0].ValueType == methodSymbol.Parameters.Last().Type)
                {
                    SetDirectParam();
                }
                else
                {
                    Conversion conversion = Context.CompileContext.RoslynCompilation.ClassifyConversion(paramExpressions[0].ValueType.RoslynSymbol, methodSymbol.Parameters.Last().Type.RoslynSymbol);

                    if (conversion.IsImplicit) // Covariant array param conversion
                    {
                        SetDirectParam();
                    }
                    else
                    {
                        SetParamsArray();
                    }
                }
            }

            var invocation = BoundInvocationExpression.CreateBoundInvocation(Context, node, methodSymbol, instanceExpression, boundArguments);

            if ((instanceExpression == null || instanceExpression.IsThis) && node.Expression is MemberAccessExpressionSyntax accessExpressionSyntax2 &&
                accessExpressionSyntax2.Expression.Kind() == SyntaxKind.BaseExpression)
            {
                invocation.MarkForcedBaseCall();
            }

            return(invocation);
        }
Exemple #13
0
        public override void Emit(EmitContext context)
        {
            var blockScope = context.OpenBlockScope();

            TypeSymbol intType = context.GetTypeSymbol(SpecialType.System_Int32);

            MethodSymbol   toCharArrayMethod = context.GetTypeSymbol(SpecialType.System_String).GetMembers <MethodSymbol>("ToCharArray", context).First(e => e.Parameters.Length == 0);
            PropertySymbol lengthProperty    = context.GetTypeSymbol(SpecialType.System_Array).GetMember <PropertySymbol>("Length", context);

            Value iteratorValue = context.EmitValue(BoundInvocationExpression.CreateBoundInvocation(context, SyntaxNode, toCharArrayMethod, IteratorSource, new BoundExpression[] {}));

            iteratorValue.MarkUsedRecursively();
            var iteratorAccess = BoundAccessExpression.BindAccess(iteratorValue);

            Value arraySize = context.CreateInternalValue(intType);

            arraySize.MarkUsedRecursively();

            BoundAccessExpression getLength = BoundAccessExpression.BindAccess(context, SyntaxNode, lengthProperty, iteratorAccess);

            context.EmitValueAssignment(arraySize, getLength);

            // Declare and reset incrementor value
            Value incrementorValue = context.CreateInternalValue(intType);

            incrementorValue.MarkUsedRecursively();
            context.EmitValueAssignment(incrementorValue, BoundAccessExpression.BindAccess(context.GetConstantValue(intType, 0)));

            JumpLabel loopLabel = context.Module.CreateLabel();

            context.Module.LabelJump(loopLabel);

            var incrementorAccess = BoundAccessExpression.BindAccess(incrementorValue);

            BoundExpression increment = new BoundInvocationExpression.BoundPrefixOperatorExpression(context, SyntaxNode,
                                                                                                    incrementorAccess, new ExternSynthesizedOperatorSymbol(BuiltinOperatorType.Addition, intType, context));

            var lengthCheck = BoundInvocationExpression.CreateBoundInvocation(context, SyntaxNode,
                                                                              new ExternSynthesizedOperatorSymbol(BuiltinOperatorType.LessThan, intType, context), null,
                                                                              new BoundExpression[]
            {
                incrementorAccess,
                BoundAccessExpression.BindAccess(arraySize)
            });

            JumpLabel exitLoopLabel = context.PushBreakLabel();
            JumpLabel continueLabel = context.PushContinueLabel();

            Value lengthCheckResult = context.EmitValue(lengthCheck);

            context.Module.AddJumpIfFalse(exitLoopLabel, lengthCheckResult);

            context.EmitValueAssignment(context.GetUserValue(ValueSymbol),
                                        BoundAccessExpression.BindElementAccess(context, SyntaxNode, iteratorAccess,
                                                                                new BoundExpression[] { incrementorAccess }));

            context.Emit(BodyStatement);

            context.Module.LabelJump(continueLabel);

            context.Emit(increment);

            context.Module.AddJump(loopLabel);

            context.Module.LabelJump(exitLoopLabel);

            context.PopBreakLabel();
            context.PopContinueLabel();

            blockScope.Dispose();
        }