public override BoundNode VisitObjectCreationExpression(ObjectCreationExpressionSyntax node) { if (node.Initializer != null) { throw new NotSupportedException(LocStr.CE_InitializerListsNotSupported, node); } MethodSymbol constructorSymbol = (MethodSymbol)GetSymbol(node); BoundExpression[] boundArguments = new BoundExpression[node.ArgumentList.Arguments.Count]; bool isConstant = true; for (int i = 0; i < boundArguments.Length; ++i) { boundArguments[i] = VisitExpression(node.ArgumentList.Arguments[i].Expression, constructorSymbol.Parameters[i].Type); isConstant &= boundArguments[i].IsConstant; } // Constant folding on struct creation when possible // Also implicitly handles parameterless constructors on value types, which Udon does not expose constructors for if (isConstant && constructorSymbol.IsExtern && constructorSymbol.ContainingType.IsValueType) { var constArgs = boundArguments.Select(e => e.ConstantValue.Value).ToArray(); object constantValue = Activator.CreateInstance(constructorSymbol.ContainingType.UdonType.SystemType, constArgs); IConstantValue constantStore = (IConstantValue)Activator.CreateInstance(typeof(ConstantValue <>).MakeGenericType(constantValue.GetType()), constantValue); return(new BoundConstantExpression(constantStore, constructorSymbol.ContainingType, node)); } return(BoundInvocationExpression.CreateBoundInvocation(Context, node, constructorSymbol, null, boundArguments)); }
public override Value EmitSet(EmitContext context, BoundExpression valueExpression) { BoundExpression instanceValue = GetInstanceExpression(context); BoundInvocationExpression invocationExpression = BoundInvocationExpression.CreateBoundInvocation(context, SyntaxNode, Property.SetMethod, instanceValue, GetParameters(context, valueExpression)); if (_isBaseCall) { invocationExpression.MarkForcedBaseCall(); } invocationExpression.MarkPropertySetter(); Value resultVal = context.EmitValue(invocationExpression); if (resultVal == null) { throw new NullReferenceException(); } if (instanceValue != null && SourceExpression.ValueType.IsValueType && SourceExpression is BoundArrayAccessExpression sourceAccessExpression) { context.EmitSet(sourceAccessExpression, instanceValue); } return(resultVal); }
public override BoundNode VisitPrefixUnaryExpression(PrefixUnaryExpressionSyntax node) { MethodSymbol unaryMethodSymbol = (MethodSymbol)GetSymbol(node); BoundExpression expression = VisitExpression(node.Operand, unaryMethodSymbol.Parameters[0].Type); // + operator is a no-op on builtins so ignore it until we allow user operator overloads if (node.OperatorToken.Kind() == SyntaxKind.PlusToken) { return(expression); } BoundExpression constantResult = ConstantExpressionOptimizer.FoldConstantUnaryPrefixExpression(Context, node, unaryMethodSymbol, expression); if (constantResult != null) { return(constantResult); } if (node.Kind() == SyntaxKind.PreIncrementExpression || node.Kind() == SyntaxKind.PreDecrementExpression) { return(new BoundInvocationExpression.BoundPrefixOperatorExpression(Context, node, (BoundAccessExpression)expression, unaryMethodSymbol)); } return(BoundInvocationExpression.CreateBoundInvocation(Context, node, unaryMethodSymbol, null, new[] { expression })); }
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 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 BoundNode VisitBinaryExpression(BinaryExpressionSyntax node) { if (node.Kind() == SyntaxKind.LogicalOrExpression || node.Kind() == SyntaxKind.LogicalAndExpression) { return(HandleShortCircuitOperator(node)); } if (node.Kind() == SyntaxKind.CoalesceExpression) { return(HandleNullCoalescingExpression(node)); } MethodSymbol binaryMethodSymbol = (MethodSymbol)GetSymbol(node); BoundExpression lhs = VisitExpression(node.Left, binaryMethodSymbol.Parameters[0].Type); BoundExpression rhs = VisitExpression(node.Right, binaryMethodSymbol.Parameters[1].Type); BoundExpression constantResult = ConstantExpressionOptimizer.FoldConstantBinaryExpression(Context, node, binaryMethodSymbol, lhs, rhs); if (constantResult != null) { return(constantResult); } return(BoundInvocationExpression.CreateBoundInvocation(Context, node, binaryMethodSymbol, null, new[] { lhs, rhs })); }
public override Value EmitSet(EmitContext context, BoundExpression valueExpression) { if (SourceExpression == null || SourceExpression.IsThis) { return(context.EmitValueAssignment(context.GetUserValue(Field), valueExpression)); } if (Field.HasAttribute <FieldChangeCallbackAttribute>()) { throw new CompilerException("Cannot set field on U# behaviour by reference when that field has a FieldChangeCallback attribute."); } TypeSymbol stringType = context.GetTypeSymbol(SpecialType.System_String); MethodSymbol setProgramVariableMethod = context.GetTypeSymbol(typeof(UdonSharpBehaviour)) .GetMembers <MethodSymbol>("SetProgramVariable", context) .First(e => e.Parameters.Length == 2 && e.Parameters[0].Type == stringType); Value value = context.EmitValue(valueExpression); context.Emit(BoundInvocationExpression.CreateBoundInvocation(context, SyntaxNode, setProgramVariableMethod, SourceExpression, new BoundExpression[] { BindAccess(context.GetConstantValue(stringType, Field.Name)), BindAccess(value) })); return(value); }
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) }); }
public override Value EmitValue(EmitContext context) { BoundInvocationExpression invocationExpression = BoundInvocationExpression.CreateBoundInvocation(context, SyntaxNode, Property.GetMethod, GetInstanceExpression(context), GetParameters(context)); if (_isBaseCall) { invocationExpression.MarkForcedBaseCall(); } return(context.EmitValue(invocationExpression)); }
private static bool TryCreateUdonSharpMetadataInvocation(AbstractPhaseContext context, SyntaxNode node, MethodSymbol symbol, BoundExpression instanceExpression, out BoundInvocationExpression createdInvocation) { if (symbol.Name == "GetUdonTypeID" || symbol.Name == "GetUdonTypeName") { if (symbol.IsStatic && symbol.TypeArguments.Length == 1 && symbol.ContainingType == context.GetTypeSymbol(typeof(UdonSharpBehaviour))) { IConstantValue constantValue; TypeSymbol constantType; var typeArgs = symbol.TypeArguments.Select(e => context.GetTypeSymbol(e.RoslynSymbol)).ToArray(); if (symbol.Name == "GetUdonTypeID") { constantValue = new ConstantValue <long>(UdonSharpInternalUtility.GetTypeID(TypeSymbol.GetFullTypeName(typeArgs[0].RoslynSymbol))); constantType = context.GetTypeSymbol(SpecialType.System_Int64); } else { constantValue = new ConstantValue <string>(TypeSymbol.GetFullTypeName(typeArgs[0].RoslynSymbol)); constantType = context.GetTypeSymbol(SpecialType.System_String); } createdInvocation = new BoundConstantInvocationExpression(node, constantValue, constantType); return(true); } if (!symbol.IsStatic && instanceExpression != null && symbol.ContainingType == context.GetTypeSymbol(typeof(UdonSharpBehaviour))) { TypeSymbol methodContainer = context.GetTypeSymbol(typeof(UdonSharpBehaviourMethods)); var shimMethod = methodContainer.GetMember <MethodSymbol>(symbol.Name, context); context.MarkSymbolReferenced(shimMethod); createdInvocation = CreateBoundInvocation(context, node, shimMethod, null, new [] { instanceExpression }); return(true); } } createdInvocation = null; return(false); }
private static bool TryCreateShimInvocation(AbstractPhaseContext context, SyntaxNode node, MethodSymbol symbol, BoundExpression instanceExpression, BoundExpression[] parameterExpressions, out BoundInvocationExpression createdInvocation) { if (TryCreateUdonSharpMetadataInvocation(context, node, symbol, instanceExpression, out createdInvocation)) { return(true); } if (TryCreateGetComponentInvocation(context, node, symbol, instanceExpression, parameterExpressions, out createdInvocation)) { return(true); } if (TryCreateInstantiationInvocation(context, node, symbol, instanceExpression, parameterExpressions, out createdInvocation)) { return(true); } if (TryCreateSetProgramVariableInvocation(context, node, symbol, instanceExpression, parameterExpressions, out createdInvocation)) { return(true); } if (TryCreateArrayMethodInvocation(context, node, symbol, instanceExpression, parameterExpressions, out createdInvocation)) { return(true); } if (TryCreateTMPMethodInvocation(context, node, symbol, instanceExpression, parameterExpressions, out createdInvocation)) { return(true); } if (TryCreateBaseEnumMethodInvocation(context, node, symbol, instanceExpression, parameterExpressions, out createdInvocation)) { return(true); } if (TryCreateCompareToInvocation(context, node, symbol, instanceExpression, parameterExpressions, out createdInvocation)) { return(true); } return(false); }
private static bool TryCreateTMPMethodInvocation(AbstractPhaseContext context, SyntaxNode node, MethodSymbol symbol, BoundExpression instanceExpression, BoundExpression[] parameterExpressions, out BoundInvocationExpression createdInvocation) { if (symbol.ContainingType != null && symbol.ContainingType.ToString() == "TMPro.TMP_Text") { createdInvocation = new BoundExternInvocation(node, context, new ExternSynthesizedMethodSymbol(context, symbol.Name, instanceExpression.ValueType, symbol.Parameters.Select(e => e.Type).ToArray(), symbol.ReturnType, symbol.IsStatic), instanceExpression, parameterExpressions); return(true); } createdInvocation = null; return(false); }
private static bool TryCreateInstantiationInvocation(AbstractPhaseContext context, SyntaxNode node, MethodSymbol symbol, BoundExpression instanceExpression, BoundExpression[] parameterExpressions, out BoundInvocationExpression createdInvocation) { switch (symbol.Name) { case "Instantiate_Extern" when symbol.ContainingType == context.GetTypeSymbol(typeof(InstantiationShim)): createdInvocation = new BoundExternInvocation(node, context, new ExternSynthesizedMethodSymbol(context, "VRCInstantiate.__Instantiate__UnityEngineGameObject__UnityEngineGameObject", parameterExpressions.Select(e => e.ValueType).ToArray(), context.GetTypeSymbol(typeof(GameObject)), true), instanceExpression, parameterExpressions); return(true); case "VRCInstantiate" when symbol.ContainingType == context.GetTypeSymbol(typeof(UdonSharpBehaviour)): // Backwards compatibility for UdonSharpBehaviour.VRCInstantiate case "Instantiate" when symbol.ContainingType == context.GetTypeSymbol(typeof(UnityEngine.Object)): { if (symbol.Name != "VRCInstantiate" && (symbol.TypeArguments.Length != 1 || symbol.TypeArguments[0] != context.GetTypeSymbol(typeof(GameObject)))) { throw new NotSupportedException("Udon does not support instantiating non-GameObject types"); } TypeSymbol instantiateShim = context.GetTypeSymbol(typeof(InstantiationShim)); MethodSymbol instantiateMethod = instantiateShim.GetMembers <MethodSymbol>("Instantiate", context) .First(e => e.Parameters .Select(p => p.Type) .SequenceEqual(parameterExpressions .Select(p => p.ValueType))); context.MarkSymbolReferenced(instantiateMethod); createdInvocation = new BoundStaticUserMethodInvocation(node, instantiateMethod, parameterExpressions); return(true); } } createdInvocation = null; return(false); }
/// <summary> /// Udon exposes a generic SetProgramVariable which the overload finding will attempt to use and fail to find, /// so just use the non-generic version in this case /// </summary> private static bool TryCreateSetProgramVariableInvocation(AbstractPhaseContext context, SyntaxNode node, MethodSymbol symbol, BoundExpression instanceExpression, BoundExpression[] parameterExpressions, out BoundInvocationExpression createdInvocation) { if (symbol.Name == "SetProgramVariable" && symbol.ContainingType == context.GetTypeSymbol(typeof(UdonBehaviour))) { MethodSymbol setProgramVarObjMethod = context.GetTypeSymbol(typeof(UdonBehaviour)) .GetMembers <MethodSymbol>("SetProgramVariable", context) .First(e => !e.RoslynSymbol.IsGenericMethod); createdInvocation = new BoundExternInvocation(node, context, setProgramVarObjMethod, instanceExpression, parameterExpressions); return(true); } createdInvocation = null; return(false); }
private static bool TryCreateArrayMethodInvocation(AbstractPhaseContext context, SyntaxNode node, MethodSymbol symbol, BoundExpression instanceExpression, BoundExpression[] parameterExpressions, out BoundInvocationExpression createdInvocation) { if ((symbol.Name == "IndexOf" || symbol.Name == "BinarySearch" || symbol.Name == "LastIndexOf" || symbol.Name == "Reverse") && symbol.ContainingType == context.GetTypeSymbol(typeof(Array))) { MethodSymbol arrayMethod = context.GetTypeSymbol(typeof(Array)) .GetMembers <MethodSymbol>(symbol.Name, context) .First(e => !e.RoslynSymbol.IsGenericMethod && e.Parameters.Length == symbol.Parameters.Length); createdInvocation = new BoundExternInvocation(node, context, arrayMethod, instanceExpression, parameterExpressions); return(true); } createdInvocation = null; return(false); }
private static bool TryCreateBaseEnumMethodInvocation(AbstractPhaseContext context, SyntaxNode node, MethodSymbol symbol, BoundExpression instanceExpression, BoundExpression[] parameterExpressions, out BoundInvocationExpression createdInvocation) { if ((symbol.Name == "ToString" || symbol.Name == "GetHashCode" || symbol.Name == "Equals") && symbol.ContainingType != null && symbol.ContainingType == context.GetTypeSymbol(SpecialType.System_Enum)) { createdInvocation = new BoundExternInvocation(node, context, context.GetTypeSymbol(SpecialType.System_Object).GetMember <MethodSymbol>(symbol.Name, context), instanceExpression, parameterExpressions); return(true); } createdInvocation = null; return(false); }
public override Value EmitValue(EmitContext context) { if (SourceExpression == null || SourceExpression.IsThis) { return(context.GetUserValue(Field)); } TypeSymbol stringType = context.GetTypeSymbol(SpecialType.System_String); MethodSymbol setProgramVariableMethod = context.GetTypeSymbol(typeof(UdonSharpBehaviour)) .GetMembers <MethodSymbol>("GetProgramVariable", context) .First(e => e.Parameters.Length == 1 && e.Parameters[0].Type == stringType); return(context.CastValue(context.EmitValue(BoundInvocationExpression.CreateBoundInvocation(context, SyntaxNode, setProgramVariableMethod, SourceExpression, new BoundExpression[] { BindAccess(context.GetConstantValue(stringType, Field.Name)) })), Field.Type, true)); }
public override Value EmitValue(EmitContext context) { Value returnValue = context.GetReturnValue(ValueType); var charArray = BoundInvocationExpression.CreateBoundInvocation(context, SyntaxNode, _toCharArraySymbol, BindAccess(context.EmitValue(SourceExpression)), new[] { IndexerExpression, BindAccess(context.GetConstantValue(context.GetTypeSymbol(SpecialType.System_Int32), 1)) }); context.EmitValueAssignment(returnValue, BindElementAccess(context, SyntaxNode, charArray, new BoundExpression[] { BindAccess(context.GetConstantValue(context.GetTypeSymbol(SpecialType.System_Int32), 0)) })); return(returnValue); }
private static bool TryCreateCompareToInvocation(AbstractPhaseContext context, SyntaxNode node, MethodSymbol symbol, BoundExpression instanceExpression, BoundExpression[] parameterExpressions, out BoundInvocationExpression createdInvocation) { if (symbol.Name == "CompareTo" && symbol.ContainingType != null && symbol.ContainingType == context.GetTypeSymbol(typeof(IComparable))) { createdInvocation = new BoundExternInvocation(node, context, new ExternSynthesizedMethodSymbol(context, "CompareTo", instanceExpression.ValueType, new [] { instanceExpression.ValueType }, context.GetTypeSymbol(SpecialType.System_Int32), false), instanceExpression, parameterExpressions); return(true); } createdInvocation = null; return(false); }
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 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 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); }
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); }
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); }