mirror of
https://github.com/ZuneDev/ZuneUIXTools.git
synced 2026-07-27 13:11:59 -07:00
Add inline XML to assembler and disassembler
This commit is contained in:
@@ -209,17 +209,28 @@ internal class AsmMarkupLoader
|
|||||||
object constantValue;
|
object constantValue;
|
||||||
var constantTypeSchema = ResolveTypeFromQualifiedName(constant.TypeName);
|
var constantTypeSchema = ResolveTypeFromQualifiedName(constant.TypeName);
|
||||||
|
|
||||||
if (constantTypeSchema.SupportsTypeConversion(stringTypeSchema))
|
if (constant is EncodedConstantDirective encodedConstant)
|
||||||
{
|
{
|
||||||
var parseResult = constantTypeSchema.TypeConverter(constant.Content, stringTypeSchema, out constantValue);
|
var parseResult = constantTypeSchema.TypeConverter(encodedConstant.Content, stringTypeSchema, out constantValue);
|
||||||
if (parseResult.Failed)
|
if (parseResult.Failed)
|
||||||
{
|
{
|
||||||
ReportError($"Failed to create an instance of '{constant.TypeName}' from '{constant.Content}'", constant);
|
ReportError($"Failed to create an instance of '{constant.TypeName}' from '{encodedConstant.Content}'", constant);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
var xmlElem = System.Xml.Linq.XElement.Parse(constant.Constructor);
|
||||||
|
|
||||||
|
constantValue = constantTypeSchema.ConstructDefault();
|
||||||
|
|
||||||
|
foreach (var attr in xmlElem.Attributes())
|
||||||
|
{
|
||||||
|
var propName = attr.Name.LocalName;
|
||||||
|
var prop = constantTypeSchema.FindProperty(propName);
|
||||||
|
prop.SetValue(ref constantValue, attr.Value);
|
||||||
|
}
|
||||||
|
|
||||||
ReportError($"'{constant.TypeName}' cannot be constructed from a string, and UIXA does not yet support XML construction.", constant);
|
ReportError($"'{constant.TypeName}' cannot be constructed from a string, and UIXA does not yet support XML construction.", constant);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using Microsoft.Iris.Markup;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace Microsoft.Iris.Asm;
|
namespace Microsoft.Iris.Asm;
|
||||||
|
|
||||||
@@ -148,7 +149,7 @@ public class Disassembler
|
|||||||
var persistedConstant = persistedList[c];
|
var persistedConstant = persistedList[c];
|
||||||
var typeSchema = persistedConstant.Type;
|
var typeSchema = persistedConstant.Type;
|
||||||
|
|
||||||
constants.Add((c, typeSchema, persistedConstant));
|
constants.Add((c, typeSchema, persistedConstant.Data));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -173,15 +174,54 @@ public class Disassembler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var stringTypeSchema = UIXTypes.MapIDToType(UIXTypeID.String);
|
||||||
|
|
||||||
foreach (var (c, typeSchema, constantValue) in constants)
|
foreach (var (c, typeSchema, constantValue) in constants)
|
||||||
{
|
{
|
||||||
string encodedValue = constantValue is IStringEncodable encodable
|
var constantName = $"const{c:D}";
|
||||||
? encodable.EncodeString()
|
|
||||||
: constantValue.ToString();
|
|
||||||
|
|
||||||
QualifiedTypeName qualifiedTypeName = GetQualifiedName(typeSchema);
|
QualifiedTypeName qualifiedTypeName = GetQualifiedName(typeSchema);
|
||||||
|
|
||||||
yield return new ConstantDirective($"const{c:D}", qualifiedTypeName, encodedValue);
|
if (constantValue is IStringEncodable encodable)
|
||||||
|
{
|
||||||
|
var encodedValue = encodable.EncodeString();
|
||||||
|
yield return new EncodedConstantDirective(constantName, qualifiedTypeName, encodedValue);
|
||||||
|
}
|
||||||
|
else if (typeSchema.SupportsTypeConversion(stringTypeSchema))
|
||||||
|
{
|
||||||
|
var encodedValue = constantValue.ToString();
|
||||||
|
yield return new EncodedConstantDirective(constantName, qualifiedTypeName, encodedValue);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
XName constElemName = qualifiedTypeName.NamespacePrefix is null
|
||||||
|
? qualifiedTypeName.TypeName
|
||||||
|
: XName.Get(qualifiedTypeName.TypeName, qualifiedTypeName.NamespacePrefix);
|
||||||
|
XElement constElem = new(constElemName);
|
||||||
|
|
||||||
|
var defaultConstantValue = typeSchema.ConstructDefault();
|
||||||
|
|
||||||
|
foreach (var prop in typeSchema.Properties)
|
||||||
|
{
|
||||||
|
// No need to serialize properties that can't be set
|
||||||
|
if (!prop.CanWrite)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var defaultPropValue = prop.GetValue(defaultConstantValue);
|
||||||
|
var propValue = prop.GetValue(constantValue);
|
||||||
|
|
||||||
|
var encodedPropValue = EncodeSimpleConstant(propValue);
|
||||||
|
var encodedDefaultPropValue = EncodeSimpleConstant(defaultPropValue);
|
||||||
|
|
||||||
|
// No need to serialize properties that are at their default value
|
||||||
|
if (encodedPropValue == encodedDefaultPropValue)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
constElem.SetAttributeValue(prop.Name, encodedPropValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
var constructor = constElem.ToString(SaveOptions.DisableFormatting);
|
||||||
|
yield return new ConstantDirective(constantName, qualifiedTypeName, constructor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,4 +312,11 @@ public class Disassembler
|
|||||||
labels = _offsetLabelMap[offset] = new(1);
|
labels = _offsetLabelMap[offset] = new(1);
|
||||||
labels.Add(new(labelName));
|
labels.Add(new(labelName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string EncodeSimpleConstant(object value)
|
||||||
|
{
|
||||||
|
return value is IStringEncodable encodable
|
||||||
|
? encodable.EncodeString()
|
||||||
|
: value.ToString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,31 +55,54 @@ partial class Lexer
|
|||||||
|
|
||||||
input = Parse.Char('=').Token()(input).Remainder;
|
input = Parse.Char('=').Token()(input).Remainder;
|
||||||
|
|
||||||
var typeNameResult = QualifiedTypeName.Token()(input);
|
// Types that can't be encoded as simple strings, such as FlowLayout,
|
||||||
input = typeNameResult.Remainder;
|
// are defined inline using XML elements.
|
||||||
if (!typeNameResult.WasSuccessful)
|
bool isInlineXml = Parse.Char('<')(input).WasSuccessful;
|
||||||
return Result.Failure<IDirective>(input, "Invalid constant directive", ["Expected qualified name of type to construct"]);
|
if (isInlineXml)
|
||||||
|
|
||||||
var openBracketResult = Parse.Char('(').Token()(input);
|
|
||||||
input = openBracketResult.Remainder;
|
|
||||||
if (!openBracketResult.WasSuccessful)
|
|
||||||
return Result.Failure<IDirective>(input, "Invalid constant directive", ["Expected '('"]);
|
|
||||||
|
|
||||||
var contentResult = Parse.CharExcept(')').AtLeastOnce().Text().Token()(input);
|
|
||||||
input = contentResult.Remainder;
|
|
||||||
if (!contentResult.WasSuccessful)
|
|
||||||
return Result.Failure<IDirective>(input, "Invalid constant directive", ["Expected constant value"]);
|
|
||||||
|
|
||||||
var closeBracketResult = Parse.Char(')').Token()(input);
|
|
||||||
input = closeBracketResult.Remainder;
|
|
||||||
if (!closeBracketResult.WasSuccessful)
|
|
||||||
return Result.Failure<IDirective>(input, "Invalid constant directive", ["Expected ')'"]);
|
|
||||||
|
|
||||||
directive = new ConstantDirective(constNameResult.Value, typeNameResult.Value, contentResult.Value)
|
|
||||||
{
|
{
|
||||||
Line = line,
|
// Find the end of the XML tag
|
||||||
Column = column,
|
var xmlPartResult = Parse.AnyChar.Until(Parse.String("/>")).Text()(input);
|
||||||
};
|
input = xmlPartResult.Remainder;
|
||||||
|
if (!xmlPartResult.WasSuccessful)
|
||||||
|
return Result.Failure<IDirective>(input, "Invalid constant directive", ["Expected valid XML"]);
|
||||||
|
|
||||||
|
var xmlElem = System.Xml.Linq.XElement.Parse($"{xmlPartResult.Value}/>");
|
||||||
|
QualifiedTypeName typeName = new(xmlElem.Name.NamespaceName, xmlElem.Name.LocalName);
|
||||||
|
var content = xmlElem.ToString(System.Xml.Linq.SaveOptions.DisableFormatting);
|
||||||
|
|
||||||
|
directive = new ConstantDirective(constNameResult.Value, typeName, content)
|
||||||
|
{
|
||||||
|
Line = line,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var typeNameResult = QualifiedTypeName.Token()(input);
|
||||||
|
input = typeNameResult.Remainder;
|
||||||
|
if (!typeNameResult.WasSuccessful)
|
||||||
|
return Result.Failure<IDirective>(input, "Invalid constant directive", ["Expected qualified name of type to construct"]);
|
||||||
|
|
||||||
|
var openBracketResult = Parse.Char('(').Token()(input);
|
||||||
|
input = openBracketResult.Remainder;
|
||||||
|
if (!openBracketResult.WasSuccessful)
|
||||||
|
return Result.Failure<IDirective>(input, "Invalid constant directive", ["Expected '('"]);
|
||||||
|
|
||||||
|
var contentResult = Parse.CharExcept(')').AtLeastOnce().Text().Token()(input);
|
||||||
|
input = contentResult.Remainder;
|
||||||
|
if (!contentResult.WasSuccessful)
|
||||||
|
return Result.Failure<IDirective>(input, "Invalid constant directive", ["Expected constant value"]);
|
||||||
|
|
||||||
|
var closeBracketResult = Parse.Char(')').Token()(input);
|
||||||
|
input = closeBracketResult.Remainder;
|
||||||
|
if (!closeBracketResult.WasSuccessful)
|
||||||
|
return Result.Failure<IDirective>(input, "Invalid constant directive", ["Expected ')'"]);
|
||||||
|
|
||||||
|
directive = new EncodedConstantDirective(constNameResult.Value, typeNameResult.Value, contentResult.Value)
|
||||||
|
{
|
||||||
|
Line = line,
|
||||||
|
Column = column,
|
||||||
|
};
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "EXPORT":
|
case "EXPORT":
|
||||||
|
|||||||
@@ -14,18 +14,31 @@ public record SectionDirective : Directive
|
|||||||
|
|
||||||
public record ConstantDirective : Directive
|
public record ConstantDirective : Directive
|
||||||
{
|
{
|
||||||
public ConstantDirective(string name, QualifiedTypeName typeName, string content) : base("constant")
|
public ConstantDirective(string name, QualifiedTypeName typeName, string constructor) : base("constant")
|
||||||
{
|
{
|
||||||
Name = name;
|
Name = name;
|
||||||
TypeName = typeName;
|
TypeName = typeName;
|
||||||
Content = content;
|
Constructor = constructor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
public QualifiedTypeName TypeName { get; }
|
public QualifiedTypeName TypeName { get; }
|
||||||
|
public string Constructor { get; }
|
||||||
|
|
||||||
|
public override string ToString() => $"{base.ToString()} {Name} = {Constructor}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public record EncodedConstantDirective : ConstantDirective
|
||||||
|
{
|
||||||
|
public EncodedConstantDirective(string name, QualifiedTypeName typeName, string content)
|
||||||
|
: base(name, typeName, $"{typeName}({content})")
|
||||||
|
{
|
||||||
|
Content = content;
|
||||||
|
}
|
||||||
|
|
||||||
public string Content { get; }
|
public string Content { get; }
|
||||||
|
|
||||||
public override string ToString() => $"{base.ToString()} {Name} = {TypeName}({Content})";
|
public override string ToString() => base.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public record ExportDirective : Directive
|
public record ExportDirective : Directive
|
||||||
|
|||||||
@@ -29,12 +29,14 @@ public class Assembly(ITestOutputHelper output)
|
|||||||
.import-type Color
|
.import-type Color
|
||||||
.import-type Font
|
.import-type Font
|
||||||
|
|
||||||
.constant const0 = Color(A=255, R=255, G=0, B=0)
|
.constant const0 = Color(255, 255, 0, 0)
|
||||||
.constant const1 = String(Howdy from Microsoft.Iris!)
|
.constant const1 = String(Howdy from Microsoft.Iris!)
|
||||||
.constant const2 = String(SelectCommand)
|
.constant const2 = String(SelectCommand)
|
||||||
.constant const3 = Color(A=255, R=0, G=0, B=255)
|
.constant const3 = Color(255, 0, 0, 255)
|
||||||
.constant const4 = Font(JetBrains Mono)
|
.constant const4 = Font(JetBrains Mono)
|
||||||
.constant const5 = String(This is some blue text)
|
.constant const5 = String(This is some blue text)
|
||||||
|
.constant xmlTest = <FlowLayout Orientation="Vertical" Spacing="50,0" />
|
||||||
|
|
||||||
.section object
|
.section object
|
||||||
|
|
||||||
Default_cont:
|
Default_cont:
|
||||||
@@ -67,7 +69,7 @@ Alt_locl:
|
|||||||
output.WriteLine(ast.ToString());
|
output.WriteLine(ast.ToString());
|
||||||
|
|
||||||
Assert.NotNull(ast);
|
Assert.NotNull(ast);
|
||||||
Assert.Equal(18, ast.Directives.Count());
|
Assert.Equal(19, ast.Directives.Count());
|
||||||
Assert.Equal(24, ast.Code.Count());
|
Assert.Equal(24, ast.Code.Count());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user