diff --git a/libs/UIX.Asm/Lexer.Directives.cs b/libs/UIX.Asm/Lexer.Directives.cs index 9df3538..620be1c 100644 --- a/libs/UIX.Asm/Lexer.Directives.cs +++ b/libs/UIX.Asm/Lexer.Directives.cs @@ -1,5 +1,6 @@ using Microsoft.Iris.Asm.Models; using Sprache; +using System.Linq; namespace Microsoft.Iris.Asm; @@ -16,7 +17,7 @@ partial class Lexer if (!directiveBeginResult.WasSuccessful) return Result.Failure(input, "Invalid directive", ["Expected '.', followed by an identifier"]); - var directiveIdResult = Parse.Letter.AtLeastOnce().Text()(input); + var directiveIdResult = WordText(input); input = directiveIdResult.Remainder; if (!directiveIdResult.WasSuccessful) return Result.Failure(input, "Invalid directive", ["Expected an identifier"]); @@ -43,8 +44,24 @@ partial class Lexer }; break; + case "EXPORT": + if (StatementEnd(input).WasSuccessful) + return Result.Failure(input, "Invalid export directive", ["Expected export information"]); + + var labelPrefixResult = AlphanumericText.Token()(input); + input = labelPrefixResult.Remainder; + if (!labelPrefixResult.WasSuccessful) + return Result.Failure(input, "Invalid export directive", ["Expected prefix of labels to export"]); + + directive = new ExportDirective(labelPrefixResult.Value) + { + Line = line, + Column = column, + }; + break; + default: - return Result.Failure(input, $"Unknown import type '{directiveIdResult.Value}'", ["Expected 'import' or 'section'"]); + return Result.Failure(input, $"Unknown import type '{directiveIdResult.Value}'", ["Expected 'export', 'import', or 'section'"]); } return Result.Success(directive, input); diff --git a/libs/UIX.Asm/Lexer.Imports.cs b/libs/UIX.Asm/Lexer.Imports.cs index 2028a28..6acf9d5 100644 --- a/libs/UIX.Asm/Lexer.Imports.cs +++ b/libs/UIX.Asm/Lexer.Imports.cs @@ -23,7 +23,7 @@ partial class Lexer return Result.Failure(input, "Invalid import type", ["An import type must be specified"]); input = input.Advance(); - var importTypeResult = Parse.Letter.AtLeastOnce().Text()(input); + var importTypeResult = WordText(input); input = importTypeResult.Remainder; if (!importTypeResult.WasSuccessful) return Result.Failure(input, "Invalid import type", ["Expected 'ns'"]); @@ -47,6 +47,22 @@ partial class Lexer import = new NamespaceImport(uriResult.Value, nameResult.Value); break; + case "TYPE": + var typePrefixResult = WordText.Token()(input); + input = typePrefixResult.Remainder; + if (!typePrefixResult.WasSuccessful) + return Result.Failure(input, "Invalid type import", ["Expected a valid namespace prefix"]); + + input = Parse.Char(':')(input).Remainder; + + var typeNameResult = WordText(input); + input = typeNameResult.Remainder; + if (!typeNameResult.WasSuccessful) + return Result.Failure(input, "Invalid type import", ["Expected a valid type name"]); + + import = new TypeImport(typePrefixResult.Value, typeNameResult.Value); + break; + default: return Result.Failure(input, $"Unknown import type '{importTypeResult.Value}'", ["Expected 'ns'"]); } diff --git a/libs/UIX.Asm/Lexer.cs b/libs/UIX.Asm/Lexer.cs index 67fb0de..bd6a994 100644 --- a/libs/UIX.Asm/Lexer.cs +++ b/libs/UIX.Asm/Lexer.cs @@ -8,6 +8,8 @@ public static partial class Lexer { public static readonly Parser AlphanumericText = Parse.LetterOrDigit.AtLeastOnce().Text(); + public static readonly Parser WordText = Parse.Letter.AtLeastOnce().Text(); + public static readonly Parser Uri = Parse.LetterOrDigit.Or(Parse.Chars(":/!._-")).AtLeastOnce().Text(); public static readonly Parser StatementEnd = Parse.Char(';').Return(";").Or(Parse.LineTerminator); @@ -19,9 +21,9 @@ public static partial class Lexer public static readonly Parser BodyItem = ParseBodyItem; public static readonly Parser Program = - from imports in Import.Token().Many() + from directives in Directive.Many() from body in BodyItem.Many() - select new Program(imports, body); + select new Program(directives, body); private static IInput ConsumeWhitespace(IInput input) => Parse.WhiteSpace.Many()(input).Remainder; } diff --git a/libs/UIX.Asm/Models/Directives.cs b/libs/UIX.Asm/Models/Directives.cs index 10ddc15..8b9780e 100644 --- a/libs/UIX.Asm/Models/Directives.cs +++ b/libs/UIX.Asm/Models/Directives.cs @@ -11,3 +11,23 @@ public record SectionDirective : Directive, IBodyItem public override string ToString() => $"{base.ToString()} {Name}"; } + +public record ExportDirective : Directive +{ + public ExportDirective(string labelPrefix) : base("export") + { + LabelPrefix = labelPrefix; + } + + public string LabelPrefix { get; init; } + + public override string ToString() => $"{base.ToString()} {LabelPrefix}"; + + public string InitializePropertiesLabel => LabelPrefix + "_prop"; + public string InitializeLocalInputLabel => LabelPrefix + "_locl"; + public string InitializeContentLabel => LabelPrefix + "_cont"; + + public string InitialEvaluateOffsetsLabelPrefix => LabelPrefix + "_evali_"; + public string FinalEvaluateOffsetsLabelPrefix => LabelPrefix + "_evalf_"; + public string RefreshGroupOffsetsLabelPrefix => LabelPrefix + "_rfsh_"; +} diff --git a/libs/UIX.Asm/Models/Imports.cs b/libs/UIX.Asm/Models/Imports.cs index 65b2e10..937969c 100644 --- a/libs/UIX.Asm/Models/Imports.cs +++ b/libs/UIX.Asm/Models/Imports.cs @@ -13,3 +13,23 @@ public record NamespaceImport : Import public override string ToString() => $"{base.ToString()} {Uri} as {Name}"; } + +public record TypeImport : Import +{ + public TypeImport(string namespacePrefix, string name) : base("type") + { + NamespacePrefix = namespacePrefix; + Name = name; + } + + public string NamespacePrefix { get; init; } + public string Name { get; init; } + + public override string ToString() + { + if (NamespacePrefix is null) + return $"{base.ToString()} {Name}"; + else + return $"{base.ToString()} {NamespacePrefix}:{Name}"; + } +} diff --git a/libs/UIX.Asm/Models/SyntaxModels.cs b/libs/UIX.Asm/Models/SyntaxModels.cs index 903582a..7875859 100644 --- a/libs/UIX.Asm/Models/SyntaxModels.cs +++ b/libs/UIX.Asm/Models/SyntaxModels.cs @@ -1,5 +1,4 @@ -using Microsoft.Iris.Markup; -using System.Collections.Generic; +using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; @@ -26,7 +25,7 @@ public record Operand(object Value, OperandDataType DataType, string Content = n public override string ToString() => Content ?? Value.ToString(); } -public record Program(IEnumerable Imports, IEnumerable Body) +public record Program(IEnumerable Directives, IEnumerable Body) { public override string ToString() { @@ -34,7 +33,7 @@ public record Program(IEnumerable Imports, IEnumerable Body) const string indent = " "; StringBuilder sb = new(); - sb.AppendJoin(lineEnding, Imports.Select(i => i.ToString())); + sb.AppendJoin(lineEnding, Directives.Select(i => i.ToString())); sb.Append(lineEnding); sb.Append(lineEnding);