From a8aea523920408376833532d9dd7c7c28c98aff2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milan=20Miku=C5=A1?= Date: Tue, 15 Aug 2023 18:45:36 +0200 Subject: [PATCH] Adding extension points to property directive resolver. --- .../IAbstractPropertyDeclarationDirective.cs | 3 ++ .../Directives/BaseTypeDirectiveCompiler.cs | 42 --------------- .../MarkupDirectiveCompilerPipeline.cs | 2 +- .../PropertyDeclarationDirectiveCompiler.cs | 29 +++++++--- .../ResolvedBaseTypeDirectiveCompiler.cs | 54 +++++++++++++++++++ 5 files changed, 81 insertions(+), 49 deletions(-) create mode 100644 src/Framework/Framework/Compilation/Directives/ResolvedBaseTypeDirectiveCompiler.cs diff --git a/src/Framework/Framework/Compilation/ControlTree/IAbstractPropertyDeclarationDirective.cs b/src/Framework/Framework/Compilation/ControlTree/IAbstractPropertyDeclarationDirective.cs index 967c6bdf0d..0cc86690db 100644 --- a/src/Framework/Framework/Compilation/ControlTree/IAbstractPropertyDeclarationDirective.cs +++ b/src/Framework/Framework/Compilation/ControlTree/IAbstractPropertyDeclarationDirective.cs @@ -1,4 +1,5 @@ using DotVVM.Framework.Compilation.Parser.Binding.Parser; +using System.Collections.Generic; using System.Reflection; namespace DotVVM.Framework.Compilation.ControlTree @@ -13,9 +14,11 @@ public interface IAbstractPropertyDeclarationDirective : IAbstractDirective, ICu { SimpleNameBindingParserNode NameSyntax { get; } TypeReferenceBindingParserNode PropertyTypeSyntax { get; } + BindingParserNode? InitializerSyntax { get; } ITypeDescriptor? PropertyType { get; } ITypeDescriptor? DeclaringType { get; set; } object? InitialValue { get; } + IList Attributes { get; } } } diff --git a/src/Framework/Framework/Compilation/Directives/BaseTypeDirectiveCompiler.cs b/src/Framework/Framework/Compilation/Directives/BaseTypeDirectiveCompiler.cs index de77691332..39a72c8aa4 100644 --- a/src/Framework/Framework/Compilation/Directives/BaseTypeDirectiveCompiler.cs +++ b/src/Framework/Framework/Compilation/Directives/BaseTypeDirectiveCompiler.cs @@ -16,48 +16,6 @@ namespace DotVVM.Framework.Compilation.Directives { - public class ResolvedBaseTypeDirectiveCompiler : BaseTypeDirectiveCompiler - { - private static readonly Lazy DynamicMarkupControlAssembly = new(CreateDynamicMarkupControlAssembly); - - public ResolvedBaseTypeDirectiveCompiler(IReadOnlyDictionary> directiveNodesByName, IAbstractTreeBuilder treeBuilder, string fileName, ImmutableList imports) - : base(directiveNodesByName, treeBuilder, fileName, imports) - { - } - - protected override ITypeDescriptor? GetOrCreateDynamicType(ITypeDescriptor baseType, string typeName) - { - if (DynamicMarkupControlAssembly.Value.GetType(typeName) is { } type) - { - return new ResolvedTypeDescriptor(type); - } - - var declaringTypeBuilder = - DynamicMarkupControlAssembly.Value.DefineType(typeName, TypeAttributes.Public, ResolvedTypeDescriptor.ToSystemType(baseType)); - var createdTypeInfo = declaringTypeBuilder.CreateTypeInfo()?.AsType(); - - return createdTypeInfo is not null - ? new ResolvedTypeDescriptor(createdTypeInfo) - : null; - } - - private static ModuleBuilder CreateDynamicMarkupControlAssembly() - { - var newDynamicAssemblyName = $"DotvvmMarkupControlDynamicAssembly-{Guid.NewGuid()}"; - var assemblyName = new AssemblyName(newDynamicAssemblyName); - var assemblyBuilder = - AssemblyBuilder.DefineDynamicAssembly( - assemblyName, - AssemblyBuilderAccess.Run); - - // For a single-module assembly, the module name is usually - // the assembly name plus an extension. - var mb = - assemblyBuilder.DefineDynamicModule(newDynamicAssemblyName); - return mb; - } - } - public abstract class BaseTypeDirectiveCompiler : DirectiveCompiler { private readonly string fileName; diff --git a/src/Framework/Framework/Compilation/Directives/MarkupDirectiveCompilerPipeline.cs b/src/Framework/Framework/Compilation/Directives/MarkupDirectiveCompilerPipeline.cs index 8deb3a263e..3c95e80470 100644 --- a/src/Framework/Framework/Compilation/Directives/MarkupDirectiveCompilerPipeline.cs +++ b/src/Framework/Framework/Compilation/Directives/MarkupDirectiveCompilerPipeline.cs @@ -24,7 +24,7 @@ protected override DefaultDirectiveResolver CreateDefaultResolver(DirectiveDicti => new(directivesByName, treeBuilder); protected override PropertyDeclarationDirectiveCompiler CreatePropertyDirectiveCompiler(DirectiveDictionary directivesByName, ImmutableList imports, ITypeDescriptor baseType) - => new(directivesByName, treeBuilder, baseType, imports); + => new ResolvedPropertyDeclarationDirectiveCompiler (directivesByName, treeBuilder, baseType, imports); protected override ViewModuleDirectiveCompiler CreateViewModuleDirectiveCompiler(DirectiveDictionary directivesByName, ITypeDescriptor baseType) => new( diff --git a/src/Framework/Framework/Compilation/Directives/PropertyDeclarationDirectiveCompiler.cs b/src/Framework/Framework/Compilation/Directives/PropertyDeclarationDirectiveCompiler.cs index 4f7e3777e7..86bcbbd304 100644 --- a/src/Framework/Framework/Compilation/Directives/PropertyDeclarationDirectiveCompiler.cs +++ b/src/Framework/Framework/Compilation/Directives/PropertyDeclarationDirectiveCompiler.cs @@ -13,7 +13,7 @@ namespace DotVVM.Framework.Compilation.Directives { - public class PropertyDeclarationDirectiveCompiler : DirectiveCompiler> + public abstract class PropertyDeclarationDirectiveCompiler : DirectiveCompiler> { private readonly ITypeDescriptor controlWrapperType; private readonly ImmutableList imports; @@ -98,15 +98,32 @@ protected override ImmutableList CreateArtefact(IReadOnlyList d.PropertyType is ResolvedTypeDescriptor { Type: not null }) - .Select(d => TryCreateDotvvmPropertyFromDirective(d)) + .Where(HasPropertyType) + .Select(TryCreateDotvvmPropertyFromDirective) .ToImmutableList(); } - protected virtual DotvvmProperty TryCreateDotvvmPropertyFromDirective(IAbstractPropertyDeclarationDirective propertyDeclarationDirective) + protected abstract bool HasPropertyType(IAbstractPropertyDeclarationDirective directive); + protected abstract DotvvmProperty TryCreateDotvvmPropertyFromDirective(IAbstractPropertyDeclarationDirective propertyDeclarationDirective); + } + + public class ResolvedPropertyDeclarationDirectiveCompiler : PropertyDeclarationDirectiveCompiler + { + public ResolvedPropertyDeclarationDirectiveCompiler( + IReadOnlyDictionary> directiveNodesByName, + IAbstractTreeBuilder treeBuilder, ITypeDescriptor controlWrapperType, + ImmutableList imports) + : base(directiveNodesByName, treeBuilder, controlWrapperType, imports) + { + } + + protected override bool HasPropertyType(IAbstractPropertyDeclarationDirective directive) + => directive.PropertyType is ResolvedTypeDescriptor { Type: not null }; + + protected override DotvvmProperty TryCreateDotvvmPropertyFromDirective(IAbstractPropertyDeclarationDirective propertyDeclarationDirective) { - if(propertyDeclarationDirective.PropertyType is not ResolvedTypeDescriptor { Type: not null } propertyType) { throw new ArgumentException("propertyDeclarationDirective.PropertyType must be of type ResolvedTypeDescriptor and have non null type."); } - if(propertyDeclarationDirective.DeclaringType is not ResolvedTypeDescriptor { Type: not null } declaringType) { throw new ArgumentException("propertyDeclarationDirective.DeclaringType must be of type ResolvedTypeDescriptor and have non null type."); } + if (propertyDeclarationDirective.PropertyType is not ResolvedTypeDescriptor { Type: not null } propertyType) { throw new ArgumentException("propertyDeclarationDirective.PropertyType must be of type ResolvedTypeDescriptor and have non null type."); } + if (propertyDeclarationDirective.DeclaringType is not ResolvedTypeDescriptor { Type: not null } declaringType) { throw new ArgumentException("propertyDeclarationDirective.DeclaringType must be of type ResolvedTypeDescriptor and have non null type."); } return DotvvmProperty.Register( propertyDeclarationDirective.NameSyntax.Name, diff --git a/src/Framework/Framework/Compilation/Directives/ResolvedBaseTypeDirectiveCompiler.cs b/src/Framework/Framework/Compilation/Directives/ResolvedBaseTypeDirectiveCompiler.cs new file mode 100644 index 0000000000..7249ea8f6f --- /dev/null +++ b/src/Framework/Framework/Compilation/Directives/ResolvedBaseTypeDirectiveCompiler.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using DotVVM.Framework.Compilation.Parser.Dothtml.Parser; +using DotVVM.Framework.Compilation.ControlTree; +using DotVVM.Framework.Compilation.ControlTree.Resolved; +using System.Reflection; +using System.Reflection.Emit; +using System.Collections.Immutable; + +namespace DotVVM.Framework.Compilation.Directives +{ + public class ResolvedBaseTypeDirectiveCompiler : BaseTypeDirectiveCompiler + { + private static readonly Lazy DynamicMarkupControlAssembly = new(CreateDynamicMarkupControlAssembly); + + public ResolvedBaseTypeDirectiveCompiler(IReadOnlyDictionary> directiveNodesByName, IAbstractTreeBuilder treeBuilder, string fileName, ImmutableList imports) + : base(directiveNodesByName, treeBuilder, fileName, imports) + { + } + + protected override ITypeDescriptor? GetOrCreateDynamicType(ITypeDescriptor baseType, string typeName) + { + if (DynamicMarkupControlAssembly.Value.GetType(typeName) is { } type) + { + return new ResolvedTypeDescriptor(type); + } + + var declaringTypeBuilder = + DynamicMarkupControlAssembly.Value.DefineType(typeName, TypeAttributes.Public, ResolvedTypeDescriptor.ToSystemType(baseType)); + var createdTypeInfo = declaringTypeBuilder.CreateTypeInfo()?.AsType(); + + return createdTypeInfo is not null + ? new ResolvedTypeDescriptor(createdTypeInfo) + : null; + } + + private static ModuleBuilder CreateDynamicMarkupControlAssembly() + { + var newDynamicAssemblyName = $"DotvvmMarkupControlDynamicAssembly-{Guid.NewGuid()}"; + var assemblyName = new AssemblyName(newDynamicAssemblyName); + var assemblyBuilder = + AssemblyBuilder.DefineDynamicAssembly( + assemblyName, + AssemblyBuilderAccess.Run); + + // For a single-module assembly, the module name is usually + // the assembly name plus an extension. + var mb = + assemblyBuilder.DefineDynamicModule(newDynamicAssemblyName); + return mb; + } + } + +}