mirror of
https://github.com/ZuneDev/ZuneUIXTools.git
synced 2026-07-27 13:11:59 -07:00
Add constants and qualified type names to lexer, and use instruction schema to decode UIB instrctions
This commit is contained in:
@@ -119,31 +119,31 @@ internal static class InstructionSet
|
||||
[OpCode.ReturnValue] = [],
|
||||
[OpCode.ReturnVoid] = [],
|
||||
|
||||
[OpCode.ConstructObject] = Inst_UInt16,
|
||||
[OpCode.ConstructObject] = [LiteralDataType.TypeIndex],
|
||||
[OpCode.ConstructObjectIndirect] = Inst_UInt16,
|
||||
[OpCode.InitializeInstance] = Inst_UInt16,
|
||||
[OpCode.LookupSymbol] = Inst_UInt16,
|
||||
[OpCode.WriteSymbol] = Inst_UInt16,
|
||||
[OpCode.WriteSymbolPeek] = Inst_UInt16,
|
||||
[OpCode.ClearSymbol] = Inst_UInt16,
|
||||
[OpCode.PropertyInitialize] = Inst_UInt16,
|
||||
[OpCode.PropertyInitializeIndirect] = Inst_UInt16,
|
||||
[OpCode.PropertyListAdd] = Inst_UInt16,
|
||||
[OpCode.PropertyAssign] = Inst_UInt16,
|
||||
[OpCode.PropertyAssignStatic] = Inst_UInt16,
|
||||
[OpCode.PropertyGet] = Inst_UInt16,
|
||||
[OpCode.PropertyGetPeek] = Inst_UInt16,
|
||||
[OpCode.PropertyGetStatic] = Inst_UInt16,
|
||||
[OpCode.MethodInvoke] = Inst_UInt16,
|
||||
[OpCode.MethodInvokePeek] = Inst_UInt16,
|
||||
[OpCode.MethodInvokeStatic] = Inst_UInt16,
|
||||
[OpCode.MethodInvokePushLastParam] = Inst_UInt16,
|
||||
[OpCode.MethodInvokeStaticPushLastParam] = Inst_UInt16,
|
||||
[OpCode.VerifyTypeCast] = Inst_UInt16,
|
||||
[OpCode.IsCheck] = Inst_UInt16,
|
||||
[OpCode.As] = Inst_UInt16,
|
||||
[OpCode.TypeOf] = Inst_UInt16,
|
||||
[OpCode.PushConstant] = Inst_UInt16,
|
||||
[OpCode.InitializeInstance] = [LiteralDataType.TypeIndex],
|
||||
[OpCode.LookupSymbol] = [LiteralDataType.SymbolRefIndex],
|
||||
[OpCode.WriteSymbol] = [LiteralDataType.SymbolRefIndex],
|
||||
[OpCode.WriteSymbolPeek] = [LiteralDataType.SymbolRefIndex],
|
||||
[OpCode.ClearSymbol] = [LiteralDataType.SymbolRefIndex],
|
||||
[OpCode.PropertyInitialize] = [LiteralDataType.PropertyIndex],
|
||||
[OpCode.PropertyInitializeIndirect] = [LiteralDataType.PropertyIndex],
|
||||
[OpCode.PropertyListAdd] = [LiteralDataType.PropertyIndex],
|
||||
[OpCode.PropertyAssign] = [LiteralDataType.PropertyIndex],
|
||||
[OpCode.PropertyAssignStatic] = [LiteralDataType.PropertyIndex],
|
||||
[OpCode.PropertyGet] = [LiteralDataType.PropertyIndex],
|
||||
[OpCode.PropertyGetPeek] = [LiteralDataType.PropertyIndex],
|
||||
[OpCode.PropertyGetStatic] = [LiteralDataType.PropertyIndex],
|
||||
[OpCode.MethodInvoke] = [LiteralDataType.MethodIndex],
|
||||
[OpCode.MethodInvokePeek] = [LiteralDataType.MethodIndex],
|
||||
[OpCode.MethodInvokeStatic] = [LiteralDataType.MethodIndex],
|
||||
[OpCode.MethodInvokePushLastParam] = [LiteralDataType.MethodIndex],
|
||||
[OpCode.MethodInvokeStaticPushLastParam] = [LiteralDataType.MethodIndex],
|
||||
[OpCode.VerifyTypeCast] = [LiteralDataType.TypeIndex],
|
||||
[OpCode.IsCheck] = [LiteralDataType.TypeIndex],
|
||||
[OpCode.As] = [LiteralDataType.TypeIndex],
|
||||
[OpCode.TypeOf] = [LiteralDataType.TypeIndex],
|
||||
[OpCode.PushConstant] = [LiteralDataType.ConstantIndex],
|
||||
[OpCode.ConstructListenerStorage] = Inst_UInt16,
|
||||
|
||||
[OpCode.JumpIfFalse] = Inst_UInt32,
|
||||
@@ -154,16 +154,16 @@ internal static class InstructionSet
|
||||
|
||||
[OpCode.EnterDebugState] = [LiteralDataType.Int32],
|
||||
|
||||
[OpCode.ConstructObjectParam] = Inst_UInt16x2,
|
||||
[OpCode.ConstructFromString] = Inst_UInt16x2,
|
||||
[OpCode.PropertyDictionaryAdd] = Inst_UInt16x2,
|
||||
[OpCode.ConvertType] = Inst_UInt16x2,
|
||||
[OpCode.ConstructObjectParam] = [LiteralDataType.TypeIndex, LiteralDataType.UInt16],
|
||||
[OpCode.ConstructFromString] = [LiteralDataType.TypeIndex, LiteralDataType.ConstantIndex],
|
||||
[OpCode.PropertyDictionaryAdd] = [LiteralDataType.TypeIndex, LiteralDataType.ConstantIndex],
|
||||
[OpCode.ConvertType] = [LiteralDataType.TypeIndex, LiteralDataType.TypeIndex],
|
||||
|
||||
[OpCode.JumpIfDictionaryContains] = [LiteralDataType.UInt16, LiteralDataType.UInt16, LiteralDataType.UInt32],
|
||||
[OpCode.JumpIfDictionaryContains] = [LiteralDataType.PropertyIndex, LiteralDataType.UInt16, LiteralDataType.UInt32],
|
||||
|
||||
[OpCode.ConstructFromBinary] = [LiteralDataType.UInt16, LiteralDataType.Bytes],
|
||||
[OpCode.ConstructFromBinary] = [LiteralDataType.TypeIndex, LiteralDataType.Bytes],
|
||||
|
||||
[OpCode.Operation] = [LiteralDataType.UInt16, LiteralDataType.Byte],
|
||||
[OpCode.Operation] = [LiteralDataType.OpHostIndex, LiteralDataType.Byte],
|
||||
|
||||
[OpCode.Listen] = [LiteralDataType.UInt16, LiteralDataType.Byte, LiteralDataType.UInt16, LiteralDataType.UInt32],
|
||||
[OpCode.DestructiveListen] = [LiteralDataType.UInt16, LiteralDataType.Byte, LiteralDataType.UInt16, LiteralDataType.UInt32, LiteralDataType.UInt32],
|
||||
|
||||
+39
-11
@@ -44,7 +44,7 @@ partial class Lexer
|
||||
}
|
||||
else
|
||||
{
|
||||
List<OperandLiteral> operands = new();
|
||||
Operand[] operands = null;
|
||||
var endOfInstructionResult = StatementEnd(input);
|
||||
input = endOfInstructionResult.Remainder;
|
||||
|
||||
@@ -52,18 +52,41 @@ partial class Lexer
|
||||
{
|
||||
input = ConsumeWhitespace(input);
|
||||
|
||||
var operandsResult = Parse.Ref(() => AlphanumericText).DelimitedBy(Parse.Char(',').Token())(input);
|
||||
input = operandsResult.Remainder;
|
||||
|
||||
var opCode = InstructionSet.MnemonicToOpCode(identifier);
|
||||
var schema = InstructionSet.InstructionSchema[opCode];
|
||||
operands = new Operand[schema.Length];
|
||||
|
||||
int schemaIndex = 0;
|
||||
foreach (var operandContent in operandsResult.Value)
|
||||
for (int operandIndex = 0; operandIndex < schema.Length; operandIndex++)
|
||||
{
|
||||
var operandType = schema[schemaIndex++];
|
||||
Operand operand;
|
||||
var operandType = schema[operandIndex];
|
||||
|
||||
object operandValue = operandType switch
|
||||
var operandConstPrefixResult = Parse.Char('@')(input);
|
||||
input = operandConstPrefixResult.Remainder;
|
||||
if (operandConstPrefixResult.WasSuccessful)
|
||||
{
|
||||
if (!OperandLiteral.IsIndex(operandType))
|
||||
return Result.Failure<IBodyItem>(input, "Invalid instruction", [$"Constant references are not allowed for this operand, expected a {operandType}"]);
|
||||
|
||||
var operandConstResult = Identifier(input);
|
||||
input = operandConstResult.Remainder;
|
||||
if (!operandConstResult.WasSuccessful)
|
||||
return Result.Failure<IBodyItem>(input, "Invalid instruction", ["Invalid constant name"]);
|
||||
|
||||
operand = new OperandReference(operandConstResult.Value)
|
||||
{
|
||||
Line = line,
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
var operandContentResult = AlphanumericText(input);
|
||||
input = operandContentResult.Remainder;
|
||||
if (!operandContentResult.WasSuccessful)
|
||||
return Result.Failure<IBodyItem>(input, "Invalid instruction", ["Invalid operand"]);
|
||||
|
||||
var operandContent = operandContentResult.Value;
|
||||
object operandValue = OperandLiteral.ReduceDataType(operandType) switch
|
||||
{
|
||||
LiteralDataType.Byte => byte.Parse(operandContent),
|
||||
LiteralDataType.UInt16 => ushort.Parse(operandContent),
|
||||
@@ -72,14 +95,19 @@ partial class Lexer
|
||||
LiteralDataType.Bytes or _ => operandContent,
|
||||
};
|
||||
|
||||
operands.Add(new(operandValue, operandType, operandContent)
|
||||
operand = new OperandLiteral(operandValue, operandType, operandContent)
|
||||
{
|
||||
Line = line,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
operands[operandIndex] = operand;
|
||||
|
||||
input = Parse.Char(',').Token()(input).Remainder;
|
||||
}
|
||||
}
|
||||
|
||||
bodyItem = new Instruction(identifier, operands)
|
||||
bodyItem = new Instruction(identifier, operands ?? [])
|
||||
{
|
||||
Line = line,
|
||||
Column = column,
|
||||
|
||||
@@ -30,12 +30,12 @@ partial class Lexer
|
||||
|
||||
case "SECTION":
|
||||
if (StatementEnd(input).WasSuccessful)
|
||||
return Result.Failure<IImportDirective>(input, "Invalid section directive", ["Expected a section name"]);
|
||||
return Result.Failure<IDirective>(input, "Invalid section directive", ["Expected a section name"]);
|
||||
|
||||
var sectionNameResult = Parse.Letter.AtLeastOnce().Token().Text()(input);
|
||||
input = sectionNameResult.Remainder;
|
||||
if (!sectionNameResult.WasSuccessful)
|
||||
return Result.Failure<IImportDirective>(input, "Invalid section name", ["Expected a section name containing only letters"]);
|
||||
return Result.Failure<IDirective>(input, "Invalid section name", ["Expected a section name containing only letters"]);
|
||||
|
||||
directive = new SectionDirective(sectionNameResult.Value)
|
||||
{
|
||||
@@ -44,27 +44,65 @@ partial class Lexer
|
||||
};
|
||||
break;
|
||||
|
||||
case "CONSTANT":
|
||||
if (StatementEnd(input).WasSuccessful)
|
||||
return Result.Failure<IDirective>(input, "Invalid constant directive", ["Expected a consant declaration"]);
|
||||
|
||||
var constNameResult = Identifier.Token()(input);
|
||||
input = constNameResult.Remainder;
|
||||
if (!constNameResult.WasSuccessful)
|
||||
return Result.Failure<IDirective>(input, "Invalid constant directive", ["Expected a name for the constant"]);
|
||||
|
||||
input = Parse.Char('=').Token()(input).Remainder;
|
||||
|
||||
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 ConstantDirective(constNameResult.Value, typeNameResult.Value, contentResult.Value)
|
||||
{
|
||||
Line = line,
|
||||
Column = column,
|
||||
};
|
||||
break;
|
||||
|
||||
case "EXPORT":
|
||||
if (StatementEnd(input).WasSuccessful)
|
||||
return Result.Failure<IImportDirective>(input, "Invalid export directive", ["Expected export information"]);
|
||||
return Result.Failure<IDirective>(input, "Invalid export directive", ["Expected export information"]);
|
||||
|
||||
var labelPrefixResult = Identifier.Token()(input);
|
||||
input = labelPrefixResult.Remainder;
|
||||
if (!labelPrefixResult.WasSuccessful)
|
||||
return Result.Failure<IImportDirective>(input, "Invalid export directive", ["Expected prefix of labels to export"]);
|
||||
return Result.Failure<IDirective>(input, "Invalid export directive", ["Expected prefix of labels to export"]);
|
||||
|
||||
var listenerCountResult = WholeNumber.Token()(input);
|
||||
input = listenerCountResult.Remainder;
|
||||
if (!listenerCountResult.WasSuccessful)
|
||||
return Result.Failure<IImportDirective>(input, "Invalid export directive", ["Expected listener count"]);
|
||||
return Result.Failure<IDirective>(input, "Invalid export directive", ["Expected listener count"]);
|
||||
|
||||
if (!uint.TryParse(listenerCountResult.Value, out var listenerCount))
|
||||
return Result.Failure<IImportDirective>(input, "Invalid export directive", ["Expected export listener count to be an unsigned integer"]);
|
||||
return Result.Failure<IDirective>(input, "Invalid export directive", ["Expected export listener count to be an unsigned integer"]);
|
||||
|
||||
var baseTypeNameResult = AlphanumericText.Token()(input);
|
||||
input = baseTypeNameResult.Remainder;
|
||||
if (!baseTypeNameResult.WasSuccessful)
|
||||
return Result.Failure<IImportDirective>(input, "Invalid export directive", ["Expected base type name"]);
|
||||
return Result.Failure<IDirective>(input, "Invalid export directive", ["Expected base type name"]);
|
||||
|
||||
var labelPrefix = labelPrefixResult.Value;
|
||||
var baseTypeName = baseTypeNameResult.Value;
|
||||
@@ -76,7 +114,7 @@ partial class Lexer
|
||||
break;
|
||||
|
||||
default:
|
||||
return Result.Failure<IImportDirective>(input, $"Unknown import type '{directiveIdResult.Value}'", ["Expected 'export', 'import', or 'section'"]);
|
||||
return Result.Failure<IDirective>(input, $"Unknown import type '{directiveIdResult.Value}'", ["Expected 'export', 'import', or 'section'"]);
|
||||
}
|
||||
|
||||
return Result.Success(directive, input);
|
||||
|
||||
@@ -48,36 +48,18 @@ partial class Lexer
|
||||
break;
|
||||
|
||||
case "TYPE":
|
||||
var typePrefixResult = Identifier.Token()(input);
|
||||
input = typePrefixResult.Remainder;
|
||||
if (!typePrefixResult.WasSuccessful)
|
||||
return Result.Failure<IImportDirective>(input, "Invalid type import", ["Expected a valid namespace prefix"]);
|
||||
input = ConsumeWhitespace(input);
|
||||
|
||||
var typeNamespaceDelimitterResult = Parse.Char(':')(input);
|
||||
input = typeNamespaceDelimitterResult.Remainder;
|
||||
|
||||
string typeName, typePrefix;
|
||||
if (typeNamespaceDelimitterResult.WasSuccessful)
|
||||
{
|
||||
var typeNameResult = Identifier(input);
|
||||
var typeNameResult = ParseQualifiedTypeName(input);
|
||||
input = typeNameResult.Remainder;
|
||||
if (!typeNameResult.WasSuccessful)
|
||||
return Result.Failure<IImportDirective>(input, "Invalid type import", ["Expected a valid type name"]);
|
||||
return Result.Failure<IImportDirective>(input, "Invalid type import", ["Expected qualified type name"]);
|
||||
|
||||
typePrefix = typePrefixResult.Value;
|
||||
typeName = typeNameResult.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
typePrefix = null;
|
||||
typeName = typePrefixResult.Value;
|
||||
}
|
||||
|
||||
import = new TypeImport(typePrefix, typeName);
|
||||
import = new TypeImport(typeNameResult.Value);
|
||||
break;
|
||||
|
||||
default:
|
||||
return Result.Failure<IImportDirective>(input, $"Unknown import type '{importTypeResult.Value}'", ["Expected 'ns'"]);
|
||||
return Result.Failure<IImportDirective>(input, $"Unknown import type '{importTypeResult.Value}'", ["Expected 'ns', 'type'"]);
|
||||
}
|
||||
|
||||
return Result.Success(import, input);
|
||||
|
||||
@@ -18,6 +18,8 @@ public static partial class Lexer
|
||||
|
||||
public static readonly Parser<string> StatementEnd = Parse.Char(';').Return(";").Or(Parse.LineTerminator);
|
||||
|
||||
public static readonly Parser<QualifiedTypeName> QualifiedTypeName = ParseQualifiedTypeName;
|
||||
|
||||
public static readonly Parser<IImportDirective> Import = ParseImport;
|
||||
|
||||
public static readonly Parser<IDirective> Directive = ParseDirective;
|
||||
@@ -29,4 +31,35 @@ public static partial class Lexer
|
||||
select new Program(body);
|
||||
|
||||
private static IInput ConsumeWhitespace(IInput input) => Parse.WhiteSpace.Many()(input).Remainder;
|
||||
|
||||
private static IResult<QualifiedTypeName> ParseQualifiedTypeName(IInput input)
|
||||
{
|
||||
var typePrefixResult = Identifier(input);
|
||||
input = typePrefixResult.Remainder;
|
||||
if (!typePrefixResult.WasSuccessful)
|
||||
return Result.Failure<QualifiedTypeName>(input, "Invalid type name", ["Expected a valid namespace prefix"]);
|
||||
|
||||
var typeNamespaceDelimitterResult = Parse.Char(':')(input);
|
||||
input = typeNamespaceDelimitterResult.Remainder;
|
||||
|
||||
string typeName, typePrefix;
|
||||
if (typeNamespaceDelimitterResult.WasSuccessful)
|
||||
{
|
||||
var typeNameResult = Identifier(input);
|
||||
input = typeNameResult.Remainder;
|
||||
if (!typeNameResult.WasSuccessful)
|
||||
return Result.Failure<QualifiedTypeName>(input, "Invalid type name", ["Expected a valid type name"]);
|
||||
|
||||
typePrefix = typePrefixResult.Value;
|
||||
typeName = typeNameResult.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
typePrefix = null;
|
||||
typeName = typePrefixResult.Value;
|
||||
}
|
||||
|
||||
QualifiedTypeName qualifiedName = new(typePrefix, typeName);
|
||||
return Result.Success(qualifiedName, input);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,16 +14,18 @@ public record SectionDirective : Directive
|
||||
|
||||
public record ConstantDirective : Directive
|
||||
{
|
||||
public ConstantDirective(string name, string typeName, string content) : base("constant")
|
||||
public ConstantDirective(string name, QualifiedTypeName typeName, string content) : base("constant")
|
||||
{
|
||||
Name = name;
|
||||
TypeName = typeName;
|
||||
ValueString = content;
|
||||
Content = content;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public string TypeName { get; }
|
||||
public string ValueString { get; }
|
||||
public QualifiedTypeName TypeName { get; }
|
||||
public string Content { get; }
|
||||
|
||||
public override string ToString() => $"{base.ToString()} {Name} = {TypeName}({Content})";
|
||||
}
|
||||
|
||||
public record ExportDirective : Directive
|
||||
|
||||
@@ -16,20 +16,12 @@ public record NamespaceImport : ImportDirective
|
||||
|
||||
public record TypeImport : ImportDirective
|
||||
{
|
||||
public TypeImport(string namespacePrefix, string name) : base("type")
|
||||
public TypeImport(QualifiedTypeName qualifiedName) : base("type")
|
||||
{
|
||||
NamespacePrefix = namespacePrefix;
|
||||
Name = name;
|
||||
QualifiedName = qualifiedName;
|
||||
}
|
||||
|
||||
public string NamespacePrefix { get; init; }
|
||||
public string Name { get; init; }
|
||||
public QualifiedTypeName QualifiedName { get; init; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (NamespacePrefix is null)
|
||||
return $"{base.ToString()} {Name}";
|
||||
else
|
||||
return $"{base.ToString()} {NamespacePrefix}:{Name}";
|
||||
}
|
||||
public override string ToString() => $"{base.ToString()} {QualifiedName}";
|
||||
}
|
||||
|
||||
@@ -1,12 +1,26 @@
|
||||
namespace Microsoft.Iris.Asm.Models;
|
||||
|
||||
/// <summary>
|
||||
/// The data type of a literal expression.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If bit 4 is set, the literal is meant to be an index.
|
||||
/// </remarks>
|
||||
public enum LiteralDataType : byte
|
||||
{
|
||||
Byte,
|
||||
UInt16,
|
||||
UInt32,
|
||||
Int32,
|
||||
Bytes,
|
||||
Byte = 0b0000,
|
||||
UInt16 = 0b0001,
|
||||
UInt32 = 0b0010,
|
||||
Int32 = 0b0011,
|
||||
|
||||
Bytes = 0b0100,
|
||||
|
||||
TypeIndex = 0b1000,
|
||||
PropertyIndex = 0b1001,
|
||||
MethodIndex = 0b1010,
|
||||
ConstantIndex = 0b1011,
|
||||
SymbolRefIndex = 0b1100,
|
||||
OpHostIndex = 0b1101,
|
||||
}
|
||||
|
||||
public abstract record Operand(object Value, string Content = null) : AsmItem
|
||||
@@ -24,15 +38,22 @@ public record OperandLiteral : Operand
|
||||
public LiteralDataType DataType { get; init; }
|
||||
|
||||
public override string ToString() => base.ToString();
|
||||
|
||||
public static LiteralDataType ReduceDataType(LiteralDataType dataType)
|
||||
{
|
||||
return IsIndex(dataType) ? LiteralDataType.UInt16 : dataType;
|
||||
}
|
||||
|
||||
public static bool IsIndex(LiteralDataType dataType) => ((byte)dataType & (1 << 3)) != 0;
|
||||
}
|
||||
|
||||
public record OperandReference : Operand
|
||||
{
|
||||
public OperandReference(string labelName) : base(labelName, labelName)
|
||||
public OperandReference(string constantName) : base(constantName, constantName)
|
||||
{
|
||||
}
|
||||
|
||||
public string LabelName => Content;
|
||||
public string ConstantName => Content;
|
||||
|
||||
public override string ToString() => base.ToString();
|
||||
public override string ToString() => $"@{base.ToString()}";
|
||||
}
|
||||
|
||||
@@ -11,6 +11,17 @@ public record Label(string Name) : CodeItem
|
||||
public override string ToString() => $"{Name}:";
|
||||
}
|
||||
|
||||
public record QualifiedTypeName(string NamespacePrefix, string TypeName) : AsmItem
|
||||
{
|
||||
public override string ToString()
|
||||
{
|
||||
if (NamespacePrefix is null)
|
||||
return TypeName;
|
||||
else
|
||||
return $"{NamespacePrefix}:{TypeName}";
|
||||
}
|
||||
}
|
||||
|
||||
public record Program
|
||||
{
|
||||
public Program(IEnumerable<IBodyItem> body)
|
||||
@@ -44,6 +55,9 @@ public record Program
|
||||
sb.AppendJoin(lineEnding, Imports.Select(i => i.ToString()));
|
||||
sb.Append(lineEnding);
|
||||
sb.Append(lineEnding);
|
||||
sb.AppendJoin(lineEnding, Directives.Where(d => d is not (IImportDirective or ExportDirective)).Select(i => i.ToString()));
|
||||
sb.Append(lineEnding);
|
||||
sb.Append(lineEnding);
|
||||
|
||||
foreach (var bodyItem in Code)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user