feat: Grammar Parser (#3)

Reviewed-on: https://git.bupt-hpc.cn/jackfiled/CanonSharp/pulls/3
Co-authored-by: jackfiled <xcrenchangjun@outlook.com>
Co-committed-by: jackfiled <xcrenchangjun@outlook.com>
This commit is contained in:
2024-08-18 12:01:27 +08:00
committed by 任昌骏
parent 3ed8bf5d36
commit cf19f8197e
85 changed files with 2340 additions and 413 deletions

View File

@@ -0,0 +1,62 @@
using CanonSharp.Pascal.Parser;
using CanonSharp.Pascal.SyntaxTree;
using CanonSharp.Tests.Utils;
namespace CanonSharp.Tests.ParserTests;
public class ConstDeclarationTests : GrammarParserTestBase
{
[Fact]
public void BooleanConstValueTest()
{
BooleanValueNode node = RunParser<BooleanValueNode>(GrammarParser.ConstValueParser(), "true");
Assert.True(node.Value);
node = RunParser<BooleanValueNode>(GrammarParser.ConstValueParser(), "false");
Assert.False(node.Value);
}
[Fact]
public void CharConstValueTest()
{
CharValueNode node = RunParser<CharValueNode>(GrammarParser.ConstValueParser(), "'a'");
Assert.Equal('a', node.Value);
}
[Fact]
public void NumberConstValueTest()
{
IntegerValueNode integerValueNode = RunParser<IntegerValueNode>(GrammarParser.ConstValueParser(), "250");
Assert.Equal(250, integerValueNode.Value);
FloatValueNode floatValueNode = RunParser<FloatValueNode>(GrammarParser.ConstValueParser(), "100.5");
Assert.Equal(100.5, floatValueNode.Value);
UnaryOperatorNode node = RunParser<UnaryOperatorNode>(GrammarParser.ConstValueParser(), "+250");
Assert.Equal(UnaryOperatorType.Plus, node.OperatorType);
node = RunParser<UnaryOperatorNode>(GrammarParser.ConstValueParser(), "-100.5");
Assert.Equal(UnaryOperatorType.Minus, node.OperatorType);
}
[Fact]
public void ConstDeclarationTest()
{
ConstantNode node = RunParser<ConstantNode>(GrammarParser.ConstDeclarationParser(), "a = true");
Assert.Equal("a", node.Identifier.LiteralValue);
Assert.True(node.Value.Convert<BooleanValueNode>().Value);
}
[Theory]
[InlineData("", 0)]
[InlineData("const INFINITE = 100;", 1)]
[InlineData("const a = true; b = false", 2)]
[InlineData("const code1 = 100.4;code2 = 'a'", 2)]
public void ConstDeclarationsCountTest(string input, int count)
{
BlockNode blockNode = RunParser<BlockNode>(GrammarParser.ConstDeclarationsParser(), input);
List<ConstantNode> constantNodes = blockNode.Statements.Select(node => node.Convert<ConstantNode>()).ToList();
Assert.Equal(count, constantNodes.Count);
}
}

View File

@@ -0,0 +1,297 @@
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.VariableParser(), "temp");
Assert.Equal("temp", node.Identifier.LiteralValue);
}
[Fact]
public void ArrayIdentifierTest()
{
VariableNode node = RunParser<VariableNode>(GrammarParser.VariableParser(), "a[0]");
Assert.Equal("a", node.Identifier.LiteralValue);
Assert.Single(node.Indexers);
Assert.Equal(0, node.Indexers.First().Convert<IntegerValueNode>().Value);
node = RunParser<VariableNode>(GrammarParser.VariableParser(), "a[i + 1]");
Assert.Equal("a", node.Identifier.LiteralValue);
Assert.Single(node.Indexers);
BinaryOperatorNode binaryOperatorNode = node.Indexers.First().Convert<BinaryOperatorNode>();
Assert.Equal(BinaryOperatorType.Add, binaryOperatorNode.OperatorType);
Assert.Equal("i", binaryOperatorNode.Left.Convert<VariableNode>().Identifier.LiteralValue);
Assert.Equal(1, binaryOperatorNode.Right.Convert<IntegerValueNode>().Value);
node = RunParser<VariableNode>(GrammarParser.VariableParser(), "a[b[i + 1] - 10, c]");
Assert.Equal("a", node.Identifier.LiteralValue);
Assert.Equal(2, node.Indexers.Count);
VariableNode secondNode = node.Indexers[1].Convert<VariableNode>();
Assert.Equal("c", secondNode.Identifier.LiteralValue);
Assert.Empty(secondNode.Indexers);
BinaryOperatorNode firstNode = node.Indexers[0].Convert<BinaryOperatorNode>();
Assert.Equal(BinaryOperatorType.Subtract, firstNode.OperatorType);
Assert.Equal(10, firstNode.Right.Convert<IntegerValueNode>().Value);
VariableNode variableNode = firstNode.Left.Convert<VariableNode>();
Assert.Equal("b", variableNode.Identifier.LiteralValue);
Assert.Single(variableNode.Indexers);
binaryOperatorNode = variableNode.Indexers[0].Convert<BinaryOperatorNode>();
Assert.Equal(BinaryOperatorType.Add, binaryOperatorNode.OperatorType);
Assert.Equal("i", binaryOperatorNode.Left.Convert<VariableNode>().Identifier.LiteralValue);
Assert.Equal(1, binaryOperatorNode.Right.Convert<IntegerValueNode>().Value);
}
[Fact]
public void ProcedureCallTest()
{
ProcedureCallNode node = RunParser<ProcedureCallNode>(GrammarParser.FactorParser(), "test(1)");
Assert.Equal("test", node.Identifier.LiteralValue);
Assert.Single(node.Parameters);
Assert.Equal(1, node.Parameters[0].Convert<IntegerValueNode>().Value);
node = RunParser<ProcedureCallNode>(GrammarParser.FactorParser(), "test()");
Assert.Equal("test", node.Identifier.LiteralValue);
Assert.Empty(node.Parameters);
VariableNode variableNode = RunParser<VariableNode>(GrammarParser.FactorParser(), "test");
Assert.Equal("test", variableNode.Identifier.LiteralValue);
Assert.Empty(variableNode.Indexers);
}
[Fact]
public void SingleTermTest()
{
VariableNode node = RunParser<VariableNode>(GrammarParser.TermParser(), "temp");
Assert.Equal("temp", node.Identifier.LiteralValue);
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>().Identifier.LiteralValue);
Assert.Equal(2, leftNode.Right.Convert<IntegerValueNode>().Value);
}
[Fact]
public void SimpleExpressionTest1()
{
VariableNode node = RunParser<VariableNode>(GrammarParser.SimpleExpressionParser(), "temp");
Assert.Equal("temp", node.Identifier.LiteralValue);
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.Identifier.LiteralValue);
}
}

View File

@@ -0,0 +1,229 @@
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.Identifier.LiteralValue);
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);
}
[Fact]
public void ProgramParseTest3()
{
Program program = ProgramParse("""
program main;
const a = 1; b = true;
begin
temp := 1 + 1;
end.
""");
Assert.Equal("main", program.Head.ProgramName.LiteralValue);
List<ConstantNode> constantNodes = program.Body.ConstantDeclarations.Statements
.Select(x => x.Convert<ConstantNode>()).ToList();
Assert.Equal(2, constantNodes.Count);
Assert.Equal("a", constantNodes[0].Identifier.LiteralValue);
Assert.Equal("b", constantNodes[1].Identifier.LiteralValue);
AssignNode assignNode = program.Body.MainBlock.Statements[0].Convert<AssignNode>();
Assert.Equal("temp", assignNode.Variable.Identifier.LiteralValue);
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);
}
[Fact]
public void ProgramParseTest4()
{
Program program = ProgramParse("""
program main;
var a : integer;
begin
a := 1 + 1;
end.
""");
IList<VariableDeclarationNode> variableDeclarationNodes = program.Body.VariableDeclarations.Statements
.Select(x => x.Convert<VariableDeclarationNode>()).ToList();
Assert.Single(variableDeclarationNodes);
Assert.Single(variableDeclarationNodes.First().Identifiers);
Assert.Equal("a", variableDeclarationNodes.First().Identifiers.First().LiteralValue);
}
[Theory]
[InlineData("""
program DoNothing;
begin
end.
""")]
[InlineData("""
program Add;
var a : Integer;
begin
a := 1 + 1
end.
""")]
[InlineData("""
program varTest;
var a : integer;
begin
a := 9 div 1;
end.
""")]
[InlineData("""
program main;
var a : integer;
begin
a := 1 + +1;
a := 1 - -1;
a := 1 + -1;
a := 1 - +1;
end.
""")]
[InlineData("""
program main;
const a = true; b = false;
var c, d : boolean;
begin
c := true;
d := false;
end.
""")]
[InlineData("""
program arrayTest;
var a : array [0..10] of integer;
begin
a[0] := 1;
end.
""")]
[InlineData("""
program arrayTest;
var a : array [10..100, 0..10] of integer;
begin
a[10,0] := 1;
end.
""")]
[InlineData("""
program main;
begin
begin
end
end.
""")]
[InlineData("""
program main;
var i : integer;
begin
while i < 10 do
i := i + 1;
end.
""")]
[InlineData("""
program main;
procedure test;
begin
end;
begin
end.
""")]
[InlineData("""
program main;
function test(a, b : integer) : integer;
begin
test := 1;
end;
begin
end.
""")]
[InlineData("""
program main;
var i : integer;
begin
for i := 1 to 100 do
begin
doSomething(i);
end;
end.
""")]
[InlineData("""
program main;
begin
if 1 = 2 then
begin
test1;
test2 := a;
end
else
begin
doSomething;
end;
end.
""")]
[InlineData("""
program main;
var a : integer;
function test : integer;
begin
end;
begin
test;
a := test;
test();
a := test();
end.
""")]
[InlineData("""
program main;
procedure test();
begin
end;
begin
test();
end.
""")]
[InlineData("""
program main;
begin
test
end.
""")]
public void ProgramParseTest(string input)
{
ProgramParse(input);
}
}

View File

@@ -0,0 +1,190 @@
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.Identifier.LiteralValue);
Assert.Equal(1, node.Expression.Convert<IntegerValueNode>().Value);
}
[Fact]
public void IfTest1()
{
IfNode node = RunParser<IfNode>(GrammarParser.IfParser(), """
if i = 1 then
a := a + 1
else
a := a + 2
""");
Assert.NotNull(node.ElseStatement);
BinaryOperatorNode condition = node.Condition.Convert<BinaryOperatorNode>();
Assert.Equal(BinaryOperatorType.Equal, condition.OperatorType);
AssignNode statement = node.Statement.Convert<AssignNode>();
Assert.Equal("a", statement.Variable.Identifier.LiteralValue);
AssignNode elseStatement = node.Statement.Convert<AssignNode>();
Assert.Equal("a", elseStatement.Variable.Identifier.LiteralValue);
}
[Fact]
public void IfTest2()
{
IfNode node = RunParser<IfNode>(GrammarParser.IfParser(), """
if i = 1 then
if i = 2 then
a := a + 1
else
a := a + 2
""");
Assert.Null(node.ElseStatement);
IfNode subIfNode = node.Statement.Convert<IfNode>();
Assert.NotNull(subIfNode.ElseStatement);
}
[Fact]
public void ForTest1()
{
ForNode node = RunParser<ForNode>(GrammarParser.ForParser(), """
for i := 1 to 10 do
a := a + i
""");
Assert.Equal("i", node.Identifier.LiteralValue);
Assert.Equal(1, node.LeftCondition.Convert<IntegerValueNode>().Value);
Assert.Equal(10, node.RightCondition.Convert<IntegerValueNode>().Value);
AssignNode assignNode = node.Statement.Convert<AssignNode>();
Assert.Equal("a", assignNode.Variable.Identifier.LiteralValue);
}
[Fact]
public void WhileTest1()
{
WhileNode node = RunParser<WhileNode>(GrammarParser.WhileParser(), """
while c >= 1 do
a := a + 1;
""");
BinaryOperatorNode binaryOperatorNode = node.Condition.Convert<BinaryOperatorNode>();
Assert.Equal(BinaryOperatorType.GreaterEqual, binaryOperatorNode.OperatorType);
AssignNode assignNode = node.Statement.Convert<AssignNode>();
Assert.Equal("a", assignNode.Variable.Identifier.LiteralValue);
}
[Fact]
public void ProcedureCallTest1()
{
ProcedureCallNode node = RunParser<ProcedureCallNode>(GrammarParser.ProcedureCallParser(), "test()");
Assert.Equal("test", node.Identifier.LiteralValue);
Assert.Empty(node.Parameters);
node = RunParser<ProcedureCallNode>(GrammarParser.ProcedureCallParser(), "test");
Assert.Equal("test", node.Identifier.LiteralValue);
Assert.Empty(node.Parameters);
}
[Fact]
public void ProcedureCallTest2()
{
ProcedureCallNode node = RunParser<ProcedureCallNode>(GrammarParser.ProcedureCallParser(),
"test(1 + 1, true)");
Assert.Equal(2, node.Parameters.Count);
BinaryOperatorNode firstParameter = node.Parameters[0].Convert<BinaryOperatorNode>();
Assert.Equal(BinaryOperatorType.Add, firstParameter.OperatorType);
BooleanValueNode secondParameter = node.Parameters[1].Convert<BooleanValueNode>();
Assert.True(secondParameter.Value);
}
[Fact]
public void ProcedureCallTest3()
{
ProcedureCallNode node =
RunParser<ProcedureCallNode>(GrammarParser.ProcedureCallParser(), "test(1 * + 1, test2[0])");
Assert.Equal(2, node.Parameters.Count);
VariableNode secondParameter = node.Parameters[1].Convert<VariableNode>();
Assert.Equal("test2", secondParameter.Identifier.LiteralValue);
Assert.Single(secondParameter.Indexers);
}
[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.Identifier.LiteralValue);
assignNode = node.Statements[1].Convert<AssignNode>();
Assert.Equal("flag", assignNode.Variable.Identifier.LiteralValue);
}
[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.Identifier.LiteralValue);
assignNode = node.Statements[1].Convert<AssignNode>();
Assert.Equal("flag", assignNode.Variable.Identifier.LiteralValue);
}
}

View File

@@ -0,0 +1,83 @@
using CanonSharp.Pascal.Parser;
using CanonSharp.Pascal.SyntaxTree;
using CanonSharp.Tests.Utils;
namespace CanonSharp.Tests.ParserTests;
public class SubprogramParserTests : GrammarParserTestBase
{
[Fact]
public void ParameterTest1()
{
List<Parameter> parameters = RunParser<Parameter>(GrammarParser.ParameterParser(), "a ,b : integer");
Assert.Equal(2, parameters.Count);
Assert.All(parameters, p =>
{
Assert.False(p.IsReference);
Assert.Equal("integer", p.TypeNode.Convert<TypeNode>().TypeToken.LiteralValue);
});
parameters = RunParser<Parameter>(GrammarParser.ParameterParser(), "var a, b,c: real");
Assert.Equal(3, parameters.Count);
Assert.All(parameters, p =>
{
Assert.True(p.IsReference);
Assert.Equal("real", p.TypeNode.Convert<TypeNode>().TypeToken.LiteralValue);
});
}
[Theory]
[InlineData("(var a, b : integer; c, d : real)", 4)]
[InlineData("(a : boolean; var c, d, e : char)", 4)]
[InlineData("(a : integer)", 1)]
[InlineData("(var b ,c : real)", 2)]
public void FormalParameterTest(string input, int count)
{
List<Parameter> parameters = RunParser<Parameter>(GrammarParser.FormalParameterParser(), input);
Assert.Equal(count, parameters.Count);
}
[Theory]
[InlineData("procedure test", 0)]
[InlineData("procedure test()", 0)]
[InlineData("procedure test(a : integer; var b : real)", 2)]
[InlineData("procedure test(a,b, c : real; var e, f : boolean)", 5)]
[InlineData("function test : integer", 0)]
[InlineData("function test() : real", 0)]
[InlineData("function test(a : integer; var b : real) : boolean", 2)]
[InlineData("function test(a,b, c : real; var e, f : boolean) : char", 5)]
public void SubprogramHeadTest(string input, int count)
{
SubprogramHead head = RunParser<SubprogramHead>(GrammarParser.SubprogramHeadParser(), input);
Assert.Equal(count, head.Parameters.Count);
}
[Fact]
public void SubprogramHeadTest1()
{
SubprogramHead head =
RunParser<SubprogramHead>(GrammarParser.SubprogramHeadParser(), "function test(a : integer) : real");
Assert.Equal("test", head.Identifier.LiteralValue);
Assert.Single(head.Parameters);
Assert.NotNull(head.TypeToken);
Assert.Equal("real", head.TypeToken.Convert<TypeNode>().TypeToken.LiteralValue);
}
[Fact]
public void SubprogramBodyTest1()
{
SubprogramBody body = RunParser<SubprogramBody>(GrammarParser.SubprogramBodyParser(), """
const a = 3;
var c, d : integer; e, f :real;
begin
c := a + d;
end
""");
Assert.Single(body.ConstDeclarations.Statements);
Assert.Equal(2, body.VariableDeclarations.Statements.Count);
Assert.Equal(1, body.MainBlock.Statements.Count);
}
}

View File

@@ -0,0 +1,82 @@
using CanonSharp.Pascal.Parser;
using CanonSharp.Pascal.SyntaxTree;
using CanonSharp.Tests.Utils;
namespace CanonSharp.Tests.ParserTests;
public class VariableDeclarationTests : GrammarParserTestBase
{
[Theory]
[InlineData("boolean", "boolean")]
[InlineData("integer", "integer")]
[InlineData("char", "char")]
[InlineData("real", "real")]
public void BasicTypeParseTest(string input, string value)
{
TypeNode node = RunParser<TypeNode>(GrammarParser.TypeParser(), input);
Assert.Equal(value, node.TypeToken.LiteralValue);
}
[Fact]
public void ArrayTypeParseTest()
{
TypeNode node = RunParser<TypeNode>(GrammarParser.ArrayTypeParser(), "array [0..9] of integer");
Assert.Equal("integer", node.TypeToken.LiteralValue);
Assert.Single(node.ArrayRanges);
Assert.Equal(new ArrayRange(0, 9), node.ArrayRanges.First());
node = RunParser<TypeNode>(GrammarParser.ArrayTypeParser(), "array [0..10,0..10] of char");
Assert.Equal("char", node.TypeToken.LiteralValue);
Assert.Equal(2, node.ArrayRanges.Count);
Assert.Equal(new ArrayRange(0, 10), node.ArrayRanges[0]);
Assert.Equal(new ArrayRange(0, 10), node.ArrayRanges[1]);
}
[Fact]
public void VariableDeclarationTest()
{
VariableDeclarationNode node = RunParser<VariableDeclarationNode>(GrammarParser.VariableDeclarationParser(),
"a : integer");
Assert.Contains(node.Identifiers, token => token.LiteralValue == "a");
Assert.Equal("integer", node.TypeNode.TypeToken.LiteralValue);
node = RunParser<VariableDeclarationNode>(GrammarParser.VariableDeclarationParser(),
"a, b, c : boolean");
Assert.Contains(node.Identifiers, token => token.LiteralValue == "a");
Assert.Contains(node.Identifiers, token => token.LiteralValue == "b");
Assert.Contains(node.Identifiers, token => token.LiteralValue == "c");
Assert.Equal("boolean", node.TypeNode.TypeToken.LiteralValue);
}
[Fact]
public void ArrayVariableDeclarationTest()
{
VariableDeclarationNode node = RunParser<VariableDeclarationNode>(GrammarParser.VariableDeclarationParser(),
"test_array: array [0..9,10..20] of real");
Assert.Single(node.Identifiers);
Assert.Contains(node.Identifiers, token => token.LiteralValue == "test_array");
Assert.Equal("real", node.TypeNode.TypeToken.LiteralValue);
Assert.Equal(2, node.TypeNode.ArrayRanges.Count);
Assert.Equal(new ArrayRange(0, 9), node.TypeNode.ArrayRanges[0]);
Assert.Equal(new ArrayRange(10, 20), node.TypeNode.ArrayRanges[1]);
}
[Theory]
[InlineData("var a : integer;", 1)]
[InlineData("var a : integer; b : boolean;", 2)]
[InlineData("var a : integer; b,c : boolean;" +
"d : char", 3)]
[InlineData("var a,d,e : integer; b : boolean; c: real;", 3)]
[InlineData("var a : array [0..5] of integer", 1)]
[InlineData("var a,b,c: array [0..9,10..20] of integer; c,d : boolean", 2)]
public void VariableDeclarationsTest(string input, int count)
{
BlockNode node = RunParser<BlockNode>(GrammarParser.VariableDeclarationsParser(), input);
Assert.Equal(count, node.Statements.Count);
}
}