Skip to content

Commit

Permalink
Adding extension points to property directive resolver.
Browse files Browse the repository at this point in the history
  • Loading branch information
Milan Mikuš committed Oct 12, 2023
1 parent bcd839a commit a8aea52
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 49 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using DotVVM.Framework.Compilation.Parser.Binding.Parser;
using System.Collections.Generic;
using System.Reflection;

namespace DotVVM.Framework.Compilation.ControlTree
Expand All @@ -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<IAbstractDirectiveAttributeReference> Attributes { get; }
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,48 +16,6 @@

namespace DotVVM.Framework.Compilation.Directives
{
public class ResolvedBaseTypeDirectiveCompiler : BaseTypeDirectiveCompiler
{
private static readonly Lazy<ModuleBuilder> DynamicMarkupControlAssembly = new(CreateDynamicMarkupControlAssembly);

public ResolvedBaseTypeDirectiveCompiler(IReadOnlyDictionary<string, IReadOnlyList<DothtmlDirectiveNode>> directiveNodesByName, IAbstractTreeBuilder treeBuilder, string fileName, ImmutableList<NamespaceImport> 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<IAbstractBaseTypeDirective, ITypeDescriptor>
{
private readonly string fileName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ protected override DefaultDirectiveResolver CreateDefaultResolver(DirectiveDicti
=> new(directivesByName, treeBuilder);

protected override PropertyDeclarationDirectiveCompiler CreatePropertyDirectiveCompiler(DirectiveDictionary directivesByName, ImmutableList<NamespaceImport> imports, ITypeDescriptor baseType)
=> new(directivesByName, treeBuilder, baseType, imports);
=> new ResolvedPropertyDeclarationDirectiveCompiler (directivesByName, treeBuilder, baseType, imports);

protected override ViewModuleDirectiveCompiler CreateViewModuleDirectiveCompiler(DirectiveDictionary directivesByName, ITypeDescriptor baseType)
=> new(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

namespace DotVVM.Framework.Compilation.Directives
{
public class PropertyDeclarationDirectiveCompiler : DirectiveCompiler<IAbstractPropertyDeclarationDirective, ImmutableList<DotvvmProperty>>
public abstract class PropertyDeclarationDirectiveCompiler : DirectiveCompiler<IAbstractPropertyDeclarationDirective, ImmutableList<DotvvmProperty>>
{
private readonly ITypeDescriptor controlWrapperType;
private readonly ImmutableList<NamespaceImport> imports;
Expand Down Expand Up @@ -98,15 +98,32 @@ protected override ImmutableList<DotvvmProperty> CreateArtefact(IReadOnlyList<IA
}

return directives
.Where(d => 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<string, IReadOnlyList<DothtmlDirectiveNode>> directiveNodesByName,
IAbstractTreeBuilder treeBuilder, ITypeDescriptor controlWrapperType,
ImmutableList<NamespaceImport> 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,
Expand Down
Original file line number Diff line number Diff line change
@@ -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<ModuleBuilder> DynamicMarkupControlAssembly = new(CreateDynamicMarkupControlAssembly);

public ResolvedBaseTypeDirectiveCompiler(IReadOnlyDictionary<string, IReadOnlyList<DothtmlDirectiveNode>> directiveNodesByName, IAbstractTreeBuilder treeBuilder, string fileName, ImmutableList<NamespaceImport> 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;
}
}

}

0 comments on commit a8aea52

Please sign in to comment.