add: basic grammar parser including expression and program.

This commit is contained in:
2024-08-15 16:18:32 +08:00
parent fee62ec289
commit bdcc59a2ab
19 changed files with 829 additions and 0 deletions

View File

@@ -0,0 +1,245 @@
using CanonSharp.Pascal.Parser;
using CanonSharp.Pascal.SyntaxTree;
using CanonSharp.Tests.Utils;
namespace CanonSharp.Tests.ParserTests;
public sealed class ExpressionParserTests : GrammarParserTestBase
{
[Fact]
public void BoolTest()
{
BooleanValueNode node = RunParser<BooleanValueNode>(GrammarParser.FactorParser(), "false");
Assert.False(node.Value);
node = RunParser<BooleanValueNode>(GrammarParser.FactorParser(), "true");
Assert.True(node.Value);
}
[Fact]
public void NumberTest()
{
IntegerValueNode integerValueNode = RunParser<IntegerValueNode>(GrammarParser.FactorParser(), "123456");
Assert.Equal(123456, integerValueNode.Value);
FloatValueNode floatValueNode = RunParser<FloatValueNode>(GrammarParser.FactorParser(), "123.456");
Assert.Equal(123.456, floatValueNode.Value);
}
[Fact]
public void UnaryOperatorTest()
{
UnaryOperatorNode node = RunParser<UnaryOperatorNode>(GrammarParser.FactorParser(), "- 123");
Assert.Equal(UnaryOperatorType.Minus, node.OperatorType);
Assert.Equal(123, node.Node.Convert<IntegerValueNode>().Value);
node = RunParser<UnaryOperatorNode>(GrammarParser.FactorParser(), "+ 100.5");
Assert.Equal(UnaryOperatorType.Plus, node.OperatorType);
Assert.Equal(100.5, node.Node.Convert<FloatValueNode>().Value);
}
[Fact]
public void IdentifierTest()
{
VariableNode node = RunParser<VariableNode>(GrammarParser.FactorParser(), "temp");
Assert.Equal("temp", node.IdentifierName);
}
[Fact]
public void SingleTermTest()
{
VariableNode node = RunParser<VariableNode>(GrammarParser.TermParser(), "temp");
Assert.Equal("temp", node.IdentifierName);
UnaryOperatorNode unaryOperatorNode = RunParser<UnaryOperatorNode>(GrammarParser.TermParser(), "- 123");
Assert.Equal(UnaryOperatorType.Minus, unaryOperatorNode.OperatorType);
Assert.Equal(123, unaryOperatorNode.Node.Convert<IntegerValueNode>().Value);
unaryOperatorNode = RunParser<UnaryOperatorNode>(GrammarParser.TermParser(), "+ 100.5");
Assert.Equal(UnaryOperatorType.Plus, unaryOperatorNode.OperatorType);
Assert.Equal(100.5, unaryOperatorNode.Node.Convert<FloatValueNode>().Value);
}
[Fact]
public void MultiplyTermTest1()
{
BinaryOperatorNode node = RunParser<BinaryOperatorNode>(GrammarParser.TermParser(), "10 / 2");
Assert.Equal(BinaryOperatorType.Divide, node.OperatorType);
Assert.Equal(10, node.Left.Convert<IntegerValueNode>().Value);
Assert.Equal(2, node.Right.Convert<IntegerValueNode>().Value);
}
[Fact]
public void MultiplyTermTest2()
{
BinaryOperatorNode node = RunParser<BinaryOperatorNode>(GrammarParser.TermParser(), "10 div 2");
Assert.Equal(BinaryOperatorType.IntegerDivide, node.OperatorType);
Assert.Equal(10, node.Left.Convert<IntegerValueNode>().Value);
Assert.Equal(2, node.Right.Convert<IntegerValueNode>().Value);
}
[Fact]
public void MultiplyTermTest3()
{
BinaryOperatorNode node = RunParser<BinaryOperatorNode>(GrammarParser.TermParser(), "temp * 2 div 3");
Assert.Equal(BinaryOperatorType.IntegerDivide, node.OperatorType);
Assert.Equal(3, node.Right.Convert<IntegerValueNode>().Value);
BinaryOperatorNode leftNode = node.Left.Convert<BinaryOperatorNode>();
Assert.Equal(BinaryOperatorType.Multiply, leftNode.OperatorType);
Assert.Equal("temp", leftNode.Left.Convert<VariableNode>().IdentifierName);
Assert.Equal(2, leftNode.Right.Convert<IntegerValueNode>().Value);
}
[Fact]
public void SimpleExpressionTest1()
{
VariableNode node = RunParser<VariableNode>(GrammarParser.SimpleExpressionParser(), "temp");
Assert.Equal("temp", node.IdentifierName);
UnaryOperatorNode unaryOperatorNode =
RunParser<UnaryOperatorNode>(GrammarParser.SimpleExpressionParser(), "- 123");
Assert.Equal(UnaryOperatorType.Minus, unaryOperatorNode.OperatorType);
Assert.Equal(123, unaryOperatorNode.Node.Convert<IntegerValueNode>().Value);
unaryOperatorNode = RunParser<UnaryOperatorNode>(GrammarParser.SimpleExpressionParser(), "+ 100.5");
Assert.Equal(UnaryOperatorType.Plus, unaryOperatorNode.OperatorType);
Assert.Equal(100.5, unaryOperatorNode.Node.Convert<FloatValueNode>().Value);
}
[Fact]
public void SimpleExpressionTest2()
{
BinaryOperatorNode node = RunParser<BinaryOperatorNode>(GrammarParser.SimpleExpressionParser(), "1 + 1");
Assert.Equal(BinaryOperatorType.Add, node.OperatorType);
Assert.Equal(1, node.Left.Convert<IntegerValueNode>().Value);
Assert.Equal(1, node.Right.Convert<IntegerValueNode>().Value);
node = RunParser<BinaryOperatorNode>(GrammarParser.SimpleExpressionParser(), "1 + 1 - 2");
Assert.Equal(BinaryOperatorType.Subtract, node.OperatorType);
Assert.Equal(2, node.Right.Convert<IntegerValueNode>().Value);
BinaryOperatorNode leftNode = node.Left.Convert<BinaryOperatorNode>();
Assert.Equal(BinaryOperatorType.Add, leftNode.OperatorType);
Assert.Equal(1, leftNode.Left.Convert<IntegerValueNode>().Value);
Assert.Equal(1, leftNode.Right.Convert<IntegerValueNode>().Value);
}
[Fact]
public void SimpleExpressionTest3()
{
BinaryOperatorNode node = RunParser<BinaryOperatorNode>(GrammarParser.SimpleExpressionParser(), "1 - 2 * 5");
Assert.Equal(BinaryOperatorType.Subtract, node.OperatorType);
Assert.Equal(1, node.Left.Convert<IntegerValueNode>().Value);
BinaryOperatorNode rightNode = node.Right.Convert<BinaryOperatorNode>();
Assert.Equal(BinaryOperatorType.Multiply, rightNode.OperatorType);
Assert.Equal(2, rightNode.Left.Convert<IntegerValueNode>().Value);
Assert.Equal(5, rightNode.Right.Convert<IntegerValueNode>().Value);
}
[Fact]
public void SimpleExpressionTest4()
{
BinaryOperatorNode node = RunParser<BinaryOperatorNode>(GrammarParser.SimpleExpressionParser(), "1 + +1");
Assert.Equal(BinaryOperatorType.Add, node.OperatorType);
Assert.Equal(1, node.Left.Convert<IntegerValueNode>().Value);
UnaryOperatorNode unaryOperatorNode = node.Right.Convert<UnaryOperatorNode>();
Assert.Equal(UnaryOperatorType.Plus, unaryOperatorNode.OperatorType);
Assert.Equal(1, unaryOperatorNode.Node.Convert<IntegerValueNode>().Value);
node = RunParser<BinaryOperatorNode>(GrammarParser.SimpleExpressionParser(), "1 - -1");
Assert.Equal(BinaryOperatorType.Subtract, node.OperatorType);
Assert.Equal(1, node.Left.Convert<IntegerValueNode>().Value);
unaryOperatorNode = node.Right.Convert<UnaryOperatorNode>();
Assert.Equal(UnaryOperatorType.Minus, unaryOperatorNode.OperatorType);
Assert.Equal(1, unaryOperatorNode.Node.Convert<IntegerValueNode>().Value);
node = RunParser<BinaryOperatorNode>(GrammarParser.SimpleExpressionParser(), "+ 1 - - 1");
Assert.Equal(BinaryOperatorType.Subtract, node.OperatorType);
unaryOperatorNode = node.Left.Convert<UnaryOperatorNode>();
Assert.Equal(UnaryOperatorType.Plus, unaryOperatorNode.OperatorType);
Assert.Equal(1, unaryOperatorNode.Node.Convert<IntegerValueNode>().Value);
unaryOperatorNode = node.Right.Convert<UnaryOperatorNode>();
Assert.Equal(UnaryOperatorType.Minus, unaryOperatorNode.OperatorType);
Assert.Equal(1, unaryOperatorNode.Node.Convert<IntegerValueNode>().Value);
}
[Fact]
public void SimpleExpressionTest5()
{
BinaryOperatorNode node = RunParser<BinaryOperatorNode>(GrammarParser.SimpleExpressionParser(),
"true and temp or temp and false");
Assert.Equal(BinaryOperatorType.Or, node.OperatorType);
BinaryOperatorNode left = node.Left.Convert<BinaryOperatorNode>();
Assert.Equal(BinaryOperatorType.And, left.OperatorType);
BinaryOperatorNode right = node.Right.Convert<BinaryOperatorNode>();
Assert.Equal(BinaryOperatorType.And, right.OperatorType);
}
[Fact]
public void ExpressionTest1()
{
BinaryOperatorNode node = RunParser<BinaryOperatorNode>(GrammarParser.ExpressionParser(),
"true and temp or temp and false");
Assert.Equal(BinaryOperatorType.Or, node.OperatorType);
BinaryOperatorNode left = node.Left.Convert<BinaryOperatorNode>();
Assert.Equal(BinaryOperatorType.And, left.OperatorType);
BinaryOperatorNode right = node.Right.Convert<BinaryOperatorNode>();
Assert.Equal(BinaryOperatorType.And, right.OperatorType);
}
[Fact]
public void ExpressionTest2()
{
BinaryOperatorNode node = RunParser<BinaryOperatorNode>(GrammarParser.ExpressionParser(), "2 >= 1");
Assert.Equal(BinaryOperatorType.GreaterEqual, node.OperatorType);
Assert.Equal(2, node.Left.Convert<IntegerValueNode>().Value);
Assert.Equal(1, node.Right.Convert<IntegerValueNode>().Value);
}
[Fact]
public void ExpressionTest3()
{
BinaryOperatorNode node = RunParser<BinaryOperatorNode>(GrammarParser.ExpressionParser(), "(1 + 1) * 2");
Assert.Equal(BinaryOperatorType.Multiply, node.OperatorType);
Assert.Equal(2, node.Right.Convert<IntegerValueNode>().Value);
node = node.Left.Convert<BinaryOperatorNode>();
Assert.Equal(BinaryOperatorType.Add, node.OperatorType);
Assert.Equal(1, node.Left.Convert<IntegerValueNode>().Value);
Assert.Equal(1, node.Right.Convert<IntegerValueNode>().Value);
}
[Fact]
public void ExpressionsTest1()
{
List<BinaryOperatorNode> nodes =
RunParser<BinaryOperatorNode>(GrammarParser.ExpressionsParser(), "1 + 1, 2 * 3");
Assert.Equal(BinaryOperatorType.Add, nodes[0].OperatorType);
Assert.Equal(BinaryOperatorType.Multiply, nodes[1].OperatorType);
}
[Fact]
public void VariableTest1()
{
VariableNode node = RunParser<VariableNode>(GrammarParser.VariableParser(), "temp");
Assert.Equal("temp", node.IdentifierName);
}
}

View File

@@ -0,0 +1,41 @@
using CanonSharp.Pascal.SyntaxTree;
using CanonSharp.Tests.Utils;
namespace CanonSharp.Tests.ParserTests;
public class ProgramParserTests : GrammarParserTestBase
{
[Fact]
public void ProgramParseTest1()
{
Program program = ProgramParse("""
program main;
begin
end.
""");
Assert.Equal("main", program.Head.ProgramName.LiteralValue);
Assert.Empty(program.Body.MainBlock.Statements);
}
[Fact]
public void ProgramParseTest2()
{
Program program = ProgramParse("""
program main;
begin
temp := 1 + 1;
end.
""");
Assert.Equal("main", program.Head.ProgramName.LiteralValue);
AssignNode assignNode = program.Body.MainBlock.Statements[0].Convert<AssignNode>();
Assert.Equal("temp", assignNode.Variable.IdentifierName);
BinaryOperatorNode binaryOperatorNode = assignNode.Expression.Convert<BinaryOperatorNode>();
Assert.Equal(BinaryOperatorType.Add, binaryOperatorNode.OperatorType);
Assert.Equal(1, binaryOperatorNode.Left.Convert<IntegerValueNode>().Value);
Assert.Equal(1, binaryOperatorNode.Right.Convert<IntegerValueNode>().Value);
}
}

View File

@@ -0,0 +1,82 @@
using CanonSharp.Pascal.Parser;
using CanonSharp.Pascal.SyntaxTree;
using CanonSharp.Tests.Utils;
namespace CanonSharp.Tests.ParserTests;
public class StatementParserTests : GrammarParserTestBase
{
[Fact]
public void StatementTest1()
{
AssignNode node = RunParser<AssignNode>(GrammarParser.StatementParser(), "temp := 1");
Assert.Equal("temp", node.Variable.IdentifierName);
Assert.Equal(1, node.Expression.Convert<IntegerValueNode>().Value);
}
[Theory]
[InlineData("""
begin
temp := 1 + 1;
flag := true and false;
end
""")]
[InlineData("""
begin
temp := 1 + 1;
flag := true and false
end
""")]
public void CompoundStatementTest1(string input)
{
BlockNode node = RunParser<BlockNode>(GrammarParser.CompoundStatementParser(), input);
Assert.Equal(2, node.Statements.Count);
AssignNode assignNode = node.Statements[0].Convert<AssignNode>();
Assert.Equal("temp", assignNode.Variable.IdentifierName);
assignNode = node.Statements[1].Convert<AssignNode>();
Assert.Equal("flag", assignNode.Variable.IdentifierName);
}
[Fact]
public void CompoundStatementTest2()
{
BlockNode node = RunParser<BlockNode>(GrammarParser.CompoundStatementParser(), "begin end");
Assert.Empty(node.Statements);
}
[Fact]
public void ProgramHeadTest1()
{
ProgramHead head = RunParser<ProgramHead>(GrammarParser.ProgramHeadParser(), "program main");
Assert.Equal("main", head.ProgramName.LiteralValue);
}
[Theory]
[InlineData("""
begin
temp := 1 + 1;
flag := true and false;
end
""")]
[InlineData("""
begin
temp := 1 + 1;
flag := true and false
end
""")]
public void ProgramBodyTest1(string input)
{
BlockNode node = RunParser<ProgramBody>(GrammarParser.ProgramBodyParser(), input).MainBlock;
Assert.Equal(2, node.Statements.Count);
AssignNode assignNode = node.Statements[0].Convert<AssignNode>();
Assert.Equal("temp", assignNode.Variable.IdentifierName);
assignNode = node.Statements[1].Convert<AssignNode>();
Assert.Equal("flag", assignNode.Variable.IdentifierName);
}
}