Compare commits
No commits in common. "5acae7d4891efc2f75e0b899c3a617a94a576f5c" and "97f9fb9ec3d079ebd36910575c117f548ac13281" have entirely different histories.
5acae7d489
...
97f9fb9ec3
|
@ -32,13 +32,6 @@ public sealed class GrammarParser : GrammarParserBuilder
|
||||||
from _2 in Delimiter(")")
|
from _2 in Delimiter(")")
|
||||||
select node;
|
select node;
|
||||||
|
|
||||||
IParser<LexicalToken, SyntaxNodeBase> procedureCallParser =
|
|
||||||
from identifier in IdentifierParser()
|
|
||||||
from _ in Delimiter("(")
|
|
||||||
from expressions in ExpressionParser().SeparatedBy(Delimiter(","))
|
|
||||||
from _1 in Delimiter(")")
|
|
||||||
select new ProcedureCallNode(identifier, expressions);
|
|
||||||
|
|
||||||
return Choice(
|
return Choice(
|
||||||
TrueParser(),
|
TrueParser(),
|
||||||
FalseParser(),
|
FalseParser(),
|
||||||
|
@ -46,7 +39,6 @@ public sealed class GrammarParser : GrammarParserBuilder
|
||||||
minusParser,
|
minusParser,
|
||||||
plusParser,
|
plusParser,
|
||||||
notParser,
|
notParser,
|
||||||
procedureCallParser,
|
|
||||||
VariableParser(),
|
VariableParser(),
|
||||||
parenthesisParser
|
parenthesisParser
|
||||||
);
|
);
|
||||||
|
@ -158,70 +150,13 @@ public sealed class GrammarParser : GrammarParserBuilder
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IParser<LexicalToken, IfNode> IfParser()
|
|
||||||
{
|
|
||||||
IParser<LexicalToken, IfNode> commonPart = from _ in Keyword("if")
|
|
||||||
from condition in ExpressionParser()
|
|
||||||
from _1 in Keyword("then")
|
|
||||||
from statement in StatementParser()
|
|
||||||
select new IfNode(condition, statement);
|
|
||||||
|
|
||||||
return Choice(
|
|
||||||
from common in commonPart
|
|
||||||
from _ in Keyword("else")
|
|
||||||
from elseStatement in StatementParser()
|
|
||||||
select new IfNode(common.Condition, common.Statement, elseStatement),
|
|
||||||
commonPart
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IParser<LexicalToken, ForNode> ForParser()
|
|
||||||
{
|
|
||||||
return from _ in Keyword("for")
|
|
||||||
from identifier in IdentifierParser()
|
|
||||||
from _1 in Operator(":=")
|
|
||||||
from left in ExpressionParser()
|
|
||||||
from _2 in Keyword("to")
|
|
||||||
from right in ExpressionParser()
|
|
||||||
from _3 in Keyword("do")
|
|
||||||
from statement in StatementParser()
|
|
||||||
select new ForNode(identifier, left, right, statement);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IParser<LexicalToken, WhileNode> WhileParser()
|
|
||||||
{
|
|
||||||
return from _ in Keyword("while")
|
|
||||||
from condition in ExpressionParser()
|
|
||||||
from _1 in Keyword("do")
|
|
||||||
from statement in StatementParser()
|
|
||||||
select new WhileNode(condition, statement);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IParser<LexicalToken, ProcedureCallNode> ProcedureCallParser()
|
|
||||||
{
|
|
||||||
return Choice(
|
|
||||||
from identifier in IdentifierParser()
|
|
||||||
from _ in Delimiter("(")
|
|
||||||
from expressions in ExpressionParser().SeparatedBy(Delimiter(","))
|
|
||||||
from _1 in Delimiter(")")
|
|
||||||
select new ProcedureCallNode(identifier, expressions),
|
|
||||||
from identifier in IdentifierParser()
|
|
||||||
select new ProcedureCallNode(identifier, [])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IParser<LexicalToken, SyntaxNodeBase> StatementParser()
|
public static IParser<LexicalToken, SyntaxNodeBase> StatementParser()
|
||||||
{
|
{
|
||||||
return Choice<LexicalToken, SyntaxNodeBase>(
|
return Choice(
|
||||||
from variable in VariableParser()
|
from variable in VariableParser()
|
||||||
from _ in Operator(":=")
|
from _ in Operator(":=")
|
||||||
from expression in ExpressionParser()
|
from expression in ExpressionParser()
|
||||||
select new AssignNode(variable, expression),
|
select new AssignNode(variable, expression)
|
||||||
ProcedureCallParser(),
|
|
||||||
IfParser(),
|
|
||||||
ForParser(),
|
|
||||||
WhileParser(),
|
|
||||||
CompoundStatementParser()
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,7 +193,7 @@ public sealed class GrammarParser : GrammarParserBuilder
|
||||||
select new ConstantNode(identifier, node);
|
select new ConstantNode(identifier, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IParser<LexicalToken, BlockNode> ConstDeclarationsParser()
|
public static IParser<LexicalToken, SyntaxNodeBase> ConstDeclarationsParser()
|
||||||
{
|
{
|
||||||
return (from _ in Keyword("const")
|
return (from _ in Keyword("const")
|
||||||
from tokens in ConstDeclarationParser().SeparatedOrEndBy1(Delimiter(";"))
|
from tokens in ConstDeclarationParser().SeparatedOrEndBy1(Delimiter(";"))
|
||||||
|
@ -305,73 +240,12 @@ public sealed class GrammarParser : GrammarParserBuilder
|
||||||
select new BlockNode(nodes)).Try(new BlockNode([]));
|
select new BlockNode(nodes)).Try(new BlockNode([]));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IParser<LexicalToken, IEnumerable<Parameter>> ParameterParser()
|
|
||||||
{
|
|
||||||
return Choice(
|
|
||||||
from _ in Keyword("var")
|
|
||||||
from tokens in IdentifierParser().SeparatedBy1(Delimiter(","))
|
|
||||||
from _1 in Delimiter(":")
|
|
||||||
from typeToken in TypeParser()
|
|
||||||
select tokens.Select(x => new Parameter(true, x, typeToken)),
|
|
||||||
from tokens in IdentifierParser().SeparatedBy1(Delimiter(","))
|
|
||||||
from _ in Delimiter(":")
|
|
||||||
from typeToken in TypeParser()
|
|
||||||
select tokens.Select(x => new Parameter(false, x, typeToken))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IParser<LexicalToken, IEnumerable<Parameter>> FormalParameterParser()
|
|
||||||
{
|
|
||||||
return (from _ in Delimiter("(")
|
|
||||||
from parameters in ParameterParser().SeparatedBy(Delimiter(";"))
|
|
||||||
from _1 in Delimiter(")")
|
|
||||||
select parameters.Aggregate(new List<Parameter>(), (result, array) =>
|
|
||||||
{
|
|
||||||
result.AddRange(array);
|
|
||||||
return result;
|
|
||||||
})).Try([]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IParser<LexicalToken, SubprogramHead> SubprogramHeadParser()
|
|
||||||
{
|
|
||||||
return Choice(
|
|
||||||
from _ in Keyword("procedure")
|
|
||||||
from identifier in IdentifierParser()
|
|
||||||
from parameters in FormalParameterParser()
|
|
||||||
select new SubprogramHead(identifier, parameters),
|
|
||||||
from _ in Keyword("function")
|
|
||||||
from identifier in IdentifierParser()
|
|
||||||
from parameters in FormalParameterParser()
|
|
||||||
from _1 in Delimiter(":")
|
|
||||||
from typeToken in TypeParser()
|
|
||||||
select new SubprogramHead(identifier, parameters, typeToken)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IParser<LexicalToken, SubprogramBody> SubprogramBodyParser()
|
|
||||||
{
|
|
||||||
return from constant in ConstDeclarationsParser()
|
|
||||||
from variables in VariableDeclarationsParser()
|
|
||||||
from block in CompoundStatementParser()
|
|
||||||
select new SubprogramBody(constant, variables, block);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IParser<LexicalToken, Subprogram> SubprogramParser()
|
|
||||||
{
|
|
||||||
return from head in SubprogramHeadParser()
|
|
||||||
from _ in Delimiter(";")
|
|
||||||
from body in SubprogramBodyParser()
|
|
||||||
select new Subprogram(head, body);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IParser<LexicalToken, ProgramBody> ProgramBodyParser()
|
public static IParser<LexicalToken, ProgramBody> ProgramBodyParser()
|
||||||
{
|
{
|
||||||
return from constant in ConstDeclarationsParser()
|
return from constant in ConstDeclarationsParser()
|
||||||
from variables in VariableDeclarationsParser()
|
from variables in VariableDeclarationsParser()
|
||||||
from subprograms in SubprogramParser().SeparatedOrEndBy(Delimiter(";"))
|
|
||||||
.Map(x => new BlockNode(x))
|
|
||||||
from block in CompoundStatementParser()
|
from block in CompoundStatementParser()
|
||||||
select new ProgramBody(constant, variables, subprograms, block);
|
select new ProgramBody(constant.Convert<BlockNode>(), variables, block);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IParser<LexicalToken, ProgramHead> ProgramHeadParser()
|
public static IParser<LexicalToken, ProgramHead> ProgramHeadParser()
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
using CanonSharp.Pascal.Scanner;
|
|
||||||
|
|
||||||
namespace CanonSharp.Pascal.SyntaxTree;
|
|
||||||
|
|
||||||
public sealed class ForNode(
|
|
||||||
LexicalToken identifier,
|
|
||||||
SyntaxNodeBase leftCondition,
|
|
||||||
SyntaxNodeBase rightCondition,
|
|
||||||
SyntaxNodeBase statement) : SyntaxNodeBase
|
|
||||||
{
|
|
||||||
public override SyntaxNodeType NodeType => SyntaxNodeType.For;
|
|
||||||
|
|
||||||
public LexicalToken Identifier => identifier;
|
|
||||||
|
|
||||||
public SyntaxNodeBase LeftCondition => leftCondition;
|
|
||||||
|
|
||||||
public SyntaxNodeBase RightCondition => rightCondition;
|
|
||||||
|
|
||||||
public SyntaxNodeBase Statement => statement;
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
namespace CanonSharp.Pascal.SyntaxTree;
|
|
||||||
|
|
||||||
public sealed class IfNode : SyntaxNodeBase
|
|
||||||
{
|
|
||||||
public override SyntaxNodeType NodeType => SyntaxNodeType.If;
|
|
||||||
|
|
||||||
public SyntaxNodeBase Condition { get; }
|
|
||||||
|
|
||||||
public SyntaxNodeBase Statement { get; }
|
|
||||||
|
|
||||||
public SyntaxNodeBase? ElseStatement { get; }
|
|
||||||
|
|
||||||
public IfNode(SyntaxNodeBase condition, SyntaxNodeBase statement)
|
|
||||||
{
|
|
||||||
Condition = condition;
|
|
||||||
Statement = statement;
|
|
||||||
ElseStatement = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IfNode(SyntaxNodeBase condition, SyntaxNodeBase statement, SyntaxNodeBase elseStatement)
|
|
||||||
{
|
|
||||||
Condition = condition;
|
|
||||||
Statement = statement;
|
|
||||||
ElseStatement = elseStatement;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
using CanonSharp.Pascal.Scanner;
|
|
||||||
|
|
||||||
namespace CanonSharp.Pascal.SyntaxTree;
|
|
||||||
|
|
||||||
public sealed class Parameter(bool isReference, LexicalToken identifier, SyntaxNodeBase typeNode) : SyntaxNodeBase
|
|
||||||
{
|
|
||||||
public override SyntaxNodeType NodeType => SyntaxNodeType.Parameter;
|
|
||||||
|
|
||||||
public bool IsReference => isReference;
|
|
||||||
|
|
||||||
public LexicalToken Identifier => identifier;
|
|
||||||
|
|
||||||
public SyntaxNodeBase TypeNode => typeNode;
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
using CanonSharp.Pascal.Scanner;
|
|
||||||
|
|
||||||
namespace CanonSharp.Pascal.SyntaxTree;
|
|
||||||
|
|
||||||
public sealed class ProcedureCallNode : SyntaxNodeBase
|
|
||||||
{
|
|
||||||
public ProcedureCallNode(LexicalToken identifier, IEnumerable<SyntaxNodeBase> parameters)
|
|
||||||
{
|
|
||||||
Identifier = identifier;
|
|
||||||
Parameters.AddRange(parameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override SyntaxNodeType NodeType => SyntaxNodeType.ProcedureCall;
|
|
||||||
|
|
||||||
public LexicalToken Identifier { get; }
|
|
||||||
|
|
||||||
public List<SyntaxNodeBase> Parameters { get; } = [];
|
|
||||||
}
|
|
|
@ -1,9 +1,6 @@
|
||||||
namespace CanonSharp.Pascal.SyntaxTree;
|
namespace CanonSharp.Pascal.SyntaxTree;
|
||||||
|
|
||||||
public sealed class ProgramBody(BlockNode constantDeclarations, BlockNode variableDeclarations,
|
public sealed class ProgramBody(BlockNode constantDeclarations, BlockNode variableDeclarations, BlockNode mainBlock) : SyntaxNodeBase
|
||||||
BlockNode subprograms,
|
|
||||||
BlockNode mainBlock)
|
|
||||||
: SyntaxNodeBase
|
|
||||||
{
|
{
|
||||||
public override SyntaxNodeType NodeType => SyntaxNodeType.ProgramBody;
|
public override SyntaxNodeType NodeType => SyntaxNodeType.ProgramBody;
|
||||||
|
|
||||||
|
@ -11,7 +8,5 @@ public sealed class ProgramBody(BlockNode constantDeclarations, BlockNode variab
|
||||||
|
|
||||||
public BlockNode VariableDeclarations => variableDeclarations;
|
public BlockNode VariableDeclarations => variableDeclarations;
|
||||||
|
|
||||||
public BlockNode Subprograms => subprograms;
|
|
||||||
|
|
||||||
public BlockNode MainBlock => mainBlock;
|
public BlockNode MainBlock => mainBlock;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
namespace CanonSharp.Pascal.SyntaxTree;
|
|
||||||
|
|
||||||
public sealed class Subprogram(SubprogramHead subprogramHead, SubprogramBody subprogramBody) : SyntaxNodeBase
|
|
||||||
{
|
|
||||||
public override SyntaxNodeType NodeType => SyntaxNodeType.SubProgram;
|
|
||||||
|
|
||||||
public SubprogramHead Head => subprogramHead;
|
|
||||||
|
|
||||||
public SubprogramBody Body => subprogramBody;
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
namespace CanonSharp.Pascal.SyntaxTree;
|
|
||||||
|
|
||||||
public sealed class SubprogramBody(BlockNode constDeclarations, BlockNode variableDeclarations, BlockNode mainBlock) : SyntaxNodeBase
|
|
||||||
{
|
|
||||||
public override SyntaxNodeType NodeType => SyntaxNodeType.SubprogramBody;
|
|
||||||
|
|
||||||
public BlockNode ConstDeclarations => constDeclarations;
|
|
||||||
|
|
||||||
public BlockNode VariableDeclarations => variableDeclarations;
|
|
||||||
|
|
||||||
public BlockNode MainBlock => mainBlock;
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
using CanonSharp.Pascal.Scanner;
|
|
||||||
|
|
||||||
namespace CanonSharp.Pascal.SyntaxTree;
|
|
||||||
|
|
||||||
public sealed class SubprogramHead : SyntaxNodeBase
|
|
||||||
{
|
|
||||||
public override SyntaxNodeType NodeType => SyntaxNodeType.SubprogramHead;
|
|
||||||
|
|
||||||
public LexicalToken Identifier { get; }
|
|
||||||
|
|
||||||
public List<Parameter> Parameters { get; } = [];
|
|
||||||
|
|
||||||
public SyntaxNodeBase? TypeToken { get; }
|
|
||||||
|
|
||||||
public SubprogramHead(LexicalToken identifier, IEnumerable<Parameter> parameters)
|
|
||||||
{
|
|
||||||
Identifier = identifier;
|
|
||||||
Parameters.AddRange(parameters);
|
|
||||||
TypeToken = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SubprogramHead(LexicalToken identifier, IEnumerable<Parameter> parameters, SyntaxNodeBase typeToken) : this(
|
|
||||||
identifier, parameters)
|
|
||||||
{
|
|
||||||
TypeToken = typeToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -14,14 +14,6 @@ public enum SyntaxNodeType
|
||||||
Block,
|
Block,
|
||||||
Constant,
|
Constant,
|
||||||
VariableDeclaration,
|
VariableDeclaration,
|
||||||
If,
|
|
||||||
While,
|
|
||||||
For,
|
|
||||||
ProcedureCall,
|
|
||||||
Parameter,
|
|
||||||
SubprogramHead,
|
|
||||||
SubprogramBody,
|
|
||||||
SubProgram,
|
|
||||||
ProgramBody,
|
ProgramBody,
|
||||||
ProgramHead,
|
ProgramHead,
|
||||||
Program
|
Program
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
namespace CanonSharp.Pascal.SyntaxTree;
|
|
||||||
|
|
||||||
public sealed class WhileNode(SyntaxNodeBase condition, SyntaxNodeBase statement) : SyntaxNodeBase
|
|
||||||
{
|
|
||||||
public override SyntaxNodeType NodeType => SyntaxNodeType.While;
|
|
||||||
|
|
||||||
public SyntaxNodeBase Condition => condition;
|
|
||||||
|
|
||||||
public SyntaxNodeBase Statement => statement;
|
|
||||||
}
|
|
|
@ -82,23 +82,6 @@ public sealed class ExpressionParserTests : GrammarParserTestBase
|
||||||
Assert.Equal(1, binaryOperatorNode.Right.Convert<IntegerValueNode>().Value);
|
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]
|
[Fact]
|
||||||
public void SingleTermTest()
|
public void SingleTermTest()
|
||||||
{
|
{
|
||||||
|
|
|
@ -138,90 +138,6 @@ public class ProgramParserTests : GrammarParserTestBase
|
||||||
a[10,0] := 1;
|
a[10,0] := 1;
|
||||||
end.
|
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)
|
public void ProgramParseTest(string input)
|
||||||
{
|
{
|
||||||
ProgramParse(input);
|
ProgramParse(input);
|
||||||
|
|
|
@ -15,114 +15,6 @@ public class StatementParserTests : GrammarParserTestBase
|
||||||
Assert.Equal(1, node.Expression.Convert<IntegerValueNode>().Value);
|
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]
|
[Theory]
|
||||||
[InlineData("""
|
[InlineData("""
|
||||||
begin
|
begin
|
||||||
|
|
|
@ -1,83 +0,0 @@
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user