diff --git a/libs/UIX.Asm/Lexer.Body.cs b/libs/UIX.Asm/Lexer.Body.cs new file mode 100644 index 0000000..985190c --- /dev/null +++ b/libs/UIX.Asm/Lexer.Body.cs @@ -0,0 +1,51 @@ +using Microsoft.Iris.Asm.Models; +using Sprache; +using System.Collections.Generic; +using System.Linq; + +namespace Microsoft.Iris.Asm; + +partial class Lexer +{ + public static readonly Parser BodyItem = ParseBodyItem; + + private static IResult ParseBodyItem(IInput input) + { + input = ConsumeWhitespace(input); + + var identifierResult = Parse.Letter.AtLeastOnce().Text().Invoke(input); + if (!identifierResult.WasSuccessful) + return Result.Failure(input, "Invalid code", []); + + input = identifierResult.Remainder; + var identifier = identifierResult.Value; + IBodyItem bodyItem; + + if (!input.AtEnd && input.Current == ':') + { + input = input.Advance(); + bodyItem = new Label(identifier); + input = StatementEnd(input).Remainder; + } + else + { + List operands = new(); + var endOfInstructionResult = StatementEnd(input); + input = endOfInstructionResult.Remainder; + + if (!endOfInstructionResult.WasSuccessful) + { + input = ConsumeWhitespace(input); + + var operandsResult = Parse.Ref(() => AlphanumericText).DelimitedBy(Parse.Char(',').Token())(input); + operands.AddRange(operandsResult.Value.Select(s => new Operand(s))); + input = operandsResult.Remainder; + } + + bodyItem = new Instruction(identifier, operands); + } + + return Result.Success(bodyItem, input); + } + +} diff --git a/libs/UIX.Asm/Lexer.Imports.cs b/libs/UIX.Asm/Lexer.Imports.cs new file mode 100644 index 0000000..8f84aa1 --- /dev/null +++ b/libs/UIX.Asm/Lexer.Imports.cs @@ -0,0 +1,49 @@ +using Microsoft.Iris.Asm.Models; +using Sprache; + +namespace Microsoft.Iris.Asm; + +partial class Lexer +{ + public static readonly Parser Import = ParseImport; + + private static IResult ParseImport(IInput input) + { + input = ConsumeWhitespace(input); + + var importDirectiveResult = Parse.String(".import-")(input); + input = importDirectiveResult.Remainder; + if (!importDirectiveResult.WasSuccessful) + return Result.Failure(input, "Invalid import directive", ["Expected '.import'"]); + + var importTypeResult = Parse.Letter.AtLeastOnce().Text()(input); + input = importTypeResult.Remainder; + if (!importTypeResult.WasSuccessful) + return Result.Failure(input, "Invalid import type", ["Expected 'ns'"]); + + IImport import; + switch (importTypeResult.Value.ToUpperInvariant()) + { + case "NS": + var uriResult = Uri.Token()(input); + input = uriResult.Remainder; + if (!uriResult.WasSuccessful) + return Result.Failure(input, "Invalid URI", ["Expected a valid URI"]); + + input = Parse.String("as").Token()(input).Remainder; + + var nameResult = AlphanumericText(input); + input = nameResult.Remainder; + if (!nameResult.WasSuccessful) + return Result.Failure(input, "Invalid namespace alias", ["Expected a valid namespace alias"]); + + import = new NamespaceImport(uriResult.Value, nameResult.Value); + break; + + default: + return Result.Failure(input, $"Unknown import type '{importTypeResult.Value}'", ["Expected 'ns'"]); + } + + return Result.Success(import, input); + } +} diff --git a/libs/UIX.Asm/Lexer.cs b/libs/UIX.Asm/Lexer.cs index aabaf21..f081191 100644 --- a/libs/UIX.Asm/Lexer.cs +++ b/libs/UIX.Asm/Lexer.cs @@ -1,11 +1,10 @@ using Microsoft.Iris.Asm.Models; using Sprache; -using System.Collections.Generic; using System.Linq; namespace Microsoft.Iris.Asm; -public static class Lexer +public static partial class Lexer { public static readonly Parser AlphanumericText = Parse.LetterOrDigit.AtLeastOnce().Text(); @@ -18,93 +17,10 @@ public static class Lexer from sectionId in Parse.Letter.AtLeastOnce().Text() select sectionId; - public static readonly Parser Import = ParseImport; - - public static readonly Parser BodyItem = ParseBodyItem; - public static readonly Parser Program = from imports in Import.Token().Many() from body in BodyItem.Many() select new Program(imports, body); - private static IResult ParseBodyItem(IInput input) - { - input = ConsumeWhitespace(input); - - var identifierResult = Parse.Letter.AtLeastOnce().Text().Invoke(input); - if (!identifierResult.WasSuccessful) - return Result.Failure(input, "Invalid code", []); - - input = identifierResult.Remainder; - var identifier = identifierResult.Value; - IBodyItem bodyItem; - - if (!input.AtEnd && input.Current == ':') - { - input = input.Advance(); - bodyItem = new Label(identifier); - input = StatementEnd(input).Remainder; - } - else - { - List operands = new(); - var endOfInstructionResult = StatementEnd(input); - input = endOfInstructionResult.Remainder; - - if (!endOfInstructionResult.WasSuccessful) - { - input = ConsumeWhitespace(input); - - var operandsResult = Parse.Ref(() => AlphanumericText).DelimitedBy(Parse.Char(',').Token())(input); - operands.AddRange(operandsResult.Value.Select(s => new Operand(s))); - input = operandsResult.Remainder; - } - - bodyItem = new Instruction(identifier, operands); - } - - return Result.Success(bodyItem, input); - } - - private static IResult ParseImport(IInput input) - { - input = ConsumeWhitespace(input); - - var importDirectiveResult = Parse.String(".import-")(input); - input = importDirectiveResult.Remainder; - if (!importDirectiveResult.WasSuccessful) - return Result.Failure(input, "Invalid import directive", ["Expected '.import'"]); - - var importTypeResult = Parse.Letter.AtLeastOnce().Text()(input); - input = importTypeResult.Remainder; - if (!importTypeResult.WasSuccessful) - return Result.Failure(input, "Invalid import type", ["Expected 'ns'"]); - - IImport import; - switch (importTypeResult.Value.ToUpperInvariant()) - { - case "NS": - var uriResult = Uri.Token()(input); - input = uriResult.Remainder; - if (!uriResult.WasSuccessful) - return Result.Failure(input, "Invalid URI", ["Expected a valid URI"]); - - input = Parse.String("as").Token()(input).Remainder; - - var nameResult = AlphanumericText(input); - input = nameResult.Remainder; - if (!nameResult.WasSuccessful) - return Result.Failure(input, "Invalid namespace alias", ["Expected a valid namespace alias"]); - - import = new NamespaceImport(uriResult.Value, nameResult.Value); - break; - - default: - return Result.Failure(input, $"Unknown import type '{importTypeResult.Value}'", ["Expected 'ns'"]); - } - - return Result.Success(import, input); - } - private static IInput ConsumeWhitespace(IInput input) => Parse.WhiteSpace.Many()(input).Remainder; }