|
|
|
@ -72,12 +72,38 @@ namespace Avalonia.Build.Tasks |
|
|
|
asm.MainModule.ImportReference(editorBrowsableAttribute.GetConstructors() |
|
|
|
.First(c => c.Parameters.Count == 1)); |
|
|
|
|
|
|
|
|
|
|
|
var loaderDispatcherDef = new TypeDefinition("CompiledAvaloniaXaml", "!XamlLoader", |
|
|
|
TypeAttributes.Class, asm.MainModule.TypeSystem.Object); |
|
|
|
|
|
|
|
|
|
|
|
loaderDispatcherDef.CustomAttributes.Add(new CustomAttribute(editorBrowsableCtor) |
|
|
|
{ |
|
|
|
ConstructorArguments = {new CustomAttributeArgument(editorBrowsableCtor.Parameters[0].ParameterType, 1)} |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
var loaderDispatcherMethod = new MethodDefinition("TryLoad", |
|
|
|
MethodAttributes.Static | MethodAttributes.Public, |
|
|
|
asm.MainModule.TypeSystem.Object) |
|
|
|
{ |
|
|
|
Parameters = {new ParameterDefinition(asm.MainModule.TypeSystem.String)} |
|
|
|
}; |
|
|
|
loaderDispatcherDef.Methods.Add(loaderDispatcherMethod); |
|
|
|
asm.MainModule.Types.Add(loaderDispatcherDef); |
|
|
|
|
|
|
|
var stringEquals = asm.MainModule.ImportReference(asm.MainModule.TypeSystem.String.Resolve().Methods.First( |
|
|
|
m => |
|
|
|
m.IsStatic && m.Name == "Equals" && m.Parameters.Count == 2 && |
|
|
|
m.ReturnType.FullName == "System.Boolean" |
|
|
|
&& m.Parameters[0].ParameterType.FullName == "System.String" |
|
|
|
&& m.Parameters[1].ParameterType.FullName == "System.String")); |
|
|
|
|
|
|
|
bool CompileGroup(IResourceGroup group) |
|
|
|
{ |
|
|
|
var typeDef = new TypeDefinition("CompiledAvaloniaXaml", group.Name, |
|
|
|
var typeDef = new TypeDefinition("CompiledAvaloniaXaml", "!"+ group.Name, |
|
|
|
TypeAttributes.Class, asm.MainModule.TypeSystem.Object); |
|
|
|
|
|
|
|
|
|
|
|
typeDef.CustomAttributes.Add(new CustomAttribute(editorBrowsableCtor) |
|
|
|
{ |
|
|
|
ConstructorArguments = {new CustomAttributeArgument(editorBrowsableCtor.Parameters[0].ParameterType, 1)} |
|
|
|
@ -87,6 +113,8 @@ namespace Avalonia.Build.Tasks |
|
|
|
|
|
|
|
foreach (var res in group.Resources.Where(CheckXamlName)) |
|
|
|
{ |
|
|
|
if(res.Name.Contains("DefaultTheme")) |
|
|
|
Console.WriteLine(); |
|
|
|
try |
|
|
|
{ |
|
|
|
// StreamReader is needed here to handle BOM
|
|
|
|
@ -114,15 +142,18 @@ namespace Avalonia.Build.Tasks |
|
|
|
compiler.Compile(parsed, builder, contextClass, |
|
|
|
populateName, buildName, |
|
|
|
"NamespaceInfo:" + res.Name, res.Uri); |
|
|
|
|
|
|
|
var classTypeDefinition = |
|
|
|
classType == null ? null : typeSystem.GetTypeReference(classType).Resolve(); |
|
|
|
|
|
|
|
if (classType != null) |
|
|
|
if (classTypeDefinition != null) |
|
|
|
{ |
|
|
|
var compiledPopulateMethod = typeSystem.GetTypeReference(builder).Resolve() |
|
|
|
.Methods.First(m => m.Name == populateName); |
|
|
|
var classTypeDefinition = typeSystem.GetTypeReference(classType).Resolve(); |
|
|
|
|
|
|
|
|
|
|
|
var trampoline = new MethodDefinition("!XamlIlPopulateTrampoline", |
|
|
|
|
|
|
|
|
|
|
|
const string TrampolineName = "!XamlIlPopulateTrampoline"; |
|
|
|
var trampoline = new MethodDefinition(TrampolineName, |
|
|
|
MethodAttributes.Static | MethodAttributes.Private, asm.MainModule.TypeSystem.Void); |
|
|
|
trampoline.Parameters.Add(new ParameterDefinition(classTypeDefinition)); |
|
|
|
classTypeDefinition.Methods.Add(trampoline); |
|
|
|
@ -143,6 +174,16 @@ namespace Avalonia.Build.Tasks |
|
|
|
&& i[c].OpCode == OpCodes.Call) |
|
|
|
{ |
|
|
|
var op = i[c].Operand as MethodReference; |
|
|
|
|
|
|
|
// TODO: Throw an error
|
|
|
|
// This usually happens when same XAML resource was added twice for some weird reason
|
|
|
|
// We currently support it for dual-named default theme resource
|
|
|
|
if (op != null |
|
|
|
&& op.Name == TrampolineName) |
|
|
|
{ |
|
|
|
foundXamlLoader = true; |
|
|
|
break; |
|
|
|
} |
|
|
|
if (op != null |
|
|
|
&& op.Name == "Load" |
|
|
|
&& op.Parameters.Count == 1 |
|
|
|
@ -158,9 +199,10 @@ namespace Avalonia.Build.Tasks |
|
|
|
|
|
|
|
if (!foundXamlLoader) |
|
|
|
{ |
|
|
|
var ctors = classTypeDefinition.GetConstructors().ToList(); |
|
|
|
var ctors = classTypeDefinition.GetConstructors() |
|
|
|
.Where(c => !c.IsStatic).ToList(); |
|
|
|
// We can inject xaml loader into default constructor
|
|
|
|
if (ctors.Count == 1 && ctors[0].Body.Instructions.Count(o=>o.OpCode!=OpCodes.Nop) == 3) |
|
|
|
if (ctors.Count == 1 && ctors[0].Body.Instructions.Count(o=>o.OpCode != OpCodes.Nop) == 3) |
|
|
|
{ |
|
|
|
var i = ctors[0].Body.Instructions; |
|
|
|
var retIdx = i.IndexOf(i.Last(x => x.OpCode == OpCodes.Ret)); |
|
|
|
@ -175,6 +217,39 @@ namespace Avalonia.Build.Tasks |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (buildName != null || classTypeDefinition != null) |
|
|
|
{ |
|
|
|
var compiledBuildMethod = buildName == null ? |
|
|
|
null : |
|
|
|
typeSystem.GetTypeReference(builder).Resolve() |
|
|
|
.Methods.First(m => m.Name == buildName); |
|
|
|
var parameterlessConstructor = compiledBuildMethod != null ? |
|
|
|
null : |
|
|
|
classTypeDefinition.GetConstructors().FirstOrDefault(c => |
|
|
|
c.IsPublic && !c.IsStatic && !c.HasParameters); |
|
|
|
|
|
|
|
if (compiledBuildMethod != null || parameterlessConstructor != null) |
|
|
|
{ |
|
|
|
var i = loaderDispatcherMethod.Body.Instructions; |
|
|
|
var nop = Instruction.Create(OpCodes.Nop); |
|
|
|
i.Add(Instruction.Create(OpCodes.Ldarg_0)); |
|
|
|
i.Add(Instruction.Create(OpCodes.Ldstr, res.Uri)); |
|
|
|
i.Add(Instruction.Create(OpCodes.Call, stringEquals)); |
|
|
|
i.Add(Instruction.Create(OpCodes.Brfalse, nop)); |
|
|
|
if (parameterlessConstructor != null) |
|
|
|
i.Add(Instruction.Create(OpCodes.Newobj, parameterlessConstructor)); |
|
|
|
else |
|
|
|
{ |
|
|
|
i.Add(Instruction.Create(OpCodes.Ldnull)); |
|
|
|
i.Add(Instruction.Create(OpCodes.Call, compiledBuildMethod)); |
|
|
|
} |
|
|
|
|
|
|
|
i.Add(Instruction.Create(OpCodes.Ret)); |
|
|
|
i.Add(nop); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
catch (Exception e) |
|
|
|
{ |
|
|
|
@ -191,11 +266,9 @@ namespace Avalonia.Build.Tasks |
|
|
|
} |
|
|
|
res.Remove(); |
|
|
|
} |
|
|
|
|
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (emres.Resources.Count(CheckXamlName) != 0) |
|
|
|
if (!CompileGroup(emres)) |
|
|
|
return new CompileResult(false); |
|
|
|
@ -205,7 +278,10 @@ namespace Avalonia.Build.Tasks |
|
|
|
return new CompileResult(false); |
|
|
|
avares.Save(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
loaderDispatcherMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ldnull)); |
|
|
|
loaderDispatcherMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ret)); |
|
|
|
|
|
|
|
var ms = new MemoryStream(); |
|
|
|
asm.Write(ms); |
|
|
|
return new CompileResult(true, ms.ToArray()); |
|
|
|
|