예제 #1
0
        public override void VisitClassDeclaration(ClassDeclarationSyntax node)
        {
            if (++classCount > 1)
            {
                throw new System.NotSupportedException("Only one class declaration per file is currently supported by UdonSharp");
            }

            using (ExpressionCaptureScope classTypeCapture = new ExpressionCaptureScope(visitorContext, null))
            {
                foreach (string namespaceToken in namespaceStack.Reverse())
                {
                    classTypeCapture.ResolveAccessToken(namespaceToken);
                }

                visitorContext.resolverContext.AddNamespace(classTypeCapture.captureNamespace);

                classTypeCapture.ResolveAccessToken(node.Identifier.ValueText);

                if (!classTypeCapture.IsType())
                {
                    throw new System.Exception($"User type {node.Identifier.ValueText} could not be found");
                }

                classDefinition.userClassType = classTypeCapture.captureType;
            }

            base.VisitClassDeclaration(node);
        }
예제 #2
0
        public override void VisitClassDeclaration(ClassDeclarationSyntax node)
        {
            UpdateSyntaxNode(node);
            using (ExpressionCaptureScope classTypeCapture = new ExpressionCaptureScope(visitorContext, null))
            {
                foreach (string namespaceToken in namespaceStack.Reverse())
                {
                    classTypeCapture.ResolveAccessToken(namespaceToken);

                    if (classTypeCapture.IsNamespace())
                    {
                        visitorContext.resolverContext.AddNamespace(classTypeCapture.captureNamespace);
                    }
                }

                classTypeCapture.ResolveAccessToken(node.Identifier.ValueText);

                if (!classTypeCapture.IsType())
                {
                    throw new System.Exception($"User type {node.Identifier.ValueText} could not be found");
                }
            }

            if (syntaxWalkerDepth == UdonSharpSyntaxWalkerDepth.ClassDefinitions ||
                syntaxWalkerDepth == UdonSharpSyntaxWalkerDepth.ClassMemberBodies)
            {
                base.VisitClassDeclaration(node);
            }
        }
예제 #3
0
        // Boilerplate to have resolution work correctly
        public override void VisitUsingDirective(UsingDirectiveSyntax node)
        {
            UpdateSyntaxNode(node);
            using (ExpressionCaptureScope namespaceCapture = new ExpressionCaptureScope(visitorContext, null))
            {
                if (node.StaticKeyword.IsKind(SyntaxKind.StaticKeyword))
                {
                    throw new System.NotSupportedException("UdonSharp does not yet support static using directives");
                }

                if (node.Alias != null)
                {
                    throw new System.NotSupportedException("UdonSharp does not yet support namespace alias directives");
                }

                Visit(node.Name);

                if (!namespaceCapture.IsNamespace())
                {
                    throw new System.Exception("Did not capture a valid namespace");
                }

                visitorContext.resolverContext.AddNamespace(namespaceCapture.captureNamespace);
            }
        }
예제 #4
0
        public override void VisitClassDeclaration(ClassDeclarationSyntax node)
        {
            using (ExpressionCaptureScope classTypeCapture = new ExpressionCaptureScope(visitorContext, null))
            {
                foreach (string namespaceToken in namespaceStack.Reverse())
                {
                    classTypeCapture.ResolveAccessToken(namespaceToken);

                    if (classTypeCapture.IsNamespace())
                    {
                        visitorContext.resolverContext.AddNamespace(classTypeCapture.captureNamespace);
                    }
                }

                visitorContext.resolverContext.AddNamespace(classTypeCapture.captureNamespace);

                classTypeCapture.ResolveAccessToken(node.Identifier.ValueText);

                if (!classTypeCapture.IsType())
                {
                    throw new System.Exception($"User type {node.Identifier.ValueText} could not be found");
                }
            }

            base.VisitClassDeclaration(node);
        }
예제 #5
0
        public override void VisitFieldDeclaration(FieldDeclarationSyntax node)
        {
            UpdateSyntaxNode(node);

            bool isPublic = node.Modifiers.HasModifier("public");

            System.Type fieldType = null;

            using (ExpressionCaptureScope fieldTypeCapture = new ExpressionCaptureScope(visitorContext, null))
            {
                UpdateSyntaxNode(node.Declaration.Type);
                Visit(node.Declaration.Type);

                fieldType = fieldTypeCapture.captureType;
            }

            if (fieldType == null)
            {
                throw new System.Exception($"The type or namespace name '{node.Declaration.Type}' could not be found (are you missing a using directive?)");
            }

            foreach (VariableDeclaratorSyntax variableDeclarator in node.Declaration.Variables)
            {
                SymbolDefinition newSymbol = visitorContext.topTable.CreateNamedSymbol(variableDeclarator.Identifier.ValueText, fieldType, isPublic ? SymbolDeclTypeFlags.Public : SymbolDeclTypeFlags.Private);

                classDefinition.fieldDefinitions.Add(new FieldDefinition(newSymbol));
            }
        }
예제 #6
0
        public override void VisitArrayType(ArrayTypeSyntax node)
        {
            using (ExpressionCaptureScope arrayTypeCaptureScope = new ExpressionCaptureScope(visitorContext, visitorContext.topCaptureScope))
            {
                Visit(node.ElementType);

                arrayTypeCaptureScope.MakeArrayType();
            }
        }
예제 #7
0
        private UdonSyncMode GetSyncAttributeValue(FieldDeclarationSyntax node)
        {
            UdonSyncMode syncMode = UdonSyncMode.NotSynced;

            if (node.AttributeLists != null)
            {
                foreach (AttributeListSyntax attributeList in node.AttributeLists)
                {
                    foreach (AttributeSyntax attribute in attributeList.Attributes)
                    {
                        using (ExpressionCaptureScope attributeTypeCapture = new ExpressionCaptureScope(visitorContext, null))
                        {
                            attributeTypeCapture.isAttributeCaptureScope = true;
                            Visit(attribute.Name);

                            if (attributeTypeCapture.captureType != typeof(UdonSyncedAttribute))
                            {
                                continue;
                            }

                            if (attribute.ArgumentList == null ||
                                attribute.ArgumentList.Arguments == null ||
                                attribute.ArgumentList.Arguments.Count == 0)
                            {
                                syncMode = UdonSyncMode.None;
                            }
                            else
                            {
                                using (ExpressionCaptureScope attributeCaptureScope = new ExpressionCaptureScope(visitorContext, null))
                                {
                                    Visit(attribute.ArgumentList.Arguments[0].Expression);

                                    if (!attributeCaptureScope.IsEnum())
                                    {
                                        throw new System.Exception("Invalid attribute argument provided for sync");
                                    }

                                    syncMode = (UdonSyncMode)attributeCaptureScope.GetEnumValue();
                                }
                            }

                            break;
                        }
                    }

                    if (syncMode != UdonSyncMode.NotSynced)
                    {
                        break;
                    }
                }
            }

            return(syncMode);
        }
예제 #8
0
        public override void VisitArrayType(ArrayTypeSyntax node)
        {
            using (ExpressionCaptureScope arrayTypeCaptureScope = new ExpressionCaptureScope(visitorContext, visitorContext.topCaptureScope))
            {
                Visit(node.ElementType);

                for (int i = 0; i < node.RankSpecifiers.Count; ++i)
                {
                    arrayTypeCaptureScope.MakeArrayType();
                }
            }
        }
예제 #9
0
        // Boilerplate to have resolution work correctly
        public override void VisitUsingDirective(UsingDirectiveSyntax node)
        {
            using (ExpressionCaptureScope namespaceCapture = new ExpressionCaptureScope(visitorContext, null))
            {
                Visit(node.Name);

                if (!namespaceCapture.IsNamespace())
                {
                    throw new System.Exception("Did not capture a valid namespace");
                }

                visitorContext.resolverContext.AddNamespace(namespaceCapture.captureNamespace);
            }
        }
예제 #10
0
        public override void VisitMethodDeclaration(MethodDeclarationSyntax node)
        {
            MethodDefinition methodDefinition = new MethodDefinition();

            methodDefinition.declarationFlags     = node.Modifiers.HasModifier("public") ? MethodDeclFlags.Public : MethodDeclFlags.Private;
            methodDefinition.methodUdonEntryPoint = visitorContext.labelTable.GetNewJumpLabel("udonMethodEntryPoint");
            methodDefinition.methodUserCallStart  = visitorContext.labelTable.GetNewJumpLabel("userMethodCallEntry");
            methodDefinition.methodReturnPoint    = visitorContext.labelTable.GetNewJumpLabel("methodReturnPoint");

            methodDefinition.originalMethodName = node.Identifier.ValueText;
            methodDefinition.uniqueMethodName   = methodDefinition.originalMethodName;
            visitorContext.resolverContext.ReplaceInternalEventName(ref methodDefinition.uniqueMethodName);

            // Resolve the type arguments
            using (ExpressionCaptureScope returnTypeCapture = new ExpressionCaptureScope(visitorContext, null))
            {
                Visit(node.ReturnType);

                if (returnTypeCapture.captureType != typeof(void))
                {
                    //methodDefinition.returnType = returnTypeCapture.captureType;
                    methodDefinition.returnSymbol = visitorContext.topTable.CreateNamedSymbol("returnValSymbol", returnTypeCapture.captureType, SymbolDeclTypeFlags.Internal);
                }
            }

            methodDefinition.parameters = new ParameterDefinition[node.ParameterList.Parameters.Count];

            for (int i = 0; i < node.ParameterList.Parameters.Count; ++i)
            {
                ParameterSyntax parameter = node.ParameterList.Parameters[i];

                ParameterDefinition paramDef = new ParameterDefinition();

                using (ExpressionCaptureScope paramTypeCapture = new ExpressionCaptureScope(visitorContext, null))
                {
                    Visit(parameter.Type);
                    paramDef.type        = paramTypeCapture.captureType;
                    paramDef.symbolName  = parameter.Identifier.ValueText;
                    paramDef.paramSymbol = visitorContext.topTable.CreateNamedSymbol(parameter.Identifier.ValueText, paramDef.type, SymbolDeclTypeFlags.Local);
                }

                methodDefinition.parameters[i] = paramDef;
            }

            definedMethods.Add(methodDefinition);
        }
예제 #11
0
        public override void VisitFieldDeclaration(FieldDeclarationSyntax node)
        {
            bool isPublic = node.Modifiers.HasModifier("public");

            System.Type fieldType = null;

            using (ExpressionCaptureScope fieldTypeCapture = new ExpressionCaptureScope(visitorContext, null))
            {
                Visit(node.Declaration.Type);

                fieldType = fieldTypeCapture.captureType;
            }

            foreach (VariableDeclaratorSyntax variableDeclarator in node.Declaration.Variables)
            {
                SymbolDefinition newSymbol = visitorContext.topTable.CreateNamedSymbol(variableDeclarator.Identifier.ValueText, fieldType, isPublic ? SymbolDeclTypeFlags.Public : SymbolDeclTypeFlags.Private);

                classDefinition.fieldDefinitions.Add(new FieldDefinition(newSymbol));
            }
        }
예제 #12
0
        private List <System.Type> GetTypeArgumentList(TypeArgumentListSyntax typeArgumentList)
        {
            UpdateSyntaxNode(typeArgumentList);

            List <System.Type> argumentTypes = new List <System.Type>();

            foreach (TypeSyntax typeSyntax in typeArgumentList.Arguments)
            {
                using (ExpressionCaptureScope typeCaptureScope = new ExpressionCaptureScope(visitorContext, null))
                {
                    Visit(typeSyntax);

                    if (!typeCaptureScope.IsType())
                    {
                        throw new System.ArgumentException("Generic argument must be a valid type");
                    }

                    argumentTypes.Add(UdonSharpUtils.RemapBaseType(typeCaptureScope.captureType));
                }
            }

            return(argumentTypes);
        }
예제 #13
0
        public override void VisitTypeOfExpression(TypeOfExpressionSyntax node)
        {
            UpdateSyntaxNode(node);

            System.Type capturedType = null;

            using (ExpressionCaptureScope typeCapture = new ExpressionCaptureScope(visitorContext, null))
            {
                Visit(node.Type);

                capturedType = typeCapture.captureType;

                // Just throw a compile error for now instead of letting people get the typeof a type that won't exist in game
                if (capturedType == typeof(UdonSharpBehaviour) || capturedType.IsSubclassOf(typeof(UdonSharpBehaviour)))
                {
                    throw new System.NotSupportedException("UdonSharp does not currently support using `typeof` on user defined types");
                }
            }

            if (visitorContext.topCaptureScope != null)
            {
                visitorContext.topCaptureScope.SetToLocalSymbol(visitorContext.topTable.CreateConstSymbol(typeof(System.Type), capturedType));
            }
        }
예제 #14
0
        bool HasRecursiveMethodAttribute(MethodDeclarationSyntax node)
        {
            if (node.AttributeLists != null)
            {
                foreach (AttributeListSyntax attributeList in node.AttributeLists)
                {
                    foreach (AttributeSyntax attribute in attributeList.Attributes)
                    {
                        using (ExpressionCaptureScope attributeTypeCapture = new ExpressionCaptureScope(visitorContext, null))
                        {
                            attributeTypeCapture.isAttributeCaptureScope = true;
                            Visit(attribute.Name);

                            if (attributeTypeCapture.captureType == typeof(RecursiveMethodAttribute))
                            {
                                return(true);
                            }
                        }
                    }
                }
            }

            return(false);
        }
예제 #15
0
        protected List <SymbolDefinition> HandleVariableDeclaration(VariableDeclarationSyntax node, SymbolDeclTypeFlags symbolType, UdonSyncMode syncMode)
        {
            UpdateSyntaxNode(node);

            bool isVar = node.Type.IsVar;

            System.Type variableType = null;

            if (!isVar)
            {
                using (ExpressionCaptureScope typeCapture = new ExpressionCaptureScope(visitorContext, null))
                {
                    Visit(node.Type);

                    if (!typeCapture.IsType())
                    {
                        throw new System.Exception($"The type or namespace name '{typeCapture.unresolvedAccessChain}' could not be found (are you missing a using directive?)");
                    }

                    variableType = typeCapture.captureType;
                }
            }

            List <SymbolDefinition> newSymbols = new List <SymbolDefinition>();

            foreach (VariableDeclaratorSyntax variableDeclarator in node.Variables)
            {
                SymbolDefinition newSymbol = null;

                string variableName = variableDeclarator.Identifier.ValueText;

                using (ExpressionCaptureScope symbolCreationScope = new ExpressionCaptureScope(visitorContext, null))
                {
                    if (!isVar)
                    {
                        newSymbol = visitorContext.topTable.CreateNamedSymbol(variableDeclarator.Identifier.ValueText, variableType, symbolType);
                    }

                    // Run the initializer if it exists
                    // Todo: Run the set on the new symbol scope from within the initializer scope for direct setting
                    if (variableDeclarator.Initializer != null && symbolType.HasFlag(SymbolDeclTypeFlags.Local))
                    {
                        using (ExpressionCaptureScope initializerCapture = new ExpressionCaptureScope(visitorContext, null, newSymbol))
                        {
                            Visit(variableDeclarator.Initializer);

                            if (newSymbol == null)
                            {
                                // TODO: Find a way to determine the return type before generating initializer code, to avoid a copy on 'var' local initializers
                                variableType = initializerCapture.GetReturnType(true);
                                newSymbol    = visitorContext.topTable.CreateNamedSymbol(variableDeclarator.Identifier.ValueText, variableType, symbolType);
                            }

                            symbolCreationScope.SetToLocalSymbol(newSymbol);
                            symbolCreationScope.ExecuteSet(initializerCapture.ExecuteGet());
                        }
                    }

                    newSymbol.syncMode = syncMode;
                }

                VerifySyncValidForType(newSymbol.symbolCsType, syncMode);
                newSymbols.Add(newSymbol);
            }

            if (!visitorContext.resolverContext.IsValidUdonType(variableType))
            {
                throw new System.NotSupportedException($"Udon does not support variables of type '{variableType.Name}' yet");
            }

            return(newSymbols);
        }
        public SymbolDefinition Invoke(SymbolDefinition[] invokeParams)
        {
            SymbolDefinition methodResult = null;

            System.Type resultSymbolType = null;
            string      lookupSymbolName = null;

            switch (captureFunc)
            {
            case InternalFunc.TypeIDInstance:
            case InternalFunc.TypeIDGeneric:
                resultSymbolType = typeof(long);
                lookupSymbolName = "udonTypeID";
                break;

            case InternalFunc.TypeNameInstance:
            case InternalFunc.TypeNameGeneric:
                resultSymbolType = typeof(string);
                lookupSymbolName = "udonTypeName";
                break;

            default:
                throw new System.ArgumentException("Invalid internal method invocation");
            }

            methodResult = visitorContext.topTable.CreateUnnamedSymbol(resultSymbolType, SymbolDeclTypeFlags.Internal);

            if (captureFunc == InternalFunc.TypeIDInstance ||
                captureFunc == InternalFunc.TypeNameInstance)
            {
                SymbolDefinition invokeSymbol = captureScope.accessSymbol;

                using (ExpressionCaptureScope resultSetterScope = new ExpressionCaptureScope(visitorContext, null))
                {
                    resultSetterScope.SetToLocalSymbol(methodResult);

                    using (ExpressionCaptureScope getInvokeScope = new ExpressionCaptureScope(visitorContext, null))
                    {
                        getInvokeScope.SetToLocalSymbol(invokeSymbol);
                        getInvokeScope.ResolveAccessToken(nameof(VRC.Udon.UdonBehaviour.GetProgramVariable));

                        string symbolName = visitorContext.topTable.GetReflectionSymbol(lookupSymbolName, resultSymbolType).symbolUniqueName;

                        SymbolDefinition invokeResult = getInvokeScope.Invoke(new SymbolDefinition[] { visitorContext.topTable.CreateConstSymbol(typeof(string), symbolName) });

                        JumpLabel exitBranchJump = visitorContext.labelTable.GetNewJumpLabel("exitUdonTypeIdLoc");
                        JumpLabel falseBranchLoc = visitorContext.labelTable.GetNewJumpLabel("falseUdonTypeIdLoc");

                        SymbolDefinition nullCheckSymbol = null;

                        using (ExpressionCaptureScope nullCheckCondition = new ExpressionCaptureScope(visitorContext, null))
                        {
                            nullCheckCondition.SetToMethods(UdonSharpUtils.GetOperators(typeof(object), BuiltinOperatorType.Inequality));
                            nullCheckSymbol = nullCheckCondition.Invoke(new SymbolDefinition[] { invokeResult, visitorContext.topTable.CreateConstSymbol(typeof(object), null) });
                        }

                        visitorContext.uasmBuilder.AddJumpIfFalse(falseBranchLoc, nullCheckSymbol);

                        resultSetterScope.ExecuteSet(captureScope.CastSymbolToType(invokeResult, resultSymbolType, true));
                        visitorContext.uasmBuilder.AddJump(exitBranchJump);

                        // If the value is null
                        visitorContext.uasmBuilder.AddJumpLabel(falseBranchLoc);

                        if (captureFunc == InternalFunc.TypeIDInstance)
                        {
                            resultSetterScope.ExecuteSet(visitorContext.topTable.CreateConstSymbol(typeof(long), 0L));
                        }
                        else
                        {
                            resultSetterScope.ExecuteSet(visitorContext.topTable.CreateConstSymbol(typeof(string), "UnknownType"));
                        }

                        visitorContext.uasmBuilder.AddJumpLabel(exitBranchJump);
                    }
                }
            }
            else
            {
                object resultSymbolValue = null;

                if (captureFunc == InternalFunc.TypeIDGeneric)
                {
                    resultSymbolValue = Internal.UdonSharpInternalUtility.GetTypeID(genericType);
                }
                else if (captureFunc == InternalFunc.TypeNameGeneric)
                {
                    resultSymbolValue = Internal.UdonSharpInternalUtility.GetTypeName(genericType);
                }

                methodResult = visitorContext.topTable.CreateConstSymbol(resultSymbolType, resultSymbolValue);
            }

            using (ExpressionCaptureScope propagateScope = new ExpressionCaptureScope(visitorContext, visitorContext.topCaptureScope))
            {
                propagateScope.SetToLocalSymbol(methodResult);
            }

            return(methodResult);
        }
예제 #17
0
        public override void VisitClassDeclaration(ClassDeclarationSyntax node)
        {
            UpdateSyntaxNode(node);
            using (ExpressionCaptureScope classTypeCapture = new ExpressionCaptureScope(visitorContext, null))
            {
                foreach (string namespaceToken in namespaceStack.Reverse())
                {
                    classTypeCapture.ResolveAccessToken(namespaceToken);

                    if (classTypeCapture.IsNamespace())
                    {
                        visitorContext.resolverContext.AddNamespace(classTypeCapture.captureNamespace);
                    }
                }

                classTypeCapture.ResolveAccessToken(node.Identifier.ValueText);

                if (!classTypeCapture.IsType())
                {
                    throw new System.Exception($"User type {node.Identifier.ValueText} could not be found");
                }
            }

            if (node.AttributeLists != null)
            {
                foreach (AttributeListSyntax attributeList in node.AttributeLists)
                {
                    foreach (AttributeSyntax attribute in attributeList.Attributes)
                    {
                        System.Type captureType = null;

                        using (ExpressionCaptureScope attributeTypeScope = new ExpressionCaptureScope(visitorContext, null))
                        {
                            attributeTypeScope.isAttributeCaptureScope = true;

                            Visit(attribute.Name);

                            captureType = attributeTypeScope.captureType;
                        }

                        if (captureType != null && captureType == typeof(UdonBehaviourSyncModeAttribute))
                        {
                            if (attribute.ArgumentList != null &&
                                attribute.ArgumentList.Arguments != null &&
                                attribute.ArgumentList.Arguments.Count == 1)
                            {
                                using (ExpressionCaptureScope attributeCaptureScope = new ExpressionCaptureScope(visitorContext, null))
                                {
                                    Visit(attribute.ArgumentList.Arguments[0].Expression);

                                    if (!attributeCaptureScope.IsEnum())
                                    {
                                        throw new System.Exception("Invalid attribute argument provided for behaviour sync");
                                    }

                                    visitorContext.behaviourSyncMode = (BehaviourSyncMode)attributeCaptureScope.GetEnumValue();
                                }
                            }
                        }
                    }
                }
            }

            if (syntaxWalkerDepth == UdonSharpSyntaxWalkerDepth.ClassDefinitions ||
                syntaxWalkerDepth == UdonSharpSyntaxWalkerDepth.ClassMemberBodies)
            {
                base.VisitClassDeclaration(node);
            }
        }
 public InternalMethodHandler(ASTVisitorContext visitorContextIn, ExpressionCaptureScope captureScopeIn)
 {
     visitorContext = visitorContextIn;
     captureScope   = captureScopeIn;
 }
예제 #19
0
        public override void VisitMethodDeclaration(MethodDeclarationSyntax node)
        {
            UpdateSyntaxNode(node);

            MethodDefinition methodDefinition = new MethodDefinition();

            methodDefinition.declarationFlags     = node.Modifiers.HasModifier("public") ? MethodDeclFlags.Public : MethodDeclFlags.Private;
            methodDefinition.methodUdonEntryPoint = visitorContext.labelTable.GetNewJumpLabel("udonMethodEntryPoint");
            methodDefinition.methodUserCallStart  = visitorContext.labelTable.GetNewJumpLabel("userMethodCallEntry");
            methodDefinition.methodReturnPoint    = visitorContext.labelTable.GetNewJumpLabel("methodReturnPoint");

            string methodName = node.Identifier.ValueText;

            methodDefinition.originalMethodName = methodName;
            methodDefinition.uniqueMethodName   = methodDefinition.originalMethodName;
            visitorContext.resolverContext.ReplaceInternalEventName(ref methodDefinition.uniqueMethodName);

            foreach (string builtinMethodName in builtinMethodNames)
            {
                if (methodName == builtinMethodName)
                {
                    throw new System.Exception($"Cannot define method '{methodName}' with the same name as a built-in UdonSharpBehaviour method");
                }
            }

            // Resolve the type arguments
            using (ExpressionCaptureScope returnTypeCapture = new ExpressionCaptureScope(visitorContext, null))
            {
                Visit(node.ReturnType);

                if (returnTypeCapture.captureType != typeof(void))
                {
                    methodDefinition.returnSymbol = visitorContext.topTable.CreateNamedSymbol("returnValSymbol", returnTypeCapture.captureType, SymbolDeclTypeFlags.Internal);

                    if (!visitorContext.resolverContext.IsValidUdonType(returnTypeCapture.captureType))
                    {
                        throw new System.NotSupportedException($"Udon does not support return values of type '{returnTypeCapture.captureType.Name}' yet");
                    }
                }
            }

            methodDefinition.parameters = new ParameterDefinition[node.ParameterList.Parameters.Count];

            for (int i = 0; i < node.ParameterList.Parameters.Count; ++i)
            {
                ParameterSyntax parameter = node.ParameterList.Parameters[i];

                ParameterDefinition paramDef = new ParameterDefinition();

                using (ExpressionCaptureScope paramTypeCapture = new ExpressionCaptureScope(visitorContext, null))
                {
                    Visit(parameter.Type);

                    if (!paramTypeCapture.IsType())
                    {
                        throw new System.TypeLoadException($"The type or namespace name '{parameter.Type}' could not be found (are you missing a using directive?)");
                    }

                    if (!visitorContext.resolverContext.IsValidUdonType(paramTypeCapture.captureType))
                    {
                        throw new System.NotSupportedException($"Udon does not support method parameters of type '{paramTypeCapture.captureType.Name}' yet");
                    }

                    paramDef.type        = paramTypeCapture.captureType;
                    paramDef.symbolName  = parameter.Identifier.ValueText;
                    paramDef.paramSymbol = visitorContext.topTable.CreateNamedSymbol(parameter.Identifier.ValueText, paramDef.type, SymbolDeclTypeFlags.Local | SymbolDeclTypeFlags.MethodParameter);
                }

                methodDefinition.parameters[i] = paramDef;
            }

            definedMethods.Add(methodDefinition);
        }
        public override void VisitPropertyDeclaration(PropertyDeclarationSyntax node)
        {
            UpdateSyntaxNode(node);

            PropertyDefinition propertyDefinition = new PropertyDefinition();

            propertyDefinition.declarationFlags     = node.Modifiers.HasModifier("public") ? PropertyDeclFlags.Public : PropertyDeclFlags.Private;
            propertyDefinition.originalPropertyName = node.Identifier.Text;

            Type type = null;

            using (ExpressionCaptureScope propertyTypeCapture = new ExpressionCaptureScope(visitorContext, null))
            {
                Visit(node.Type);

                type = propertyTypeCapture.captureType;

                if (!visitorContext.resolverContext.IsValidUdonType(type))
                {
                    throw new NotSupportedException($"Udon does not support variable of type '{type}' yet");
                }
            }

            BackingFieldDefinition backingField = new BackingFieldDefinition();

            backingField.backingFieldName = $"{node.Identifier.Text}_k_BackingField";

            if (node.AttributeLists != null && node.AttributeLists.Any())
            {
                foreach (AttributeListSyntax attributes in node.AttributeLists)
                {
                    if (attributes.Target != null && attributes.Target.Identifier.Kind() == SyntaxKind.FieldKeyword)
                    {
                        foreach (AttributeSyntax attribute in attributes.Attributes)
                        {
                            using (ExpressionCaptureScope attributeTypeCapture = new ExpressionCaptureScope(visitorContext, null))
                            {
                                attributeTypeCapture.isAttributeCaptureScope = true;
                                Visit(attribute.Name);

                                backingField.synced = true;

                                if (attributeTypeCapture.captureType != typeof(UdonSyncedAttribute))
                                {
                                    continue;
                                }

                                if (attribute.ArgumentList == null || attribute.ArgumentList.Arguments == null || attribute.ArgumentList.Arguments.Count == 0)
                                {
                                    backingField.syncMode = UdonSyncMode.None;
                                }
                                else
                                {
                                    using (ExpressionCaptureScope attributeCaptureScope = new ExpressionCaptureScope(visitorContext, null))
                                    {
                                        Visit(attribute.ArgumentList.Arguments[0].Expression);

                                        if (!attributeCaptureScope.IsEnum())
                                        {
                                            throw new Exception("Invalid attribute argument provided for sync");
                                        }

                                        backingField.syncMode = (UdonSyncMode)attributeCaptureScope.GetEnumValue();
                                    }
                                }

                                break;
                            }
                        }
                    }

                    if (backingField.synced)
                    {
                        break;
                    }
                }
            }

            backingField.type       = type;
            propertyDefinition.type = type;
            backingField.type       = type;

            if (node.AccessorList != null)
            {
                foreach (AccessorDeclarationSyntax accessor in node.AccessorList.Accessors)
                {
                    bool isSetter = accessor.Keyword.Kind() == SyntaxKind.SetKeyword;
                    if (isSetter)
                    {
                        SetterDefinition setter = new SetterDefinition();
                        setter.accessorName     = $"_set_{node.Identifier.Text}";
                        setter.entryPoint       = visitorContext.labelTable.GetNewJumpLabel("udonMethodEntryPoint");
                        setter.userCallStart    = visitorContext.labelTable.GetNewJumpLabel("userMethodCallEntry");
                        setter.returnPoint      = visitorContext.labelTable.GetNewJumpLabel("methodReturnPoint");
                        setter.backingField     = (accessor.Body == null && accessor.ExpressionBody == null) ? backingField : null;
                        setter.type             = type;
                        setter.declarationFlags = GetDeclFlags(accessor);
                        setter.paramSymbol      = visitorContext.topTable.CreateNamedSymbol("value", type, SymbolDeclTypeFlags.Local | SymbolDeclTypeFlags.MethodParameter);

                        propertyDefinition.setter = setter;
                    }
                    else
                    {
                        GetterDefinition getter = new GetterDefinition();
                        getter.accessorName     = $"_get_{node.Identifier.Text}";
                        getter.entryPoint       = visitorContext.labelTable.GetNewJumpLabel("udonMethodEntryPoint");
                        getter.userCallStart    = visitorContext.labelTable.GetNewJumpLabel("userMethodCallEntry");
                        getter.returnPoint      = visitorContext.labelTable.GetNewJumpLabel("methodReturnPoint");
                        getter.backingField     = (accessor.Body == null && accessor.ExpressionBody == null) ? backingField : null;
                        getter.type             = type;
                        getter.declarationFlags = GetDeclFlags(accessor);

                        using (ExpressionCaptureScope returnTypeCapture = new ExpressionCaptureScope(visitorContext, null))
                        {
                            Visit(node.Type);

                            getter.returnSymbol = visitorContext.topTable.CreateNamedSymbol("returnValSymbol", returnTypeCapture.captureType, SymbolDeclTypeFlags.Internal);
                        }

                        propertyDefinition.getter = getter;
                    }
                }
            }
            else
            {
                GetterDefinition getter = new GetterDefinition();
                getter.accessorName     = $"_get_{node.Identifier.Text}";
                getter.entryPoint       = visitorContext.labelTable.GetNewJumpLabel("udonMethodEntryPoint");
                getter.userCallStart    = visitorContext.labelTable.GetNewJumpLabel("userMethodCallEntry");
                getter.returnPoint      = visitorContext.labelTable.GetNewJumpLabel("methodReturnPoint");
                getter.type             = type;
                getter.declarationFlags = PropertyDeclFlags.Public;

                using (ExpressionCaptureScope returnTypeCapture = new ExpressionCaptureScope(visitorContext, null))
                {
                    Visit(node.Type);

                    getter.returnSymbol = visitorContext.topTable.CreateNamedSymbol("returnValSymbol", returnTypeCapture.captureType, SymbolDeclTypeFlags.Internal);
                }

                propertyDefinition.getter = getter;
            }

            if (propertyDefinition.setter?.backingField != null || propertyDefinition.getter?.backingField != null)
            {
                backingField.fieldSymbol          = visitorContext.topTable.CreateNamedSymbol("kBackingField", type, SymbolDeclTypeFlags.Internal | SymbolDeclTypeFlags.PropertyBackingField);
                backingField.fieldSymbol.syncMode = backingField.syncMode;

                if (backingField.synced)
                {
                    VerifySyncValidForType(backingField.type, backingField.fieldSymbol.syncMode);
                }
            }

            definedProperties.Add(propertyDefinition);
        }
예제 #21
0
        private List <System.Attribute> GetFieldAttributes(FieldDeclarationSyntax node)
        {
            List <System.Attribute> attributes = new List <System.Attribute>();

            if (node.AttributeLists != null)
            {
                foreach (AttributeListSyntax attributeList in node.AttributeLists)
                {
                    UpdateSyntaxNode(attributeList);

                    foreach (AttributeSyntax attribute in attributeList.Attributes)
                    {
                        using (ExpressionCaptureScope attributeTypeCapture = new ExpressionCaptureScope(visitorContext, null))
                        {
                            attributeTypeCapture.isAttributeCaptureScope = true;
                            Visit(attribute.Name);

                            System.Type captureType = attributeTypeCapture.captureType;

                            if (captureType == typeof(UdonSyncedAttribute))
                            {
                                UdonSyncMode syncMode = UdonSyncMode.NotSynced;

                                if (attribute.ArgumentList == null ||
                                    attribute.ArgumentList.Arguments == null ||
                                    attribute.ArgumentList.Arguments.Count == 0)
                                {
                                    syncMode = UdonSyncMode.None;
                                }
                                else
                                {
                                    using (ExpressionCaptureScope attributeCaptureScope = new ExpressionCaptureScope(visitorContext, null))
                                    {
                                        Visit(attribute.ArgumentList.Arguments[0].Expression);

                                        if (!attributeCaptureScope.IsEnum())
                                        {
                                            throw new System.Exception("Invalid attribute argument provided for sync");
                                        }

                                        syncMode = (UdonSyncMode)attributeCaptureScope.GetEnumValue();
                                    }
                                }
                                attributes.Add(new UdonSyncedAttribute(syncMode));
                            }
                            else if (captureType != null)
                            {
                                try
                                {
                                    object attributeObject = null;

                                    if (attribute.ArgumentList == null ||
                                        attribute.ArgumentList.Arguments == null ||
                                        attribute.ArgumentList.Arguments.Count == 0)
                                    {
                                        attributeObject = System.Activator.CreateInstance(captureType);
                                    }
                                    else
                                    {
                                        // todo: requires constant folding to support decently
                                        object[] attributeArgs = new object[attribute.ArgumentList.Arguments.Count];

                                        for (int i = 0; i < attributeArgs.Length; ++i)
                                        {
                                            AttributeArgumentSyntax attributeArg = attribute.ArgumentList.Arguments[i];

                                            using (ExpressionCaptureScope attributeCapture = new ExpressionCaptureScope(visitorContext, null))
                                            {
                                                Visit(attributeArg);

                                                SymbolDefinition attrSymbol = attributeCapture.ExecuteGet();

                                                if (!attrSymbol.declarationType.HasFlag(SymbolDeclTypeFlags.Constant))
                                                {
                                                    throw new System.ArgumentException("Attributes do not support non-constant expressions");
                                                }

                                                attributeArgs[i] = attrSymbol.symbolDefaultValue;
                                            }
                                        }

                                        attributeObject = System.Activator.CreateInstance(captureType, attributeArgs);
                                    }

                                    if (attributeObject != null)
                                    {
                                        attributes.Add((System.Attribute)attributeObject);
                                    }
                                }
                                catch (System.Reflection.TargetInvocationException constructionException)
                                {
                                    throw constructionException.InnerException;
                                }
                            }
                        }
                    }
                }
            }

            return(attributes);
        }