public void InitializePropertyTypeNode(PropertyTypeNode propertyType) { foreach (var item in items) { item.Initialize(propertyType); } }
private static Type GetPropertyWrapperTypeFor( PropertyTypeNode containerType, PropertyTypeNode propertyType) { var propertyWrapperTypeString = GetPropertyWrapperTypeString(containerType, propertyType); Type wrapperType; if (!PropertyWrapperTypeFromName.TryGetValue(propertyWrapperTypeString, out wrapperType)) { return(null); } if (wrapperType == null) { return(null); } if (PropertyTypeNode.IsEnumerableType(propertyType.Tag)) { return(wrapperType.MakeGenericType( containerType.NativeType, typeof(List <>).MakeGenericType(propertyType.NativeType), propertyType.NativeType)); } return(wrapperType.MakeGenericType(containerType.NativeType, propertyType.NativeType)); }
public override void OnPropertyContainerGenerationCompleted(PropertyTypeNode container) { TypeDefinition type = null; if (!_typeDefinitionPerPropertyNodeMap.TryGetValue(container, out type)) { // @TODO error return; } if (GeneratedContainerTypeDefinition?.Module == null) { return; } try { GeneratedContainerTypeDefinition.Module.Write(); } catch (Exception e) { Debug.Log(e.ToString()); throw; } }
public override void OnGenerateConstructorForContainer(PropertyTypeNode container) { TypeDefinition type; if (!_typeDefinitionPerPropertyNodeMap.TryGetValue(container, out type)) { // @TODO error return; } try { MethodDefinition constructor = null; // Check if there is one already var constructors = type.GetConstructors(); if (constructors != null && constructors.Count() == 0) { constructor = constructors.FirstOrDefault(c => !c.HasParameters); } bool constructorCreated = constructor == null; if (constructor == null) { const MethodAttributes attributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName; constructor = new MethodDefinition( ".ctor", attributes, type.Module.TypeSystem.Void); } constructor.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0)); var baseConstructor = type.BaseType.Resolve().GetConstructors().FirstOrDefault(c => !c.HasParameters); if (baseConstructor != null) { constructor.Body.Instructions.Add(Instruction.Create(OpCodes.Call, baseConstructor)); } // TODO add static property initialisers // TODO add user hooks GenerateFragments(ConstructorInitializerFragments, constructor.Body.GetILProcessor()); if (constructorCreated) { constructor.Body.Instructions.Add(Instruction.Create(OpCodes.Ret)); type.Methods.Add(constructor); } } catch (Exception e) { Debug.Log(e.ToString()); throw; } }
public CheckPropertyGateResult Check(PropertyTypeNode propertyType, PropertyValueNode propertyValue) { if (propertyType.Extensions.TryGet <ReadOnlyAttribute, bool>(out var isReadOnly) && isReadOnly) { return(new CheckPropertyGateResult.Error()); } return(CheckPropertyGateResult.Success.Instance); }
public override void OnGenerateStaticConstructorForContainer(PropertyTypeNode container) { TypeDefinition type = null; if (!_typeDefinitionPerPropertyNodeMap.TryGetValue(container, out type)) { // @TODO error return; } try { // Check if there is one already MethodDefinition staticConstructor = type.GetMethods().FirstOrDefault(c => c.Name == ".cctor"); bool constructorCreated = staticConstructor == null; if (staticConstructor == null) { const MethodAttributes attributes = MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName; staticConstructor = new MethodDefinition(".cctor", attributes, type.Module.TypeSystem.Void); } var ilProcessor = staticConstructor.Body.GetILProcessor(); staticConstructor.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0)); StaticConstructorStagePrePostFragments stageFragments; if (StaticConstructorInitializerFragments.TryGetValue( ConstructorStage.PropertyInitializationStage, out stageFragments)) { GenerateFragments(stageFragments.InStageFragments, ilProcessor); GenerateFragments(stageFragments.PostStageFragments, ilProcessor); } if (!constructorCreated) { return; } staticConstructor.Body.Instructions.Add(Instruction.Create(OpCodes.Ret)); type.Methods.Add(staticConstructor); } catch (Exception e) { Debug.Log(e.ToString()); throw; } }
public override void OnGeneratePropertyBagForContainer(PropertyTypeNode container) { TypeDefinition type = null; if (!_typeDefinitionPerPropertyNodeMap.TryGetValue(container, out type)) { // @TODO error return; } GeneratePropertyBag(type.Module, type, PropertyBagItemTypes); }
public override void OnGenerateUserHooksForContainer(PropertyTypeNode container) { if (container.UserHooks.HasFlag(UserHookFlags.OnPropertyBagConstructed)) { TypeDefinition type = null; if (!_typeDefinitionPerPropertyNodeMap.TryGetValue(container, out type)) { // @TODO error return; } } }
private static string GetPropertyWrapperTypeString( PropertyTypeNode containerType, PropertyTypeNode propertyType) { var propertyWrapperTypeStringPrefix = string.Empty; if (containerType.Tag.HasFlag(PropertyTypeNode.TypeTag.Struct)) { propertyWrapperTypeStringPrefix = "Struct"; } switch (propertyType.Tag) { case PropertyTypeNode.TypeTag.Struct: return($"{propertyWrapperTypeStringPrefix}MutableContainerProperty"); case PropertyTypeNode.TypeTag.Class: return($"{propertyWrapperTypeStringPrefix}ContainerProperty"); case PropertyTypeNode.TypeTag.Enum: return($"{propertyWrapperTypeStringPrefix}EnumProperty"); case PropertyTypeNode.TypeTag.List: { switch (propertyType.Of.Tag) { case PropertyTypeNode.TypeTag.Primitive: return($"{propertyWrapperTypeStringPrefix}ListProperty"); case PropertyTypeNode.TypeTag.Struct: return($"{propertyWrapperTypeStringPrefix}MutableContainerListProperty"); case PropertyTypeNode.TypeTag.Class: return($"{propertyWrapperTypeStringPrefix}ContainerListProperty"); case PropertyTypeNode.TypeTag.Enum: return($"{propertyWrapperTypeStringPrefix}EnumListProperty"); case PropertyTypeNode.TypeTag.Unknown: case PropertyTypeNode.TypeTag.List: default: throw new Exception($"Invalid property tag for list property name {propertyType.PropertyName}"); } } case PropertyTypeNode.TypeTag.Primitive: return($"{propertyWrapperTypeStringPrefix}Property"); default: break; } return($"{propertyWrapperTypeStringPrefix}Property"); }
public override void OnGenerateNestedContainer(PropertyTypeNode container, PropertyTypeNode nestedContainer) { TypeDefinition type = null; if (!_typeDefinitionPerPropertyNodeMap.TryGetValue(container, out type)) { // @TODO error return; } var cecilBackend = new CecilGenerationBackend(); cecilBackend.GenerateContainer(nestedContainer); type.NestedTypes.Add(cecilBackend.GeneratedContainerTypeDefinition); }
public override void OnPropertyContainerGenerationStarted(PropertyTypeNode container) { var assembly = GetAssembly(container.NativeType.Assembly.Location); var module = assembly.Modules.FirstOrDefault( m => m.FileName == container.NativeType.Module.FullyQualifiedName); if (module == null) { // It doesn't seem to exist // TODO fallback return; } var attributes = TypeAttributes.Public | TypeAttributes.Class; if (container.IsAbstractClass) { attributes |= TypeAttributes.Abstract; } if (container.Tag == PropertyTypeNode.TypeTag.Struct) { attributes |= TypeAttributes.SequentialLayout; } var containerType = new TypeDefinition( container.TypePath.Namespace, GetPropertyContainerClassNameForType(module, container.NativeType, container.TypeName), attributes, GetPropertyContainerTypeReference() ); GenerateVersionStorage(module, containerType); module.Types.Add(containerType); GeneratedContainerTypeDefinition = containerType; _typeDefinitionPerPropertyNodeMap[container] = containerType; }
public override void OnPropertyGenerationStarted(PropertyTypeNode container, PropertyTypeNode property) { TypeDefinition type; if (!_typeDefinitionPerPropertyNodeMap.TryGetValue(container, out type)) { // @TODO error return; } // Backing field (should be optional) var backingField = new FieldDefinition( BackingFieldFromPropertyName(property.PropertyName), FieldAttributes.Private, type.Module.ImportReference(property.NativeType) ); type.Fields.Add(backingField); ConstructorInitializerFragments.Add( new CecilGenerationFragmentContext() { Module = type.Module, Type = type, Fragment = ilProcessor => { ilProcessor.Append(ilProcessor.Create(OpCodes.Ldarg_0)); ilProcessor.Append(ilProcessor.Create(OpCodes.Newobj, type.Module.ImportReference(property.NativeType))); ilProcessor.Append(ilProcessor.Create(OpCodes.Stfld, backingField)); } }); // Property wrapper static field var propertyWrapperType = type.Module.ImportReference(GetPropertyWrapperTypeFor(container, property)); var propertyWrapperField = new FieldDefinition( PropertyWrapperFieldName(property.PropertyName), FieldAttributes.Private | FieldAttributes.Static, propertyWrapperType ); type.Fields.Add(propertyWrapperField); PropertyBagItemTypes.Add(propertyWrapperField); // TODO add a post processing field initialization ConstructorInitializerFragments.Add( new CecilGenerationFragmentContext() { Module = type.Module, Type = type, Fragment = ilProcessor => { ilProcessor.Append(ilProcessor.Create(OpCodes.Ldarg_0)); // #arg 0 ilProcessor.Append(ilProcessor.Create(OpCodes.Ldstr, property.PropertyName)); // #arg 1 (getter) // #arg 2 (setter) // #arg 2 (reference) } }); /* * FloatListProperty = * new ListProperty<TestContainer, List<float>, float>(nameof(FloatList), * c => c._floatList, * null, * null); */ // Accessor method var getPropertyMethod = new MethodDefinition( "get_" + property.PropertyName, MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, type.Module.ImportReference(property.NativeType) ); getPropertyMethod.Body.Variables.Add( new VariableDefinition(type.Module.ImportReference(typeof(PropertyBag)))); // get { return FloatListProperty.GetValue(this); } var il = getPropertyMethod.Body.GetILProcessor(); il.Append(il.Create(OpCodes.Ldarg_0)); il.Append(il.Create(OpCodes.Ldfld, propertyWrapperField)); il.Append(il.Create(OpCodes.Ldarg_0)); var getValueDelegateRef = propertyWrapperType.Resolve().Methods.FirstOrDefault(m => m.Name == "GetValue"); il.Append(il.Create(OpCodes.Callvirt, type.Module.ImportReference(getValueDelegateRef))); il.Append(il.Create(OpCodes.Ret)); type.Methods.Add(getPropertyMethod); // Actual property // public List<float> FloatList var propertyAccessorForProperty = new PropertyDefinition( property.PropertyName, PropertyAttributes.None, type.Module.ImportReference(property.NativeType) ) { HasThis = true, GetMethod = getPropertyMethod, }; type.Properties.Add(propertyAccessorForProperty); }
private List <PropertyTypeNode> ExtractPropertyNodesFrom( SemanticModel model, SemanticInformationCollector collector) { if (model == null) { throw new Exception("Invalid semantic model for property node introspection (null)."); } var nodes = new List <PropertyTypeNode>(); var typePerFullTypename = new Dictionary <string, PropertyTypeNode>(); // Expect a top -> bottom tree traversal, so it means that the // list contains types declared in order. foreach (var type in collector.ContainerTypes) { var tag = PropertyTypeNode.TypeTag.Class; if (type is StructDeclarationSyntax) { tag = PropertyTypeNode.TypeTag.Struct; } var symbol = model.GetDeclaredSymbol(type); var typePath = new ContainerTypeTreePath { Namespace = NamespaceForType(type) }; var fullTypeNamePath = symbol.ToString().Replace(typePath.Namespace, "").Trim('.').Split('.'); fullTypeNamePath = fullTypeNamePath.Take(fullTypeNamePath.Length - 1).ToArray(); foreach (var pathPart in fullTypeNamePath) { typePath.TypePath.Push(pathPart); } var node = new PropertyTypeNode { Tag = tag, TypePath = typePath, TypeName = symbol.Name, IsAbstractClass = symbol.IsAbstract, OverrideDefaultBaseClass = symbol.AllInterfaces.Any(i => i.Name == typeof(IPropertyContainer).Name) ? string.Empty : symbol.BaseType.Name }; var fieldCollector = new FieldCollector(model); fieldCollector.Visit(type); foreach (var field in fieldCollector.Properties) { var genericProperty = new RoslynProperty(field.Symbol); if (!genericProperty.IsValid) { continue; } // Parse var property = new PropertyTypeNode() { PropertyName = PropertyNameFromFieldName(field.Symbol.Name), Tag = genericProperty.TypeTag, TypeName = genericProperty.TypeID, Of = genericProperty.ListOf, IsReadonly = genericProperty.IsReadonly, IsPublicProperty = field.SyntaxNode.Modifiers.Any(SyntaxKind.PublicKeyword) }; // Extract info about backing fields var initializer = field.SyntaxNode.Declaration.Variables.First().Initializer; if (initializer?.Value is ExpressionSyntax) { /* * // @TODO * var initializerExpression = initializer.Value; * * // @TODO * var symbolNames = model.LookupSymbols(initializerExpression.SpanStart).Select(s => s.Name).ToList(); */ // property.DefaultValue = property.PropertyBackingAccessor = string.Empty; } if (!string.IsNullOrEmpty(property.PropertyName)) { node.Properties.Add(property); } } var containingSymbolFullName = symbol.ContainingSymbol.ToDisplayString(); // symbol.ContainingSymbol.Name if (typePerFullTypename.ContainsKey(containingSymbolFullName)) { // This is a nested node var parent = typePerFullTypename[containingSymbolFullName]; node.TypePath = new ContainerTypeTreePath(parent.TypePath); node.TypePath.TypePath.Push(parent.TypeName); parent.NestedContainers.Add(node); } else { // This is a new node typePerFullTypename[node.FullTypeName] = node; nodes.Add(node); } } return(nodes); }