Skip to content

Commit

Permalink
Add inline assembly support
Browse files Browse the repository at this point in the history
  • Loading branch information
Argmaster committed Oct 25, 2024
1 parent c0ea4ae commit 7af2a11
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 8 deletions.
76 changes: 76 additions & 0 deletions src/Bytom.Language.Tests/ParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -593,4 +593,80 @@ out var errorPosition
Assert.That(forStatement!.body, Has.Length.EqualTo(1));
}
}

public class InlineAssemblyTest
{
[Test]
public void TestGlobalAdd()
{
bool result = Parser.TryParse(@"
asm {
pop RD0
pop RD1
add RD0, RD1
};
",
out var value,
out var error,
out var errorPosition
);
Assert.That(error, Is.Null);
Assert.That(result, Is.True);
Assert.That(value, Is.InstanceOf<AST.Module>());

var module = (AST.Module)value;
Assert.That(module!.statements, Has.Length.EqualTo(1));

var statement = module!.statements[0];
Assert.That(statement, Is.InstanceOf<AST.Statements.SideEffect>());

var sideEffect = (AST.Statements.SideEffect)statement;
Assert.That(sideEffect!.expression, Is.InstanceOf<AST.Expressions.InlineAssembly>());

var asmStatement = (AST.Expressions.InlineAssembly)sideEffect!.expression;
Assert.That(asmStatement!.assembly, Has.Length.Not.EqualTo(0));
}

[Test]
public void TestAdd()
{
bool result = Parser.TryParse(@"
function add(var x: $T; var y: $T;): $T
{
return asm {
pop RD0
pop RD1
add RD0, RD1
};
}
",
out var value,
out var error,
out var errorPosition
);
Assert.That(error, Is.Null);
Assert.That(result, Is.True);
Assert.That(value, Is.InstanceOf<AST.Module>());

var module = (AST.Module)value;
Assert.That(module!.statements, Has.Length.EqualTo(1));

var statement = module!.statements[0];
Assert.That(statement, Is.InstanceOf<AST.Statements.FunctionDefinition>());

var function = (AST.Statements.FunctionDefinition)statement;
Assert.That(function!.name.name, Is.EqualTo("add"));
Assert.That(function!.arguments, Has.Length.EqualTo(2));
Assert.That(function!.return_type.type_name, Is.EqualTo("$T"));
Assert.That(function!.body, Has.Length.EqualTo(1));

var returnStatement = (AST.Statements.Return)function!.body[0];
Assert.That(returnStatement!.value, Is.InstanceOf<AST.Expressions.InlineAssembly>());

var asmStatement = (AST.Expressions.InlineAssembly)returnStatement!.value;
Assert.That(asmStatement!.assembly, Is.EqualTo("pop RD0\npop RD1\nadd RD0, RD1"));


}
}
}
26 changes: 23 additions & 3 deletions src/Bytom.Language/Parser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -241,14 +241,34 @@ from close in Character.EqualTo('"')
);

public static TokenListParser<Tokens, object> TypeName { get; } =
from name in Token.EqualTo(Tokens.Name)
from name in Token.EqualTo(Tokens.Name).Or(Token.EqualTo(Tokens.GenericName))
from pointer in Token.EqualTo(Tokens.Asterisk).Many()
select (object)new AST.Expressions.TypeName(name.ToStringValue(), pointer.Length);

private static TextParser<string> InlineAssemblyParser { get; } =
from asm in Span.EqualTo("asm")
from whitespace in Character.WhiteSpace.Many()
from openCurlyBrace in Character.EqualTo('{')
from content in Span.Except("}")
from closeCurlyBrace in Character.EqualTo('}')
select string.Join(
"\n", content.ToStringValue()
.Split("\n")
.Select(s => s.Trim())
.Where(s => s.Length != 0)
.ToArray()
);

public static TokenListParser<Tokens, object> InlineAssembly { get; } =
Token.EqualTo(Tokens.Asm)
.Apply(InlineAssemblyParser)
.Select(s => (object)new AST.Expressions.InlineAssembly(s));

public static TokenListParser<Tokens, object> Expression { get; } =
Parse.OneOf(
StringLiteral.Try(),
IntegerLiteral.Try(),
StringLiteral,
IntegerLiteral,
InlineAssembly,
FunctionCall.Try(),
LeftIdentifier
);
Expand Down
17 changes: 13 additions & 4 deletions src/Bytom.Language/Tokenizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,21 @@ public static class Tokenizer
{
static TextParser<Unit> StringToken { get; } =
from open in Character.EqualTo('"')
from content in Character.EqualTo('\\').IgnoreThen(Character.AnyChar).Value(Unit.Value).Try()
from content in Character.EqualTo('\\')
.IgnoreThen(Character.AnyChar).Value(Unit.Value).Try()
.Or(Character.Except('"').Value(Unit.Value))
.IgnoreMany()
from close in Character.EqualTo('"')
select Unit.Value;

static TextParser<Unit> InlineAssembly { get; } =
from open in Span.EqualTo("asm")
from whitespace in Character.WhiteSpace.IgnoreMany()
from openCurly in Character.EqualTo('{')
from content in Character.Except('}').Value(Unit.Value).IgnoreMany()
from closeCurly in Character.EqualTo('}')
select Unit.Value;

public static Tokenizer<Tokens> Instance { get; } =
new TokenizerBuilder<Tokens>()
.Ignore(Span.WhiteSpace)
Expand All @@ -143,7 +152,6 @@ from close in Character.EqualTo('"')
.Match(Character.EqualTo('.'), Tokens.Dot)
.Match(Span.EqualTo("=>"), Tokens.Arrow)
.Match(Character.EqualTo('='), Tokens.Assignment)
.Match(Span.EqualTo("asm"), Tokens.Asm)
.Match(Span.EqualTo("struct"), Tokens.Struct)
.Match(Span.EqualTo("bitfield"), Tokens.BitField)
.Match(Span.EqualTo("return"), Tokens.Return)
Expand All @@ -157,11 +165,12 @@ from close in Character.EqualTo('"')
.Match(Span.EqualTo("if"), Tokens.If)
.Match(Span.EqualTo("elif"), Tokens.Elif)
.Match(Span.EqualTo("else"), Tokens.Else)
.Match(InlineAssembly, Tokens.Asm)
.Match(StringToken, Tokens.StringLiteral)
.Match(Numerics.Integer, Tokens.IntegerLiteral, requireDelimiters: true)
.Match(Numerics.Integer, Tokens.IntegerLiteral, requireDelimiters: true)
.Match(Identifier.CStyle, Tokens.Name, requireDelimiters: true)
.Match(Span.Regex("[a-zA-Z_$]*"), Tokens.GenericName, requireDelimiters: true)
.Match(Span.Regex("[a-zA-Z_][a-z-A-Z_0-9]*"), Tokens.Name, requireDelimiters: true)
.Match(Span.Regex("\\$[a-zA-Z_][a-z-A-Z_0-9]*"), Tokens.GenericName, requireDelimiters: true)
.Build();
}
}
2 changes: 1 addition & 1 deletion src/Bytom.Language/operators.by
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@


function add(var x: $T, var y: $T): $T
function add(var x: $T; var y: $T;): $T
{
return asm {
pop RD0
Expand Down

0 comments on commit 7af2a11

Please sign in to comment.