// Automatically infers the name of the symbol based on its type // Used for intermediate values usually public SymbolDefinition CreateUnnamedSymbol(string symbolType, SymbolDeclTypeFlags declType) { System.Type resolvedType = resolver.ResolveExternType(symbolType); if (declType.HasFlag(SymbolDeclTypeFlags.Array)) { resolvedType = resolvedType.MakeArrayType(); } return(CreateUnnamedSymbol(resolvedType, declType)); }
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); }
/// <summary> /// Create a symbol given a name. At the moment assumes that only internal symbols get incremented, this means there's no masking at the moment for local variables. /// </summary> /// <param name="symbolName"></param> /// <param name="resolvedSymbolType"></param> /// <param name="declType"></param> /// <param name="appendType">Used to disable redundant type append from unnamed variable allocations</param> /// <returns></returns> private SymbolDefinition CreateNamedSymbolInternal(string symbolName, System.Type resolvedSymbolType, SymbolDeclTypeFlags declType, bool appendType = true) { if (resolvedSymbolType == null || symbolName == null) { throw new System.ArgumentNullException(); } if (!declType.HasFlag(SymbolDeclTypeFlags.Internal) && symbolName.StartsWith("__")) { throw new System.ArgumentException($"Symbol {symbolName} cannot have name starting with \"__\", this naming is reserved for internal variables."); } string uniqueSymbolName = symbolName; bool hasGlobalDeclaration = false; if (declType.HasFlag(SymbolDeclTypeFlags.Internal)) { uniqueSymbolName = $"intnl_{uniqueSymbolName}"; } if (declType.HasFlag(SymbolDeclTypeFlags.Constant)) { uniqueSymbolName = $"const_{uniqueSymbolName}"; hasGlobalDeclaration = true; } if (declType.HasFlag(SymbolDeclTypeFlags.This)) { uniqueSymbolName = $"this_{uniqueSymbolName}"; hasGlobalDeclaration = true; } if (!declType.HasFlag(SymbolDeclTypeFlags.Public) && !declType.HasFlag(SymbolDeclTypeFlags.Private)) { if (appendType) { string sanitizedName = resolver.SanitizeTypeName(resolvedSymbolType.Name); uniqueSymbolName += $"_{sanitizedName}"; } if (hasGlobalDeclaration) { uniqueSymbolName = $"__{IncrementGlobalNameCounter(uniqueSymbolName)}_{uniqueSymbolName}"; } else { uniqueSymbolName = $"__{IncrementUniqueNameCounter(uniqueSymbolName)}_{uniqueSymbolName}"; } } System.Type typeForName = resolvedSymbolType; if (resolvedSymbolType == typeof(UdonSharpBehaviour) || resolvedSymbolType.IsSubclassOf(typeof(UdonSharpBehaviour))) { typeForName = typeof(VRC.Udon.UdonBehaviour); } else if (resolvedSymbolType.IsArray && (resolvedSymbolType.GetElementType() == typeof(UdonSharpBehaviour) || resolvedSymbolType.GetElementType().IsSubclassOf(typeof(UdonSharpBehaviour)))) { typeForName = typeof(Component[]); // Hack because VRC doesn't expose UdonBehaviour array type } string udonTypeName = resolver.GetUdonTypeName(typeForName); if (udonTypeName == null) { throw new System.ArgumentException($"Could not locate Udon type for system type {resolvedSymbolType.FullName}"); } udonTypeName = udonTypeName.Replace("VRCUdonCommonInterfacesIUdonEventReceiver", "VRCUdonUdonBehaviour"); SymbolDefinition symbolDefinition = new SymbolDefinition(); symbolDefinition.declarationType = declType; symbolDefinition.symbolCsType = resolvedSymbolType; symbolDefinition.symbolOriginalName = symbolName; symbolDefinition.symbolResolvedTypeName = udonTypeName; symbolDefinition.symbolUniqueName = uniqueSymbolName; if (hasGlobalDeclaration) { GetGlobalSymbolTable().symbolDefinitions.Add(symbolDefinition); } else { symbolDefinitions.Add(symbolDefinition); } return(symbolDefinition); }