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); }
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); }
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) }); }
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)); }
public override BoundNode VisitDeclarationExpression(DeclarationExpressionSyntax node) { return(BoundAccessExpression.BindAccess(Context, node, GetDeclaredSymbol(node.Designation), 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(); }
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); }
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"); } }
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); }