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 #2
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 static BoundInvocationExpression CreateBoundInvocation(AbstractPhaseContext context, SyntaxNode node,
                                                                      MethodSymbol symbol, BoundExpression instanceExpression, BoundExpression[] parameterExpressions)
        {
            if (TryCreateShimInvocation(context, node, symbol, instanceExpression, parameterExpressions, out var boundShimInvocation))
            {
                return(boundShimInvocation);
            }

            if (symbol.IsExtern)
            {
                if (CompilerUdonInterface.IsUdonEvent(symbol.Name) &&
                    symbol.ContainingType == context.GetTypeSymbol(typeof(UdonSharpBehaviour))) // Pass through for making base calls on the U# behaviour type return noop
                {
                    return(new BoundUdonSharpBehaviourInvocationExpression(node, symbol, instanceExpression, parameterExpressions));
                }

                if (symbol.IsOperator)
                {
                    // Enum equality/inequality
                    if (symbol.ContainingType?.IsEnum ?? false)
                    {
                        MethodSymbol objectEqualsMethod = context.GetTypeSymbol(SpecialType.System_Object)
                                                          .GetMember <MethodSymbol>("Equals", context);

                        var boundEqualsInvocation = CreateBoundInvocation(context, node, objectEqualsMethod, parameterExpressions[0],
                                                                          new[] { parameterExpressions[1] });
                        if (symbol.Name == "op_Equality")
                        {
                            return(boundEqualsInvocation);
                        }

                        MethodSymbol boolNotOperator = new ExternSynthesizedOperatorSymbol(
                            BuiltinOperatorType.UnaryNegation, context.GetTypeSymbol(SpecialType.System_Boolean),
                            context);

                        return(new BoundExternInvocation(node, context, boolNotOperator, null, new BoundExpression[] { boundEqualsInvocation }));
                    }

                    if (node is AssignmentExpressionSyntax)
                    {
                        return(new BoundCompoundAssignmentExpression(context, node, (BoundAccessExpression)parameterExpressions[0], symbol, parameterExpressions[1]));
                    }

                    if (symbol is ExternBuiltinOperatorSymbol externBuiltinOperatorSymbol &&
                        externBuiltinOperatorSymbol.OperatorType == BuiltinOperatorType.BitwiseNot)
                    {
                        return(new BoundBitwiseNotExpression(node, parameterExpressions[0]));
                    }

                    if (parameterExpressions.Length == 2 || symbol.Name == "op_UnaryNegation" || symbol.Name == "op_LogicalNot")
                    {
                        return(new BoundBuiltinOperatorInvocationExpression(node, context, symbol, parameterExpressions));
                    }

                    throw new NotSupportedException("Operator expressions must have either 1 or 2 parameters", node.GetLocation());
                }

                return(new BoundExternInvocation(node, context, symbol, instanceExpression, parameterExpressions));
            }

            if (symbol.IsStatic)
            {
                return(new BoundStaticUserMethodInvocation(node, symbol, parameterExpressions));
            }

            if (symbol is UdonSharpBehaviourMethodSymbol udonSharpBehaviourMethodSymbol)
            {
                if (instanceExpression != null && !instanceExpression.IsThis)
                {
                    udonSharpBehaviourMethodSymbol.MarkNeedsReferenceExport();
                }

                return(new BoundUdonSharpBehaviourInvocationExpression(node, symbol, instanceExpression,
                                                                       parameterExpressions));
            }

            throw new System.NotImplementedException();
        }