public override Value EmitValue(EmitContext context)
        {
            Value returnValue;

            if (context.IsRecursiveMethodEmit)
            {
                using (context.InterruptAssignmentScope())
                {
                    returnValue = context.EmitValue(new BoundArrayCreationExpression(SyntaxNode, context, ArrayType,
                                                                                     new BoundExpression[]
                    {
                        BoundAccessExpression.BindAccess(
                            context.GetConstantValue(context.GetTypeSymbol(SpecialType.System_Int32),
                                                     Initializers.Length))
                    }, null));
                }
            }
            else
            {
                returnValue = context.CreateGlobalInternalValue(ArrayType);
                returnValue.DefaultValue = Activator.CreateInstance(ArrayType.UdonType.SystemType, Initializers.Length);
            }

            BoundAccessExpression arrayAccess = BoundAccessExpression.BindAccess(returnValue);
            TypeSymbol            intType     = context.GetTypeSymbol(SpecialType.System_Int32);

            // This is quite wasteful for allocations in the compile, todo: look at caching these safely
            for (int i = 0; i < Initializers.Length; ++i)
            {
                BoundAccessExpression elementAccess = BoundAccessExpression.BindElementAccess(context, SyntaxNode, arrayAccess, new BoundExpression[] { new BoundConstantExpression(new ConstantValue <int>(i), intType, SyntaxNode) });
                context.EmitSet(elementAccess, Initializers[i]);
            }

            return(returnValue);
        }
        public override Value EmitValue(EmitContext context)
        {
            Type operandType = ValueType.UdonType.SystemType;

            object allBits;

            if (UdonSharpUtils.IsSignedType(operandType))
            {
                allBits = Convert.ChangeType(-1, operandType);
            }
            else
            {
                allBits = operandType.GetField("MaxValue").GetValue(null);
            }

            BoundAccessExpression allBitsExpr = BoundAccessExpression.BindAccess(context.GetConstantValue(ValueType, allBits));

            Value returnValue = context.GetReturnValue(ValueType);

            using (context.InterruptAssignmentScope())
            {
                BoundAccessExpression operandVal = BoundAccessExpression.BindAccess(context.EmitValue(SourceExpression));

                context.EmitValueAssignment(returnValue,
                                            CreateBoundInvocation(context, null,
                                                                  new ExternSynthesizedOperatorSymbol(BuiltinOperatorType.LogicalXor, ValueType, context), null,
                                                                  new BoundExpression[] { operandVal, allBitsExpr }));
            }

            return(returnValue);
        }
 public BoundCompoundAssignmentExpression(AbstractPhaseContext context, SyntaxNode node, BoundAccessExpression assignmentTarget, MethodSymbol operatorMethod, BoundExpression assignmentSource)
     : base(node, null, null, null)
 {
     TargetExpression = assignmentTarget;
     AssignmentSource = assignmentSource;
     OperatorMethod   = operatorMethod;
 }
        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);
        }
Example #5
0
        public override BoundNode VisitElementAccessExpression(ElementAccessExpressionSyntax node)
        {
            BoundExpression accessExpression = VisitExpression(node.Expression);

            // if (node.ArgumentList.Arguments.Count != 1)
            //     throw new NotSupportedException("UdonSharp does not currently support multidimensional arrays", node.GetLocation());

            if (accessExpression.ValueType == Context.GetTypeSymbol(SpecialType.System_String))
            {
                return(new BoundStringAccessExpression(Context, node, accessExpression, VisitExpression(node.ArgumentList.Arguments[0].Expression, Context.GetTypeSymbol(SpecialType.System_Int32))));
            }

            PropertySymbol accessorSymbol = GetSymbol(node) as PropertySymbol;

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

            // There's some extern/user defined indexer, so use that
            if (accessorSymbol != null)
            {
                for (int i = 0; i < indexers.Length; ++i)
                {
                    indexers[i] = VisitExpression(node.ArgumentList.Arguments[i].Expression, accessorSymbol.Parameters[i].Type);
                }

                return(BoundAccessExpression.BindElementAccess(Context, node, accessorSymbol, accessExpression, indexers));
            }

            for (int i = 0; i < indexers.Length; ++i)
            {
                indexers[i] = VisitExpression(node.ArgumentList.Arguments[i].Expression, typeof(int));
            }

            return(BoundAccessExpression.BindElementAccess(Context, node, accessExpression, indexers));
        }
        protected void PopRecursiveValues(Value[] values, EmitContext context)
        {
            if (values.Length == 0)
            {
                return;
            }

            Value stack     = context.RecursiveStackValue;
            Value stackAddr = context.RecursiveStackAddressValue;
            BoundAccessExpression stackAddrAccess = BoundAccessExpression.BindAccess(stackAddr);
            TypeSymbol            intType         = context.GetTypeSymbol(SpecialType.System_Int32);
            TypeSymbol            objectType      = context.GetTypeSymbol(SpecialType.System_Object);
            TypeSymbol            objectArrayType = objectType.MakeArrayType(context);

            context.Module.AddCommentTag("Recursive stack pop");

            BoundInvocationExpression decrementExpression = new BoundPrefixOperatorExpression(context, SyntaxNode,
                                                                                              stackAddrAccess, new ExternSynthesizedOperatorSymbol(BuiltinOperatorType.Subtraction, intType, context));

            foreach (var valueToPop in values.Reverse())
            {
                context.Emit(decrementExpression);

                ExternSynthesizedMethodSymbol arrayGetMethod = new ExternSynthesizedMethodSymbol(context, "Get",
                                                                                                 objectArrayType, new [] { intType }, objectType, false);

                context.Module.AddPush(stack);
                context.Module.AddPush(stackAddr);
                context.Module.AddPush(valueToPop);
                context.Module.AddExtern(arrayGetMethod);
            }

            context.Module.AddCommentTag("Recursive stack pop end");
        }
        protected void PushRecursiveValues(Value[] values, EmitContext context)
        {
            if (values.Length == 0)
            {
                return;
            }

            Value stack = context.RecursiveStackValue;
            BoundAccessExpression stackAccess = BoundAccessExpression.BindAccess(stack);
            Value stackAddr = context.RecursiveStackAddressValue;
            BoundAccessExpression stackAddrAccess = BoundAccessExpression.BindAccess(stackAddr);

            context.Module.AddCommentTag("Recursive stack push");

            // Now we start copying values over to the stack
            BoundInvocationExpression incrementExpression = new BoundPrefixOperatorExpression(context, SyntaxNode,
                                                                                              stackAddrAccess, new ExternSynthesizedOperatorSymbol(BuiltinOperatorType.Addition, context.GetTypeSymbol(SpecialType.System_Int32), context));

            foreach (var valueToPush in values)
            {
                BoundArrayAccessExpression arraySet = new BoundArrayAccessExpression(null, context, stackAccess,
                                                                                     new BoundExpression[] { stackAddrAccess });

                context.EmitSet(arraySet, BoundAccessExpression.BindAccess(valueToPush));

                context.Emit(incrementExpression);
            }

            context.Module.AddCommentTag("Recursive stack push end");
        }
        public override Value EmitValue(EmitContext context)
        {
            Value returnValue = base.EmitValue(context);

            if (Initializers != null)
            {
                BoundAccessExpression arrayAccess = BoundAccessExpression.BindAccess(returnValue);
                TypeSymbol            intType     = context.GetTypeSymbol(SpecialType.System_Int32);

                using (context.InterruptAssignmentScope())
                {
                    // This is quite wasteful for allocations in the compile, todo: look at caching these safely
                    for (int i = 0; i < Initializers.Length; ++i)
                    {
                        BoundAccessExpression elementAccess = BoundAccessExpression.BindElementAccess(context,
                                                                                                      SyntaxNode, arrayAccess,
                                                                                                      new BoundExpression[]
                                                                                                      { new BoundConstantExpression(new ConstantValue <int>(i), intType, SyntaxNode) });
                        context.EmitSet(elementAccess, Initializers[i]);
                    }
                }
            }

            return(returnValue);
        }
Example #9
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)));
        }
            public override Value EmitValue(EmitContext context)
            {
                Value returnVal = context.GetReturnValue(ValueType);

                context.EmitValueAssignment(returnVal,
                                            BoundAccessExpression.BindAccess(context.GetConstantValue(ValueType, ConstantValue.Value)));

                return(returnVal);
            }
            public BoundPrefixOperatorExpression(AbstractPhaseContext context, SyntaxNode node, BoundAccessExpression assignmentTarget, MethodSymbol operatorMethod)
                : base(node, null, null, null)
            {
                TargetExpression = assignmentTarget;
                Type           targetType     = TargetExpression.ValueType.UdonType.SystemType;
                IConstantValue incrementValue = (IConstantValue)Activator.CreateInstance(
                    typeof(ConstantValue <>).MakeGenericType(targetType), Convert.ChangeType(1, targetType));

                InternalExpression = CreateBoundInvocation(context, null, operatorMethod, null,
                                                           new BoundExpression[] { assignmentTarget, new BoundConstantExpression(incrementValue, TargetExpression.ValueType, node) });
            }
Example #12
0
        private BoundAccessExpression VisitAccessExpression(SyntaxNode node)
        {
            if (node.Kind() == SyntaxKind.ElementAccessExpression)
            {
                return((BoundAccessExpression)Visit(node));
            }

            if (node.Kind() != SyntaxKind.IdentifierName &&
                node.Kind() != SyntaxKind.SimpleMemberAccessExpression &&
                node.Kind() != SyntaxKind.ThisExpression)
            {
                return(null);
            }

            Symbol nodeSymbol = GetSymbol(node);

            if (nodeSymbol.RoslynSymbol.Kind == SymbolKind.NamedType)
            {
                return(null);
            }
            BoundExpression lhsExpression = null;

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

                if (accessExpressionSyntax.Expression.Kind() != SyntaxKind.ThisExpression)
                {
                    if (lhsExpression == null && !nodeSymbol.IsStatic)
                    {
                        lhsExpression = BoundAccessExpression.BindThisAccess(OwningSymbol.ContainingType);
                    }

                    BoundAccessExpression access = BoundAccessExpression.BindAccess(Context, node, nodeSymbol, lhsExpression);
                    if (accessExpressionSyntax.Expression.Kind() == SyntaxKind.BaseExpression)
                    {
                        access.MarkForcedBaseCall();
                    }

                    return(access);
                }
            }

            if (!nodeSymbol.IsStatic)
            {
                lhsExpression = BoundAccessExpression.BindThisAccess(OwningSymbol.ContainingType);
            }

            return(BoundAccessExpression.BindAccess(Context, node, nodeSymbol, lhsExpression));
        }
            public override Value EmitValue(EmitContext context)
            {
                Value targetValue =
                    context.EmitValueWithDeferredRelease(TargetExpression);

                var invocation = CreateBoundInvocation(context, null, OperatorMethod, null,
                                                       new[] { BoundAccessExpression.BindAccess(targetValue), AssignmentSource });

                Value setResult;

                if (TargetExpression.ValueType != OperatorMethod.ReturnType)
                {
                    setResult = context.EmitSet(TargetExpression, new BoundCastExpression(null, invocation, ValueType, true));
                }
                else
                {
                    setResult = context.EmitSet(TargetExpression, invocation);
                }

                return(setResult);
            }
        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));
        }
Example #15
0
 public override BoundNode VisitDeclarationExpression(DeclarationExpressionSyntax node)
 {
     return(BoundAccessExpression.BindAccess(Context, node, GetDeclaredSymbol(node.Designation), null));
 }
Example #16
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();
        }
Example #17
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);
        }
            public override Value EmitValue(EmitContext context)
            {
                Value returnValue = context.GetReturnValue(TargetExpression.ValueType);

                context.EmitValueAssignment(returnValue, TargetExpression);

                Type           targetType     = TargetExpression.ValueType.UdonType.SystemType;
                IConstantValue incrementValue = (IConstantValue)Activator.CreateInstance(
                    typeof(ConstantValue <>).MakeGenericType(targetType), Convert.ChangeType(1, targetType));
                BoundExpression expression = CreateBoundInvocation(context, null, InternalExpression.Method, null,
                                                                   new BoundExpression[] { BoundAccessExpression.BindAccess(returnValue), new BoundConstantExpression(incrementValue, TargetExpression.ValueType, SyntaxNode) });

                if (InternalExpression.Method.ReturnType != TargetExpression.ValueType)
                {
                    expression = new BoundCastExpression(null, expression, ValueType, true);
                }

                context.EmitSet(TargetExpression, expression);

                return(returnValue);
            }
Example #19
0
        public override Value EmitValue(EmitContext context)
        {
            // Make base calls to UdonSharpBehaviour events a noop
            if (IsBaseCall)
            {
                if (Method.ContainingType == context.GetTypeSymbol(typeof(UdonSharpBehaviour)))
                {
                    if (Method.Name == "OnOwnershipRequest")
                    {
                        return(context.GetConstantValue(context.GetTypeSymbol(SpecialType.System_Boolean), true));
                    }

                    return(null);
                }
            }

            if (SourceExpression == null || SourceExpression.IsThis)
            {
                return(base.EmitValue(context));
            }

            // Calls across UdonBehaviours
            CompilationContext.MethodExportLayout layout =
                context.CompileContext.GetUsbMethodLayout(Method, context);

            Value.CowValue        instanceCowValue = GetInstanceValue(context);
            Value                 instanceValue    = instanceCowValue.Value;
            BoundAccessExpression instanceAccess   = BoundAccessExpression.BindAccess(instanceValue);

            TypeSymbol stringType = context.GetTypeSymbol(SpecialType.System_String);

            Value[] recursiveValues   = null;
            Value   stackSizeCheckVal = null;
            bool    isRecursiveCall   = context.IsRecursiveMethodEmit;

            if (isRecursiveCall)
            {
                stackSizeCheckVal = context.CreateGlobalInternalValue(context.GetTypeSymbol(SpecialType.System_Int32));
            }

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

                Value[] parameterValues = GetParameterValues(context);
                instanceValue  = instanceCowValue.Value;
                instanceAccess = BoundAccessExpression.BindAccess(instanceValue); // Re-bind here since the parameters may have changed the cowvalue

                if (isRecursiveCall)
                {
                    EmitContext.MethodLinkage selfLinkage = context.GetMethodLinkage(context.CurrentEmitMethod, false);
                    recursiveValues = selfLinkage.ParameterValues;

                    CheckStackSize(stackSizeCheckVal, context);
                    PushRecursiveValues(recursiveValues, context);

                    for (int i = 0; i < parameterValues.Length; ++i)
                    {
                        Value paramIntermediate = context.CreateInternalValue(parameterValues[i].UserType);
                        context.Module.AddCopy(parameterValues[i], paramIntermediate);
                        parameterValues[i] = paramIntermediate;
                    }
                }
                else
                {
                    instanceCowValue.Dispose();
                }

                context.TopTable.DirtyAllValues();

                for (int i = 0; i < Method.Parameters.Length; ++i)
                {
                    context.Emit(CreateBoundInvocation(context, SyntaxNode, setProgramVariableMethod, instanceAccess,
                                                       new BoundExpression[]
                    {
                        BoundAccessExpression.BindAccess(context.GetConstantValue(stringType, layout.ParameterExportNames[i])),
                        BoundAccessExpression.BindAccess(parameterValues[i])
                    }));
                }
            }

            if (isRecursiveCall)
            {
                if (recursiveValues == null)
                {
                    recursiveValues = Array.Empty <Value>();
                }

                Value[] scopeValues = context.CollectRecursiveValues();

                PushRecursiveValues(scopeValues, context);

                recursiveValues = recursiveValues.Concat(scopeValues).ToArray();

                stackSizeCheckVal.DefaultValue = recursiveValues.Length;
                context.UpdateRecursiveStackMaxSize(recursiveValues.Length);
            }

            MethodSymbol sendCustomEventMethod = context.GetTypeSymbol(typeof(UdonSharpBehaviour)).GetMember <MethodSymbol>("SendCustomEvent", context);

            context.Emit(CreateBoundInvocation(context, SyntaxNode, sendCustomEventMethod, BoundAccessExpression.BindAccess(instanceValue),
                                               new BoundExpression[]
            {
                BoundAccessExpression.BindAccess(context.GetConstantValue(stringType, layout.ExportMethodName))
            }));

            if (isRecursiveCall)
            {
                PopRecursiveValues(recursiveValues, context);
            }

            if (Method.Parameters.Length > 0 &&
                Method.Parameters.Any(e => e.IsOut))
            {
                if (isRecursiveCall)
                {
                    throw new CompilerException("U# does not yet support calling user methods with ref/out parameters from methods marked with RecursiveMethod");
                }

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

                // Copy out/ref parameters back
                for (int i = 0; i < Method.Parameters.Length; ++i)
                {
                    ParameterSymbol parameterSymbol = Method.Parameters[i];

                    if (parameterSymbol.IsOut)
                    {
                        BoundAccessExpression currentAccessExpression = (BoundAccessExpression)ParameterExpressions[i];

                        currentAccessExpression.EmitSet(context, CreateBoundInvocation(context, SyntaxNode,
                                                                                       getProgramVariableMethod, instanceAccess, new[]
                        {
                            BoundAccessExpression.BindAccess(context.GetConstantValue(stringType,
                                                                                      layout.ParameterExportNames[i]))
                        }));
                    }
                }
            }

            if (IsPropertySetter)
            {
                return(GetParameterValues(context).Last());
            }

            if (Method.ReturnType != null)
            {
                MethodSymbol getProgramVariableMethod = context.GetTypeSymbol(typeof(UdonSharpBehaviour))
                                                        .GetMembers <MethodSymbol>("GetProgramVariable", context)
                                                        .First(e => e.Parameters.Length == 1 &&
                                                               e.Parameters[0].Type == stringType);

                Value returnVal = context.CreateInternalValue(Method.ReturnType);

                BoundInvocationExpression boundGetReturn = CreateBoundInvocation(context, SyntaxNode,
                                                                                 getProgramVariableMethod, instanceAccess,
                                                                                 new BoundExpression[]
                {
                    BoundAccessExpression.BindAccess(context.GetConstantValue(stringType,
                                                                              layout.ReturnExportName))
                });

                context.EmitValueAssignment(returnVal, boundGetReturn);

                return(returnVal);
            }

            return(null);
        }
        protected void CheckStackSize(Value valueCount, EmitContext context)
        {
            using (context.InterruptAssignmentScope())
            {
                Value stack = context.RecursiveStackValue;
                BoundAccessExpression stackAccess = BoundAccessExpression.BindAccess(stack);
                Value stackAddr = context.RecursiveStackAddressValue;
                BoundAccessExpression stackAddrAccess = BoundAccessExpression.BindAccess(stackAddr);

                TypeSymbol arrayType = context.GetTypeSymbol(SpecialType.System_Array);

                context.Module.AddCommentTag("Stack size check");

                // Check stack size and double it if it's not enough
                // We know that doubling once will always be enough since the default size of the stack is the max number of stack values pushed in any method
                PropertySymbol arraySizeProperty = arrayType.GetMember <PropertySymbol>("Length", context);

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

                Value arraySize =
                    context.EmitValue(BoundAccessExpression.BindAccess(context, SyntaxNode, arraySizeProperty,
                                                                       stackAccess));
                BoundAccessExpression arraySizeAccess = BoundAccessExpression.BindAccess(arraySize);

                Value targetSize = context.EmitValue(CreateBoundInvocation(context, SyntaxNode,
                                                                           new ExternSynthesizedOperatorSymbol(BuiltinOperatorType.Addition, intType, context), null,
                                                                           new BoundExpression[] { stackAddrAccess, BoundAccessExpression.BindAccess(valueCount) }));

                Value isSizeGreaterThan = context.EmitValue(CreateBoundInvocation(context, SyntaxNode,
                                                                                  new ExternSynthesizedOperatorSymbol(BuiltinOperatorType.GreaterThanOrEqual, intType, context), null,
                                                                                  new BoundExpression[]
                {
                    BoundAccessExpression.BindAccess(targetSize),
                    arraySizeAccess,
                }));

                JumpLabel skipResizeLabel = context.Module.CreateLabel();

                context.Module.AddJumpIfFalse(skipResizeLabel, isSizeGreaterThan);

                // Resize logic
                Value constantTwo = context.GetConstantValue(intType, 2);
                Value newSize     = context.EmitValue(CreateBoundInvocation(context, SyntaxNode,
                                                                            new ExternSynthesizedOperatorSymbol(BuiltinOperatorType.Multiplication, intType, context), null,
                                                                            new BoundExpression[]
                {
                    arraySizeAccess,
                    BoundAccessExpression.BindAccess(constantTwo),
                }));

                Value newArray = context.EmitValue(new BoundArrayCreationExpression(SyntaxNode, context,
                                                                                    context.GetTypeSymbol(SpecialType.System_Object).MakeArrayType(context),
                                                                                    new BoundExpression[] { BoundAccessExpression.BindAccess(newSize) }, null));

                MethodSymbol arrayCopyMethod = arrayType.GetMembers <MethodSymbol>("Copy", context)
                                               .First(e => e.Parameters.Length == 3 && e.Parameters[2].Type == intType);

                context.Emit(CreateBoundInvocation(context, null, arrayCopyMethod, null,
                                                   new BoundExpression[]
                {
                    stackAccess,
                    BoundAccessExpression.BindAccess(newArray),
                    BoundAccessExpression.BindAccess(arraySize)
                }));

                context.Module.AddCopy(newArray, stack);

                context.Module.LabelJump(skipResizeLabel);

                context.Module.AddCommentTag("Stack size check end");
            }
        }
Example #21
0
        public override Value EmitValue(EmitContext context)
        {
            JumpLabel returnPoint    = context.Module.CreateLabel();
            Value     returnPointVal =
                context.CreateGlobalInternalValue(context.GetTypeSymbol(SpecialType.System_UInt32));

            context.Module.AddPush(returnPointVal);
            var linkage = context.GetMethodLinkage(Method, !IsBaseCall);

            Value[] parameterValues = GetParameterValues(context);

            Value[] recursiveValues = null;
            bool    isRecursiveCall = context.IsRecursiveMethodEmit;

            Value stackSizeCheckVal = null;

            if (isRecursiveCall)
            {
                EmitContext.MethodLinkage selfLinkage = context.GetMethodLinkage(context.CurrentEmitMethod, false);
                recursiveValues = selfLinkage.ParameterValues;

                stackSizeCheckVal = context.CreateGlobalInternalValue(context.GetTypeSymbol(SpecialType.System_Int32));

                CheckStackSize(stackSizeCheckVal, context);
                PushRecursiveValues(selfLinkage.ParameterValues, context);
            }

            ReleaseCowReferences(context);

            if (isRecursiveCall)
            {
                Value.CowValue[] paramCows = parameterValues.Select(e => e.GetCowValue(context)).ToArray();

                for (int i = 0; i < linkage.ParameterValues.Length; ++i)
                {
                    context.EmitValueAssignment(linkage.ParameterValues[i], BoundAccessExpression.BindAccess(paramCows[i]));
                }

                foreach (var paramCow in paramCows)
                {
                    paramCow.Dispose();
                }
            }
            else
            {
                for (int i = 0; i < linkage.ParameterValues.Length; ++i)
                {
                    context.Module.AddCopy(parameterValues[i], linkage.ParameterValues[i]);
                }
            }

            context.TopTable.DirtyAllValues();

            if (isRecursiveCall)
            {
                Value[] collectedValues = context.CollectRecursiveValues().Where(e => !recursiveValues.Contains(e)).ToArray();

                PushRecursiveValues(collectedValues, context);

                recursiveValues = recursiveValues.Concat(collectedValues).ToArray();

                stackSizeCheckVal.DefaultValue = recursiveValues.Length;
                context.UpdateRecursiveStackMaxSize(recursiveValues.Length);
            }

            context.Module.AddCommentTag($"Calling {Method}");
            context.Module.AddJump(linkage.MethodLabel);

            context.Module.LabelJump(returnPoint);
            returnPointVal.DefaultValue = returnPoint.Address;

            Value recursiveRet = null;

            if (isRecursiveCall)
            {
                if (linkage.ReturnValue != null)
                {
                    recursiveRet = context.CreateInternalValue(linkage.ReturnValue.UserType);
                    context.Module.AddCopy(linkage.ReturnValue, recursiveRet);
                }

                PopRecursiveValues(recursiveValues, context);
            }

            // Handle out/ref parameters
            for (int i = 0; i < Method.Parameters.Length; ++i)
            {
                if (!Method.Parameters[i].IsOut)
                {
                    continue;
                }

                if (isRecursiveCall)
                {
                    throw new CompilerException("U# does not yet support calling user methods with ref/out parameters from methods marked with RecursiveMethod");
                }

                BoundAccessExpression paramAccess = (BoundAccessExpression)ParameterExpressions[i];

                paramAccess.EmitSet(context, BoundAccessExpression.BindAccess(linkage.ParameterValues[i]));
            }

            // Properties need to return the value that they are set to for assignment expressions
            if (IsPropertySetter)
            {
                return(parameterValues.Last());
            }

            if (Method.ReturnType != null)
            {
                if (isRecursiveCall)
                {
                    return(recursiveRet);
                }

                return(linkage.ReturnValue);
            }

            return(null);
        }
 public BoundAssignmentExpression(SyntaxNode node, BoundAccessExpression assignmentTarget, BoundExpression assignmentSource)
     : base(node, assignmentSource)
 {
     TargetExpression = assignmentTarget;
 }
        private static bool TryCreateGetComponentInvocation(AbstractPhaseContext context, SyntaxNode node,
                                                            MethodSymbol symbol, BoundExpression instanceExpression, BoundExpression[] parameterExpressions,
                                                            out BoundInvocationExpression createdInvocation)
        {
            if (symbol.RoslynSymbol != null &&
                symbol.RoslynSymbol.IsGenericMethod &&
                symbol.TypeArguments.Length == 1 &&
                _getComponentNames.Contains(symbol.Name) &&
                (symbol.ContainingType.UdonType.SystemType == typeof(Component) || symbol.ContainingType.UdonType.SystemType == typeof(GameObject)))
            {
                TypeSymbol gameObjectType = context.GetTypeSymbol(typeof(GameObject));
                TypeSymbol typeArgument   = symbol.TypeArguments[0];

                // udon-workaround: Work around the udon bug where it checks the strongbox type instead of variable type and blows up when the strong box is `object`
                if (instanceExpression.ValueType == gameObjectType)
                {
                    PropertySymbol accessProperty = gameObjectType.GetMember <PropertySymbol>("transform", context);
                    instanceExpression = BoundAccessExpression.BindAccess(context, node, accessProperty, instanceExpression);
                }
                else
                {
                    PropertySymbol accessProperty = context.GetTypeSymbol(typeof(Component)).GetMember <PropertySymbol>("transform", context);
                    instanceExpression = BoundAccessExpression.BindAccess(context, node, accessProperty, instanceExpression);
                }

                TypeSymbol udonSharpBehaviourType = context.GetTypeSymbol(typeof(UdonSharpBehaviour));

                // Exact UdonSharpBehaviour type match
                if (typeArgument == udonSharpBehaviourType)
                {
                    MethodSymbol getComponentMethodShim = context.GetTypeSymbol(typeof(GetComponentShim))
                                                          .GetMembers <MethodSymbol>(symbol.Name + "USB", context)
                                                          .First(e => e.Parameters.Length == parameterExpressions.Length + 1);

                    createdInvocation = new BoundStaticUserMethodInvocation(node, getComponentMethodShim,
                                                                            new [] { instanceExpression }.Concat(parameterExpressions).ToArray());

                    context.MarkSymbolReferenced(getComponentMethodShim);

                    return(true);
                }

                // Subclass of UdonSharpBehaviour
                if (typeArgument.IsUdonSharpBehaviour)
                {
                    // Handle inherited types
                    if (context.CompileContext.HasInheritedUdonSharpBehaviours(typeArgument))
                    {
                        MethodSymbol getComponentInheritedMethodShim = context.GetTypeSymbol(typeof(GetComponentShim))
                                                                       .GetMembers <MethodSymbol>(symbol.Name + "I", context)
                                                                       .First(e => e.Parameters.Length == parameterExpressions.Length + 1);

                        getComponentInheritedMethodShim = getComponentInheritedMethodShim.ConstructGenericMethod(context, new [] { typeArgument });

                        createdInvocation = new BoundStaticUserMethodInvocation(node, getComponentInheritedMethodShim,
                                                                                new [] { instanceExpression }.Concat(parameterExpressions).ToArray());

                        context.MarkSymbolReferenced(getComponentInheritedMethodShim);

                        return(true);
                    }

                    MethodSymbol getComponentMethodShim = context.GetTypeSymbol(typeof(GetComponentShim))
                                                          .GetMembers <MethodSymbol>(symbol.Name, context)
                                                          .First(e => e.Parameters.Length == parameterExpressions.Length + 1);

                    getComponentMethodShim = getComponentMethodShim.ConstructGenericMethod(context, new [] { typeArgument });

                    createdInvocation = new BoundStaticUserMethodInvocation(node, getComponentMethodShim,
                                                                            new [] { instanceExpression }.Concat(parameterExpressions).ToArray());

                    context.MarkSymbolReferenced(getComponentMethodShim);

                    return(true);
                }

                if (_brokenGetComponentTypes.Contains(typeArgument.UdonType.SystemType))
                {
                    MethodSymbol getComponentInheritedMethodShim = context.GetTypeSymbol(typeof(GetComponentShim))
                                                                   .GetMembers <MethodSymbol>(symbol.Name + "VRC", context)
                                                                   .First(e => e.Parameters.Length == parameterExpressions.Length + 1);

                    getComponentInheritedMethodShim = getComponentInheritedMethodShim.ConstructGenericMethod(context, new [] { typeArgument });

                    createdInvocation = new BoundStaticUserMethodInvocation(node, getComponentInheritedMethodShim,
                                                                            new [] { instanceExpression }.Concat(parameterExpressions).ToArray());

                    context.MarkSymbolReferenced(getComponentInheritedMethodShim);

                    return(true);
                }

                createdInvocation = new BoundGetUnityEngineComponentInvocation(context, node, symbol,
                                                                               instanceExpression,
                                                                               parameterExpressions);

                return(true);
            }

            createdInvocation = null;
            return(false);
        }