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); }
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); }
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 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(); }