private static void PopulateClass(TypeSafeDataUnit dataUnit, CodeTypeDeclaration container) { foreach (var nestedUnit in dataUnit.NestedUnits) { string className; if (!CompilerUtil.GetSafeNameAndVerifyNotDuplicate(nestedUnit.ClassName, container, out className)) { continue; } if (className == container.Name) { TSLog.LogWarning(LogCategory.Compile, Strings.Warning_NameCannotBeSameAsParent); className = "_" + className; // Check for duplicates again after having added the '_' if (!CompilerUtil.GetSafeNameAndVerifyNotDuplicate(className, container, out className)) { continue; } } var nestedContainer = CompilerUtil.CreateStaticType(className); PopulateClass(nestedUnit, nestedContainer); container.Members.Add(nestedContainer); } PopulateClassMembers(dataUnit, container); }
private static CodeMemberMethod GetGenericResourceListMethod(string name) { var method = new CodeMemberMethod { Name = name, ReturnType = new CodeTypeReference(typeof(List <>), CodeTypeReferenceOptions.GlobalReference) { TypeArguments = { new CodeTypeReference("global::TypeSafe.Resource", new CodeTypeReference("TResource", CodeTypeReferenceOptions.GenericTypeParameter)) } }, TypeParameters = { new CodeTypeParameter("TResource") { Constraints ={ CompilerUtil.GetGlobalScopeTypeReference(typeof(Object)) } } }, Attributes = MemberAttributes.Public | MemberAttributes.Static }; return(method); }
private static CodeExpression GetCreateExpression(TypeSafeDataEntry c, Type t) { if (t.IsPrimitive) { if (c.Parameters.Length == 0 || c.Parameters.Length > 1 || !c.Parameters[0].GetType().IsPrimitive || c.Parameters[0].GetType() != t) { throw new ArgumentException("Primitive DataType must have a single parameter of the same type"); } return(new CodePrimitiveExpression(c.Parameters[0])); } if (t == typeof(string)) { if (c.Parameters.Length == 0 || c.Parameters.Length > 1 || !(c.Parameters[0] is string)) { throw new ArgumentException("String DataType must have a single string parameter"); } return(new CodePrimitiveExpression(c.Parameters[0])); } if (!c.Parameters.All(p => p.GetType().IsPrimitive || p is string)) { throw new ArgumentException("Parameters must be all primitive types"); } var dataType = new CodeTypeReference(t); CompilerUtil.SetTypeGlobalReference(dataType); return(new CodeObjectCreateExpression(dataType, c.Parameters.Select(p => new CodePrimitiveExpression(p)).Cast <CodeExpression>().ToArray())); }
public CodeCompileUnit Compile(TypeSafeDataUnit dataUnit) { var compileUnit = new CodeCompileUnit(); compileUnit.UserData.Add(Strings.CompileUnitUserDataKey, dataUnit.FileName); CompilerUtil.WriteHeader(compileUnit); var ns = new CodeNamespace(Namespace); compileUnit.Namespaces.Add(ns); var className = CompilerUtil.GetSafeName(dataUnit.ClassName, false, false); if (className != dataUnit.ClassName) { TSLog.LogWarning(LogCategory.Compile, string.Format("Class name was modified to conform to C# standards ({0} -> {1})", dataUnit.ClassName, className)); } var container = CompilerUtil.CreateStaticType(className); CompilerUtil.AddTypeSafeTag(container); PopulateClass(dataUnit, container); ns.Types.Add(container); return(compileUnit); }
/// <summary> /// Get a CodeTypeReference object to the TypeSafe.Resource[T] class where T is <paramref name="t" />. /// </summary> public static CodeTypeReference GetResourceType(Type t) { if (t == typeof(GameObject)) { return(new CodeTypeReference("global::TypeSafe.PrefabResource")); } return(new CodeTypeReference("global::TypeSafe.Resource", CompilerUtil.GetGlobalScopeTypeReference(t))); }
public static void WriteGetContentsGenericMethod(CodeTypeDeclaration type) { var method = GetGenericResourceListMethod(Strings.GetResourcesMethodName); method.Comments.AddRange(CompilerUtil.CreateDocsComment(Strings.GetContentsGenericCommentSummary, Strings.GetContentsGenericCommentReturns)); method.Statements.Add( new CodeMethodReturnStatement( new CodeSnippetExpression( "global::TypeSafe.TypeSafeUtil.GetResourcesOfType<TResource>(GetContents())"))); type.Members.Add(method); }
public static void CreateGetContentsMethod(CodeTypeDeclaration type) { var method = new CodeMemberMethod { Name = Strings.GetResourcesMethodName, ReturnType = GetIResourceIListType(), Attributes = MemberAttributes.Public | MemberAttributes.Static }; method.Comments.AddRange(CompilerUtil.CreateDocsComment(Strings.GetContentsCommentSummary, Strings.GetContentsCommentReturns)); method.Statements.Add( new CodeMethodReturnStatement(new CodeFieldReferenceExpression(null, CollectionMemberName))); type.Members.Add(method); }
public static void WriteUnloadAllRecursiveMethod(CodeTypeDeclaration type) { var method = new CodeMemberMethod { Name = Strings.UnloadAllRecursiveMethodName }; method.Comments.AddRange(CompilerUtil.CreateDocsComment(Strings.UnloadAllRecursiveCommentSummary)); method.Statements.Add( new CodeMethodInvokeExpression( new CodeTypeReferenceExpression(new CodeTypeReference("TypeSafe.TypeSafeUtil") { Options = CodeTypeReferenceOptions.GlobalReference }), "UnloadAll", new CodeSnippetExpression("GetContentsRecursive()"))); type.Members.Add(method); }
private static void WriteResourceProperty(CodeTypeDeclaration type, ResourceDefinition rd, int index) { string name; if (!CompilerUtil.GetSafeNameAndVerifyNotDuplicate(rd.Name, type, out name)) { return; } var resourceType = GetResourceType(rd.Type); var attributes = MemberAttributes.Static; if (rd.Type.IsNotPublic) { attributes |= MemberAttributes.Assembly; } else { attributes |= MemberAttributes.Public; } // Create a property to access the array var propertyExpression = new CodeMemberProperty { Name = name, Type = resourceType, HasSet = false, HasGet = true, Attributes = attributes, GetStatements = { new CodeMethodReturnStatement(new CodeCastExpression(resourceType, new CodeArrayIndexerExpression( new CodeVariableReferenceExpression(CollectionMemberName), new CodePrimitiveExpression(index)))) } }; type.Members.Add(propertyExpression); }
private void WriteFolder(CodeTypeDeclaration type, ResourceFolder folder) { ResourceCompilerUtil.WriteResources(type, folder); foreach (var f in folder.Folders) { var c = CompilerUtil.CreateStaticType(CompilerUtil.GetSafeName(f.Name)); WriteFolder(c, f); type.Members.Add(c); } ResourceCompilerUtil.CreateGetContentsMethod(type); ResourceCompilerUtil.CreateGetContentsRecursiveMethod(type, folder); ResourceCompilerUtil.WriteGetContentsGenericMethod(type); ResourceCompilerUtil.WriteGetContentsRecursiveGenericMethod(type); ResourceCompilerUtil.WriteUnloadAllMethod(type); ResourceCompilerUtil.WriteUnloadAllRecursiveMethod(type); }
public CodeCompileUnit Compile(ResourceDatabase database) { var unit = new CodeCompileUnit(); unit.UserData.Add(Strings.CompileUnitUserDataKey, "Resources"); CompilerUtil.WriteHeader(unit); var ns = new CodeNamespace(Namespace); unit.Namespaces.Add(ns); var container = CompilerUtil.CreateStaticType(ClassName); CompilerUtil.AddTypeSafeTag(container); WriteFolder(container, database.RootFolder); ns.Types.Add(container); return(unit); }
public static void CreateGetContentsRecursiveMethod(CodeTypeDeclaration type, ResourceFolder folder) { var cache = new CodeMemberField(GetIResourceIListType(), RecursiveLookupCacheName) { Attributes = MemberAttributes.Static | MemberAttributes.Private }; type.Members.Add(cache); var method = new CodeMemberMethod { Attributes = MemberAttributes.Static | MemberAttributes.Public, Name = Strings.GetResourcesRecursiveMethodName, ReturnType = GetIResourceIListType() }; method.Comments.AddRange(CompilerUtil.CreateDocsComment(Strings.GetContentsRecursiveCommentSummary, Strings.GetContentsRecursiveCommentReturns)); method.Statements.Add( new CodeConditionStatement( new CodeBinaryOperatorExpression( new CodeFieldReferenceExpression(null, RecursiveLookupCacheName), CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression(null) ), new CodeMethodReturnStatement(new CodeFieldReferenceExpression(null, RecursiveLookupCacheName)))); // Create list method.Statements.Add(new CodeVariableDeclarationStatement(GetIResourceListType(), "tmp", new CodeObjectCreateExpression(GetIResourceListType()))); // Add any resources from this folder method.Statements.Add(new CodeMethodInvokeExpression(new CodeVariableReferenceExpression("tmp"), "AddRange", new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(null, Strings.GetResourcesMethodName)))); // Add any resources from subfolders foreach (var f in folder.Folders) { var name = CompilerUtil.GetSafeName(f.Name, true); // Skip if this folder hasn't been added to the type for some reason if (!CompilerUtil.IsDuplicate(name, type)) { continue; } // Add any resources from this folder method.Statements.Add(new CodeMethodInvokeExpression(new CodeVariableReferenceExpression("tmp"), "AddRange", new CodeMethodInvokeExpression( new CodeMethodReferenceExpression(new CodeSnippetExpression(name), Strings.GetResourcesRecursiveMethodName)))); } method.Statements.Add( new CodeAssignStatement(new CodeFieldReferenceExpression(null, RecursiveLookupCacheName), new CodeVariableReferenceExpression("tmp"))); method.Statements.Add( new CodeMethodReturnStatement(new CodeFieldReferenceExpression(null, RecursiveLookupCacheName))); type.Members.Add(method); }
private static void PopulateClassMembers(TypeSafeDataUnit unit, CodeTypeDeclaration container) { // Create the list type that is used to store the internal array (not used when All list is disabled) var valueListType = new CodeTypeReference(typeof(IList <>)) { TypeArguments = { unit.DataType } }; // Set up the default type for members var dataType = new CodeTypeReference(unit.DataType); // Use global references CompilerUtil.SetTypeGlobalReference(dataType); CompilerUtil.SetTypeGlobalReference(valueListType); // Expression to make the internal list (not used when All list is disabled) var arrayExpression = new CodeArrayCreateExpression(dataType); //TSLog.Log(LogCategory.Trace, $"[DataUnitCompiler] Populating {container.Name}"); foreach (var c in unit.Data) { // Can't override type if using the All property method (since can't store non-compatible types in the list) if (unit.EnableAllProperty && c.OverrideType != null) { throw new InvalidOperationException("Cannot override type when using All list."); } var name = c.PropertyName; string memberName; if ( !CompilerUtil.GetSafeNameAndVerifyNotDuplicate(name, container, out memberName, !c.OverrideRestrictedNames)) { continue; } // Create the expression to initialize this member var entryExpression = GetCreateExpression(c, c.OverrideType != null ? c.OverrideType : unit.DataType); var isObsolete = !string.IsNullOrEmpty(c.ObsoleteWarning); //TSLog.Log(LogCategory.Trace, $"[DataUnitCompiler] Member (name={memberName}, isObsolete={isObsolete})"); // Exclude obsolete members from the _all array if (unit.EnableAllProperty && !isObsolete) { // Add the initializer expression to the internal _all array arrayExpression.Initializers.Add(entryExpression); } CodeTypeMember member; // Create a field if one of the following criteria matches: // - Entry is a primitive or string. We duplicate the data (include in _all array and const field) so that const uses are faster // - All property is disabled, so we don't have an internal _all array to access // - Entry has an obsolete warning and so isn't included in the internal _all array. if (!unit.EnableAllProperty || unit.DataType.IsPrimitive || unit.DataType == typeof(string) || isObsolete) { //TSLog.Log(LogCategory.Trace, $"[DataUnitCompiler] Member handled as field"); var entryTypeReference = dataType; var attributes = MemberAttributes.Public; if (c.OverrideType != null) { entryTypeReference = new CodeTypeReference(c.OverrideType); } if (CompilerUtil.IsPrimitiveType(unit.DataType)) { attributes |= MemberAttributes.Const; } else { attributes |= MemberAttributes.Static; entryTypeReference = new CodeTypeReference("readonly global::" + entryTypeReference.BaseType); } // Duplicate data and create a field for data entry member = new CodeMemberField { Name = memberName, Type = entryTypeReference, Attributes = attributes, InitExpression = entryExpression }; if (isObsolete) { //TSLog.Log(LogCategory.Trace, $"[DataUnitCompiler] Adding obsolete warning: {c.ObsoleteWarning}"); member.CustomAttributes.Add(CompilerUtil.GetObsoleteAttribute(c.ObsoleteWarning, false)); } } else { //TSLog.Log(LogCategory.Trace, $"[DataUnitCompiler] Member handled as property"); // Otherwise create a property getter to access the internal _all array element member = new CodeMemberProperty { Name = memberName, Type = dataType, HasSet = false, HasGet = true, Attributes = MemberAttributes.Static | MemberAttributes.Public, GetStatements = { new CodeMethodReturnStatement(new CodeArrayIndexerExpression( new CodeVariableReferenceExpression("__all"), new CodePrimitiveExpression(arrayExpression.Initializers.Count - 1))) } }; } container.Members.Add(member); } if (unit.EnableAllProperty) { var all = new CodeMemberField(valueListType, "__all") { InitExpression = new CodeObjectCreateExpression( new CodeTypeReference(typeof(ReadOnlyCollection <>), CodeTypeReferenceOptions.GlobalReference) { TypeArguments = { dataType } }, arrayExpression), Attributes = MemberAttributes.Private | MemberAttributes.Static }; container.Members.Add(all); var allPublic = new CodeMemberProperty { Name = "All", Type = valueListType, GetStatements = { new CodeMethodReturnStatement(new CodeFieldReferenceExpression { FieldName = "__all" }) }, HasGet = true, Attributes = MemberAttributes.Public | MemberAttributes.Static }; container.Members.Add(allPublic); } }