예제 #1
0
        public override Value EmitValue(EmitContext context)
        {
            // We don't want any references outside the flow control to be dirtied conditionally
            context.TopTable.DirtyAllValues();

            Value resultValue = context.CreateInternalValue(ValueType);

            if (OperatorType == BuiltinOperatorType.LogicalAnd)
            {
                JumpLabel failLabel = context.Module.CreateLabel();

                context.EmitValueAssignment(resultValue, Lhs);

                context.Module.AddJumpIfFalse(failLabel, resultValue);

                context.EmitValueAssignment(resultValue, Rhs);

                context.Module.LabelJump(failLabel);
            }
            else if (OperatorType == BuiltinOperatorType.LogicalOr)
            {
                JumpLabel failLabel = context.Module.CreateLabel();
                JumpLabel exitLabel = context.Module.CreateLabel();

                context.EmitValueAssignment(resultValue, Lhs);

                context.Module.AddJumpIfFalse(failLabel, resultValue);
                context.Module.AddJump(exitLabel);

                context.Module.LabelJump(failLabel);

                context.EmitValueAssignment(resultValue, Rhs);

                context.Module.LabelJump(exitLabel);
            }
            else
            {
                throw new InvalidOperationException("Invalid operator type");
            }

            return(resultValue);
        }
예제 #2
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);
        }
예제 #3
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);
        }
예제 #4
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();
        }