static void ExportUdonTypes() { string path = EditorUtility.SaveFilePanel("Save Udon Types", "", "UdonNodeInfo", "dll"); var typeResolver = new TypeResolverGroup(new List <IUAssemblyTypeResolver>() { new SystemTypeResolver(), new UnityEngineTypeResolver(), new VRCSDK2TypeResolver(), new UdonTypeResolver(), new ExceptionTypeResolver(), new UdonBehaviourTypeResolver(), }); var rootType = new TDType(); try { EditorUtility.DisplayProgressBar("Progress", "Parsing Definitions...", 1f / 2); ParseDefinitions(rootType, typeResolver); EditorUtility.DisplayProgressBar("Progress", "Saving to file...", 2f / 2); string codeString = UdonTypeDLLExporter.ExportTDTypeAsDLL(rootType, typeResolver); CompilerParameters parameters = new CompilerParameters(); parameters.GenerateExecutable = false; parameters.CompilerOptions = "-nostdlib -noconfig"; parameters.OutputAssembly = "Output.dll"; CompilerResults r = CodeDomProvider.CreateProvider("CSharp") .CompileAssemblyFromSource(parameters, codeString); foreach (var s in r.Output) { if (s.Contains("warning")) { continue; } Debug.Log(s); } File.WriteAllLines("source.txt", new[] { codeString }); File.Copy("Output.dll", path, true); } finally { EditorUtility.ClearProgressBar(); } Debug.Log($"Done\nOutput to: {path}"); }
private static void AddInputs(Class Class, Method method) { for (int i = 0; i < method.Inputs.Count; i++) { TDType input = method.Inputs[i]; Class.Methods.Append(input); //Type name Class.Methods.Append( $" {UdonTypeExporter.RemoveTypeSpecialCharacters(UdonTypeExporter.FirstCharacterToLower(input.UdonName), true, true)}_{i}"); //Parameter name if (i != method.Inputs.Count - 1) { Class.Methods.Append(", "); } } }
public double[] GetStats(TDType type_) { double[] ret = new double[m_evals.Count]; int endIndex, startIndex; if( (endIndex=m_pnls.Dates.IndexOf(AsOfDate))==-1) return ret; DateTime date = GetDate(type_); startIndex = m_pnls.Dates.IndexOf(date); if (startIndex == -1) return ret; for (int i = startIndex; i <= endIndex; ++i) for (int j = 0; j < m_pnls.ArrayLength; ++j) ret[j] += m_pnls.GetValue(m_pnls.Dates[i], j); return ret; }
private static void ParseDefinitions( TDType rootType, TypeResolverGroup typeResolverGroup) { foreach (var definition in UdonEditorManager.Instance.GetNodeDefinitions()) { if (StartsWithIgnoredKeyword(definition) | IsSpecialDefinition(definition)) { continue; } //Try to match by the non constructor regex, if it fails fallback to the constructor regex. //Perhaps they can be combined but this works. var match = NonCtorRegex.Match(definition.fullName); if (match.Groups.Count != NonCtorRegex.GetGroupNumbers().Length) { match = CtorRegex.Match(definition.fullName); } var groups = match.Groups; //Make sure all groups are filled. If not then the regex failed. if (groups.Count == NonCtorRegex.GetGroupNumbers().Length) { var definitionName = groups["namespace"].ToString(); var methodType = groups["methodType"].ToString(); var methodName = groups["methodName"].ToString(); var inputsRaw = groups["inputs"].ToString(); var methodOutput = groups["outputs"].ToString(); //For some reason underscores are allowed and I'm not quite sure how to deal with them, so let's just do this //Replace with -, split by _, replace - with _ inputsRaw = inputsRaw.Replace("VRCSDKBaseVRC_", "VRCSDKBaseVRC-"); var methodInputs = inputsRaw.Split('_'); for (int i = 0; i < methodInputs.Length; i++) { methodInputs[i] = methodInputs[i].Replace("-", "_"); } var isStatic = (definition.inputNames.Length > 0 && definition.inputNames[0] != "instance"); //Some of the methods don't have any inputs(so definition.inputNames[0] doesn't exist) so we have to check the wrapper try { int outputCount = definition.outputs[0] != typeof(void) ? 1 : 0; int inputParameterCount = Wrapper.GetExternFunctionParameterCount(definition.fullName) - outputCount; if (definition.inputNames.Length == 0 && inputParameterCount == 0) { isStatic = true; } } catch //Catch because the wrapper just throws for some unsupported externs that exist in node definitions { } var fullUdonExternString = definition.fullName; var definitionType = typeResolverGroup.GetTypeFromTypeStringWithErrors(definitionName); var namespaceName = GetTypeFullName(definitionType); var definitionTDType = GetOrCreateTDType(rootType, namespaceName, typeResolverGroup); definitionTDType.UdonName = GenerateUdonName(definitionType); definitionTDType.CSharpType = definitionType; //Create TDTypes for all C# types encountered in the definition, and attach methods to them for each of the Extern functions var method = new Method { FullUdonExternString = fullUdonExternString, MethodName = methodName, MethodType = methodType, IsStatic = isStatic }; foreach (var udonTypeName in methodInputs) { if (udonTypeName != "") { var thisType = typeResolverGroup.GetTypeFromTypeStringWithErrors(udonTypeName); var typeName = GetTypeFullName(thisType); TDType tdType = GetOrCreateTDType(rootType, typeName, typeResolverGroup); tdType.UdonName = GenerateUdonName(thisType); tdType.CSharpType = thisType; if (typeResolverGroup.GetTypeFromTypeStringWithErrors(tdType.UdonName) != thisType) { Debug.LogError( $"Could not generate proper udon name for {thisType}. Generated: {tdType.UdonName}"); } method.Inputs.Add(tdType); } } if (methodOutput != "") { var thisType = typeResolverGroup.GetTypeFromTypeStringWithErrors(methodOutput); TDType tdType = GetOrCreateTDType(rootType, GetTypeFullName(thisType), typeResolverGroup); tdType.UdonName = GenerateUdonName(thisType); tdType.CSharpType = thisType; method.Output = tdType; } if (method.IsStatic) { definitionTDType.StaticMethods.Add(method); } else { definitionTDType.NonStaticMethods.Add(method); } } else { Debug.LogError($"Unhandled definition: {definition.fullName}"); } } }
public static TDType GetOrCreateTDType(TDType rootType, string fullName, TypeResolverGroup typeResolverGroup) { bool containsGenericArguments = fullName.Contains("<"); Queue <string> namespaces; string genericArguments = null; if (containsGenericArguments) //Generic types { var match = GenericsRegex.Match(fullName); var groups = match.Groups; var baseType = groups["GenericBaseType"].ToString(); genericArguments = groups["GenericArguments"].ToString(); namespaces = new Queue <string>(baseType.Split('.')); } else { namespaces = new Queue <string>(fullName.Split('.')); } var current = rootType; while (namespaces.Count > 0) { var name = namespaces.Dequeue(); //Only the full string is "generic", so it must be the last thing in the queue. //IE. System.Collections.Generic isn't generic itself, but System.Collections.Generic.List is generic bool isGeneric = containsGenericArguments && namespaces.Count == 0; var child = current.Children.Find(x => x.TypeName == name && x.IsGeneric == isGeneric && genericArguments == x.InputGenericArguments); if (child != null) { //Go down tree current = child; } else { //Create an go down tree var type = new TDType { NamespaceName = current.FullName, FullName = (current.FullName != null ? current.FullName + "." : "") + name, TypeName = name, InputGenericArguments = genericArguments }; string attemptedUdonName = GenerateUdonName(type.FullName, true); //Try to generate udon name and set it if it's correct. if (typeResolverGroup.GetTypeFromTypeString(attemptedUdonName) != null) { type.UdonName = attemptedUdonName; } current.Children.Add(type); current = type; current.IsGeneric = isGeneric; } } if (current.IsGeneric) { current.IsGeneric = true; if (!genericArguments.Contains("<")) { current.AddGenericArguments(rootType, typeResolverGroup, genericArguments.Replace(" ", "").Split(',')); } else { //Only one thing contains a nested generic argument in Udon currently //and luckily it looks like "thing<other<something, else>>" //which means it's a single layer of nesting //So for now we can just pass "other<something, else>" to GetOrCreateTDType //In the future this might change? current.AddGenericArguments(rootType, typeResolverGroup, genericArguments); } } if (fullName.Contains("[]")) { //Add base type for arrays GetOrCreateTDType(rootType, fullName.Replace("[]", ""), typeResolverGroup); } return(current); }
public DateTime GetDate(TDType type_) { DateTime ret = DateTime.MinValue; switch (type_) { case TDType.OneDay: ret=AsOfDate; while (PnlConstruct.Dates.Contains(ret) == false) ret = MyCalendar.NextWeekDay(ret); break; case TDType.WeekToDate: ret = AsOfDate; while (ret.DayOfWeek != DayOfWeek.Monday) ret = MyCalendar.PrevWeekDay(ret); break; case TDType.MonthToDate: ret = new DateTime(AsOfDate.Year, AsOfDate.Month, 1); while (PnlConstruct.Dates.Contains(ret) == false) ret = MyCalendar.NextWeekDay(ret); break; case TDType.QuarterToDate: int month = AsOfDate.Month; switch (month) { case 1: case 2: case 3: ret = new DateTime(AsOfDate.Year, 1, 1); break; case 4: case 5: case 6: ret = new DateTime(AsOfDate.Year, 4, 1); break; case 7: case 8: case 9: ret = new DateTime(AsOfDate.Year, 7, 1); break; case 10: case 11: case 12: ret = new DateTime(AsOfDate.Year, 10, 1); break; } while (PnlConstruct.Dates.Contains(ret) == false) ret = MyCalendar.NextWeekDay(ret); break; case TDType.YearToDate: ret = new DateTime(AsOfDate.Year, 1, 1); while (PnlConstruct.Dates.Contains(ret) == false) ret = MyCalendar.NextWeekDay(ret); break; case TDType.Inception: ret = PnlConstruct.Dates[0]; break; case TDType.CustomToDate: ret = CustomStartDate; while (PnlConstruct.Dates.Contains(ret) == false) { if (ret > PnlConstruct.LastDate) { ret = PnlConstruct.LastDate; break; } ret = MyCalendar.NextWeekDay(ret); } break; case TDType.OneYear: ret = AsOfDate.AddYears(-1); if (MyCalendar.IsWeekend(ret)) ret = MyCalendar.NextWeekDay(ret); break; case TDType.TwoYear: ret = AsOfDate.AddYears(-2); if (MyCalendar.IsWeekend(ret)) ret = MyCalendar.NextWeekDay(ret); break; } return ret; }
public static string ExportTDTypeAsDLL(TDType root, TypeResolverGroup typeResolverGroup) { HashSet <Class> parentlessClasses = new HashSet <Class>(); HashSet <Class> extenstionClasses = new HashSet <Class>(); Dictionary <string, Class> fullNameToClass = new Dictionary <string, Class>(); void WriteTypeCode(TDType type) { if (string.IsNullOrEmpty(type.FullName) || type.FullName.Contains("*")) { return; } var fullName = type.FullName.Replace("[]", "Array"); var typeName = type.TypeName.Replace("[]", "Array"); bool extensionClass = type.FullName.EndsWith("[]"); string dictionaryKey = type.IsGeneric ? type.FullName + type.GenericArguments.Count : type.FullName; //Create or get class if (!fullNameToClass.TryGetValue(dictionaryKey, out var Class)) { Class = new Class { UdonName = type.UdonName, TypeName = typeName, IsExtentionClass = extensionClass, Type = type, FullName = type.FullName }; Class.IsNamespace = Class.TypeName == "System" || Class.TypeName == "Collections" || (string.IsNullOrEmpty(Class.UdonName) && type.GenericArguments.Count == 0); if (type.CSharpType != null) { Class.IsEnum = type.CSharpType.IsEnum; Class.IsInterface = type.CSharpType.IsInterface; Class.IsStruct = type.CSharpType.IsValueType; if (!Class.IsEnum && !Class.IsExtentionClass) { Class.InheritedClass = type.CSharpType.GetFirstInheritedUdonType(typeResolverGroup); } if (!Class.IsExtentionClass) { type.CSharpType.AddTypeInterfaces(Class.Interfaces, typeResolverGroup); } if (Class.IsEnum) { var names = Enum.GetNames(type.CSharpType); foreach (var name in names) { Class.EnumNames.Add(name); } } } fullNameToClass[dictionaryKey] = Class; //Add new class to children if (string.IsNullOrEmpty(type.NamespaceName) || Class.IsNamespace) { parentlessClasses.Add(Class); } else { if (fullNameToClass.TryGetValue(type.NamespaceName, out var Parent)) { if (extensionClass) { extenstionClasses.Add(Class); } else { Parent.Children.Add(Class); } } else { Debug.LogError($"Parent class not created {type.NamespaceName}"); } } } if (type.UdonName != null) { AddMethods(type.StaticMethods, Class, extensionClass, type.FullName); AddMethods(type.NonStaticMethods, Class, extensionClass, type.FullName); } } void VisitType(TDType type) { WriteTypeCode(type); foreach (var child in type.Children) { VisitType(child); } } //Visit tree and build classes/namespaces VisitType(root); //Required for -nostdlib var collections = fullNameToClass["System.Collections"].Methods; collections.AppendLine("public interface IEnumerable { }"); var system = fullNameToClass["System"].Methods; system.AppendLine("public abstract class ValueType { }"); system.AppendLine("public abstract class Enum : ValueType { }"); system.AppendLine("public class Attribute { }"); system.AppendLine("public abstract class Delegate { }"); system.AppendLine("public abstract class MulticastDelegate : Delegate { }"); system.AppendLine("public struct IntPtr { }"); system.AppendLine("public struct UIntPtr { }"); system.AppendLine("public struct RuntimeTypeHandle { }"); system.AppendLine("public struct RuntimeMethodHandle { }"); system.AppendLine("public struct RuntimeFieldHandle { }"); system.AppendLine("public interface IDisposable { }"); system.AppendLine("public sealed class ParamArrayAttribute : Attribute { }"); //Write all namespaces out var fullCode = new StringBuilder(); foreach (var Class in parentlessClasses) { fullCode.AppendLine(Class.GenerateCode()); } foreach (var Class in extenstionClasses) { fullCode.AppendLine(Class.GenerateCode()); } fullCode.AppendLine(attributeClassString); return(fullCode.ToString()); }