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:
62
CanonSharp.Tests/ParserTests/ConstDeclarationTests.cs
Normal file
62
CanonSharp.Tests/ParserTests/ConstDeclarationTests.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
297
CanonSharp.Tests/ParserTests/ExpressionParserTests.cs
Normal file
297
CanonSharp.Tests/ParserTests/ExpressionParserTests.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
229
CanonSharp.Tests/ParserTests/ProgramParserTests.cs
Normal file
229
CanonSharp.Tests/ParserTests/ProgramParserTests.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
190
CanonSharp.Tests/ParserTests/StatementParserTests.cs
Normal file
190
CanonSharp.Tests/ParserTests/StatementParserTests.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
83
CanonSharp.Tests/ParserTests/SubprogramParserTests.cs
Normal file
83
CanonSharp.Tests/ParserTests/SubprogramParserTests.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
82
CanonSharp.Tests/ParserTests/VariableDeclarationTests.cs
Normal file
82
CanonSharp.Tests/ParserTests/VariableDeclarationTests.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user