Browse Source

Support group transformations in the XAML Build Task

pull/9537/head
Max Katz 4 years ago
parent
commit
a9e904b0d2
  1. 1
      src/Avalonia.Base/Utilities/StringBuilderCache.cs
  2. 3
      src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj
  3. 2
      src/Avalonia.Build.Tasks/BuildEngineErrorCode.cs
  4. 12
      src/Avalonia.Build.Tasks/Extensions.cs
  5. 75
      src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs

1
src/Avalonia.Base/Utilities/StringBuilderCache.cs

@ -9,6 +9,7 @@ using System;
using System.Text;
namespace Avalonia.Utilities;
#nullable enable
// <summary>Provide a cached reusable instance of stringbuilder per thread.</summary>
internal static class StringBuilderCache

3
src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj

@ -55,6 +55,9 @@
<Compile Include="../Avalonia.Base/Utilities/MathUtilities.cs">
<Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
</Compile>
<Compile Include="..\Avalonia.Base\Platform\AssetLoader.cs">
<Link>Markup\AssetLoader.cs</Link>
</Compile>
<Compile Include="..\Avalonia.Base\Utilities\StringBuilderCache.cs" Link="Utilities\StringBuilderCache.cs" />
<Compile Include="..\Markup\Avalonia.Markup\Markup\Parsers\ArgumentListParser.cs">
<Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>

2
src/Avalonia.Build.Tasks/BuildEngineErrorCode.cs

@ -5,6 +5,8 @@ namespace Avalonia.Build.Tasks
InvalidXAML = 1,
DuplicateXClass = 2,
LegacyResmScheme = 3,
TransformError = 4,
EmitError = 4,
Unknown = 9999
}

12
src/Avalonia.Build.Tasks/Extensions.cs

@ -7,15 +7,19 @@ namespace Avalonia.Build.Tasks
{
static string FormatErrorCode(BuildEngineErrorCode code) => $"AVLN:{(int)code:0000}";
public static void LogError(this IBuildEngine engine, BuildEngineErrorCode code, string file, string message)
public static void LogError(this IBuildEngine engine, BuildEngineErrorCode code, string file, string message,
int lineNumber = 0, int linePosition = 0)
{
engine.LogErrorEvent(new BuildErrorEventArgs("Avalonia", FormatErrorCode(code), file ?? "", 0, 0, 0, 0, message,
engine.LogErrorEvent(new BuildErrorEventArgs("Avalonia", FormatErrorCode(code), file ?? "",
lineNumber, linePosition, lineNumber, linePosition, message,
"", "Avalonia"));
}
public static void LogWarning(this IBuildEngine engine, BuildEngineErrorCode code, string file, string message)
public static void LogWarning(this IBuildEngine engine, BuildEngineErrorCode code, string file, string message,
int lineNumber = 0, int linePosition = 0)
{
engine.LogWarningEvent(new BuildWarningEventArgs("Avalonia", FormatErrorCode(code), file ?? "", 0, 0, 0, 0, message,
engine.LogWarningEvent(new BuildWarningEventArgs("Avalonia", FormatErrorCode(code), file ?? "",
lineNumber, linePosition, lineNumber, linePosition, message,
"", "Avalonia"));
}

75
src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs

@ -233,13 +233,14 @@ namespace Avalonia.Build.Tasks
var builder = typeSystem.CreateTypeBuilder(typeDef);
var populateMethodsToTransform = new List<(MethodDefinition populateMethod, string resourceFilePath)>();
foreach (var res in group.Resources.Where(CheckXamlName).OrderBy(x=>x.FilePath.ToLowerInvariant()))
IReadOnlyCollection<XamlDocumentResource> parsedXamlDocuments = new List<XamlDocumentResource>();
foreach (var res in group.Resources.Where(CheckXamlName).OrderBy(x => x.FilePath.ToLowerInvariant()))
{
engine.LogMessage($"XAMLIL: {res.Name} -> {res.Uri}", logImportance);
try
{
engine.LogMessage($"XAMLIL: {res.Name} -> {res.Uri}", logImportance);
// StreamReader is needed here to handle BOM
var xaml = new StreamReader(new MemoryStream(res.FileContents)).ReadToEnd();
var parsed = XDocumentXamlParser.Parse(xaml);
@ -276,9 +277,9 @@ namespace Avalonia.Build.Tasks
compiler.Transform(parsed);
var populateName = classType == null ? "Populate:" + res.Name : "!XamlIlPopulate";
var buildName = classType == null ? "Build:" + res.Name : null;
var buildName = classType == null ? "Build:" + res.Name : null;
var classTypeDefinition =
classType == null ? null : typeSystem.GetTypeReference(classType).Resolve();
@ -286,11 +287,57 @@ namespace Avalonia.Build.Tasks
var populateBuilder = classTypeDefinition == null ?
builder :
typeSystem.CreateTypeBuilder(classTypeDefinition);
compiler.Compile(parsed,
contextClass,
((List<XamlDocumentResource>)parsedXamlDocuments).Add(new XamlDocumentResource(
parsed, res.Uri, res, classType,
populateBuilder,
compiler.DefinePopulateMethod(populateBuilder, parsed, populateName,
classTypeDefinition == null),
buildName == null ? null : compiler.DefineBuildMethod(builder, parsed, buildName, true),
buildName == null ? null : compiler.DefineBuildMethod(builder, parsed, buildName, true)));
}
catch (Exception e)
{
int lineNumber = 0, linePosition = 0;
if (e is XamlParseException xe)
{
lineNumber = xe.LineNumber;
linePosition = xe.LinePosition;
}
engine.LogError(BuildEngineErrorCode.TransformError, res.FilePath, e.Message, lineNumber, linePosition);
return false;
}
}
try
{
compiler.TransformGroup(parsedXamlDocuments);
}
catch (XamlDocumentParseException e)
{
engine.LogError(BuildEngineErrorCode.TransformError, e.FilePath, e.Message, e.LineNumber, e.LinePosition);
}
catch (XamlParseException e)
{
engine.LogError(BuildEngineErrorCode.TransformError, "", e.Message, e.LineNumber, e.LinePosition);
}
foreach (var document in parsedXamlDocuments)
{
var parsed = document.XamlDocument;
var res = (IResource)document.FileSource;
var classType = document.ClassType;
var populateBuilder = document.TypeBuilder;
try
{
var classTypeDefinition =
classType == null ? null : typeSystem.GetTypeReference(classType).Resolve();
compiler.Compile(parsed,
contextClass,
document.PopulateMethod,
document.BuildMethod,
builder.DefineSubType(compilerConfig.WellKnownTypes.Object, "NamespaceInfo:" + res.Name,
true),
(closureName, closureBaseType) =>
@ -417,12 +464,12 @@ namespace Avalonia.Build.Tasks
}
if (buildName != null || classTypeDefinition != null)
if (document.BuildMethod != null || classTypeDefinition != null)
{
var compiledBuildMethod = buildName == null ?
var compiledBuildMethod = document.BuildMethod == null ?
null :
typeSystem.GetTypeReference(builder).Resolve()
.Methods.First(m => m.Name == buildName);
.Methods.First(m => m.Name == document.BuildMethod.Name);
var parameterlessConstructor = compiledBuildMethod != null ?
null :
classTypeDefinition.GetConstructors().FirstOrDefault(c =>
@ -459,9 +506,7 @@ namespace Avalonia.Build.Tasks
lineNumber = xe.LineNumber;
linePosition = xe.LinePosition;
}
engine.LogErrorEvent(new BuildErrorEventArgs("Avalonia", "XAMLIL", res.FilePath,
lineNumber, linePosition, lineNumber, linePosition,
e.Message, "", "Avalonia"));
engine.LogError(BuildEngineErrorCode.EmitError, res.FilePath, e.Message, lineNumber, linePosition);
return false;
}
res.Remove();

Loading…
Cancel
Save