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;
            }
        }
Beispiel #5
0
        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);
        }
Beispiel #13
0
        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);
        }