2024-01-31 09:21:30 -06:00
|
|
|
using Microsoft.Iris.Asm.Models;
|
|
|
|
|
using Sprache;
|
2024-01-29 21:42:06 -06:00
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
2024-01-29 21:57:00 -06:00
|
|
|
namespace Microsoft.Iris.Asm;
|
2024-01-29 21:42:06 -06:00
|
|
|
|
|
|
|
|
public static class Lexer
|
|
|
|
|
{
|
|
|
|
|
public static readonly Parser<string> AlphanumericText = Parse.LetterOrDigit.AtLeastOnce().Text();
|
|
|
|
|
|
|
|
|
|
public static readonly Parser<string> Uri = Parse.LetterOrDigit.Or(Parse.Chars(":/!._-")).AtLeastOnce().Text();
|
|
|
|
|
|
|
|
|
|
public static readonly Parser<string> StatementEnd = Parse.Char(';').Return(";").Or(Parse.LineTerminator);
|
|
|
|
|
|
2024-01-30 22:44:48 -06:00
|
|
|
public static readonly Parser<IImport> Import = ParseImport;
|
2024-01-29 21:42:06 -06:00
|
|
|
|
|
|
|
|
public static readonly Parser<IBodyItem> BodyItem = ParseBodyItem;
|
|
|
|
|
|
|
|
|
|
public static readonly Parser<Program> Program =
|
|
|
|
|
from imports in Import.Token().Many()
|
|
|
|
|
from body in BodyItem.Many()
|
|
|
|
|
select new Program(imports, body);
|
|
|
|
|
|
|
|
|
|
private static IResult<IBodyItem> ParseBodyItem(IInput input)
|
|
|
|
|
{
|
2024-01-30 22:44:48 -06:00
|
|
|
input = ConsumeWhitespace(input);
|
2024-01-29 21:42:06 -06:00
|
|
|
|
|
|
|
|
var identifierResult = Parse.Letter.AtLeastOnce().Text().Invoke(input);
|
|
|
|
|
if (!identifierResult.WasSuccessful)
|
|
|
|
|
return Result.Failure<Instruction>(input, "Invalid code", System.Array.Empty<string>());
|
|
|
|
|
|
|
|
|
|
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<Operand> operands = new();
|
|
|
|
|
var endOfInstructionResult = StatementEnd(input);
|
|
|
|
|
input = endOfInstructionResult.Remainder;
|
|
|
|
|
|
|
|
|
|
if (!endOfInstructionResult.WasSuccessful)
|
|
|
|
|
{
|
2024-01-30 22:44:48 -06:00
|
|
|
input = ConsumeWhitespace(input);
|
2024-01-29 21:42:06 -06:00
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
2024-01-30 22:44:48 -06:00
|
|
|
|
|
|
|
|
private static IResult<IImport> ParseImport(IInput input)
|
|
|
|
|
{
|
|
|
|
|
input = ConsumeWhitespace(input);
|
|
|
|
|
|
|
|
|
|
var importDirectiveResult = Parse.String(".import-")(input);
|
|
|
|
|
input = importDirectiveResult.Remainder;
|
|
|
|
|
if (!importDirectiveResult.WasSuccessful)
|
|
|
|
|
return Result.Failure<IImport>(input, "Invalid import directive", null);
|
|
|
|
|
|
|
|
|
|
var importTypeResult = Parse.Letter.AtLeastOnce().Text()(input);
|
|
|
|
|
input = importTypeResult.Remainder;
|
|
|
|
|
if (!importTypeResult.WasSuccessful)
|
|
|
|
|
return Result.Failure<IImport>(input, "Invalid import type", null);
|
|
|
|
|
|
|
|
|
|
IImport import;
|
|
|
|
|
switch (importTypeResult.Value.ToUpperInvariant())
|
|
|
|
|
{
|
|
|
|
|
case "NS":
|
|
|
|
|
var uriResult = Uri.Token()(input);
|
|
|
|
|
input = uriResult.Remainder;
|
|
|
|
|
if (!uriResult.WasSuccessful)
|
|
|
|
|
return Result.Failure<IImport>(input, "Invalid URI", null);
|
|
|
|
|
|
|
|
|
|
input = Parse.String("as").Token()(input).Remainder;
|
|
|
|
|
|
|
|
|
|
var nameResult = AlphanumericText(input);
|
|
|
|
|
input = nameResult.Remainder;
|
|
|
|
|
if (!nameResult.WasSuccessful)
|
|
|
|
|
return Result.Failure<IImport>(input, "Invalid namespace alias", null);
|
|
|
|
|
|
|
|
|
|
import = new NamespaceImport(uriResult.Value, nameResult.Value);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return Result.Failure<IImport>(input, $"Unknown import type '{importTypeResult.Value}'", null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Result.Success(import, input);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static IInput ConsumeWhitespace(IInput input) => Parse.WhiteSpace.Many()(input).Remainder;
|
2024-01-29 21:42:06 -06:00
|
|
|
}
|