add: 这就是完全的Pascal (#11)
5!8!4!个状态堂堂登场! Co-authored-by: Ichirinko <1621543655@qq.com> Reviewed-on: PostGuard/Canon#11
This commit is contained in:
parent
184604940e
commit
99fdd6438b
|
@ -19,7 +19,7 @@ public enum NonTerminatorType
|
|||
VarDeclaration,
|
||||
Type,
|
||||
BasicType,
|
||||
Range,
|
||||
Period,
|
||||
Subprogram,
|
||||
SubprogramHead,
|
||||
SubprogramBody,
|
||||
|
@ -37,5 +37,9 @@ public enum NonTerminatorType
|
|||
ExpressionList,
|
||||
SimpleExpression,
|
||||
Term,
|
||||
Factor
|
||||
Factor,
|
||||
AddOperator,
|
||||
MultiplyOperator,
|
||||
RelationOperator,
|
||||
IdVarPart
|
||||
}
|
||||
|
|
|
@ -29,7 +29,15 @@ public enum DelimiterType
|
|||
LeftSquareBracket,
|
||||
RightSquareBracket,
|
||||
SingleQuotation,
|
||||
DoubleQuotation
|
||||
DoubleQuotation,
|
||||
/// <summary>
|
||||
/// 访问记录字段用的点 x.a
|
||||
/// </summary>
|
||||
Dot,
|
||||
/// <summary>
|
||||
/// 数组声明上下界之间的分隔符 1..50
|
||||
/// </summary>
|
||||
DoubleDots
|
||||
}
|
||||
|
||||
public enum KeywordType
|
||||
|
@ -49,6 +57,15 @@ public enum KeywordType
|
|||
For,
|
||||
To,
|
||||
Do,
|
||||
Integer,
|
||||
Real,
|
||||
Boolean,
|
||||
Character,
|
||||
Divide,
|
||||
Not,
|
||||
Mod,
|
||||
And,
|
||||
Or
|
||||
}
|
||||
|
||||
public enum OperatorType
|
||||
|
@ -63,9 +80,6 @@ public enum OperatorType
|
|||
Minus,
|
||||
Multiply,
|
||||
Divide,
|
||||
Mod,
|
||||
And,
|
||||
Or,
|
||||
Assign
|
||||
}
|
||||
|
||||
|
|
413
Canon.Tests/GrammarParserTests/PascalGrammarConstPart.cs
Normal file
413
Canon.Tests/GrammarParserTests/PascalGrammarConstPart.cs
Normal file
|
@ -0,0 +1,413 @@
|
|||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.Enums;
|
||||
using Canon.Core.GrammarParser;
|
||||
using Canon.Core.LexicalParser;
|
||||
|
||||
namespace Canon.Tests.GrammarParserTests;
|
||||
|
||||
public class PascalGrammarConstPart
|
||||
{
|
||||
private static readonly Dictionary<NonTerminator, List<List<TerminatorBase>>> s_pascalGrammar = new()
|
||||
{
|
||||
{
|
||||
// ProgramStart -> ProgramBody
|
||||
new NonTerminator(NonTerminatorType.StartNonTerminator), [
|
||||
[new NonTerminator(NonTerminatorType.ProgramBody)]
|
||||
]
|
||||
},
|
||||
{
|
||||
// ProgramBody -> ConstDeclarations
|
||||
new NonTerminator(NonTerminatorType.ProgramBody), [
|
||||
[
|
||||
new NonTerminator(NonTerminatorType.ConstDeclarations),
|
||||
// new NonTerminator(NonTerminatorType.VarDeclarations),
|
||||
// new NonTerminator(NonTerminatorType.SubprogramDeclarations),
|
||||
// new NonTerminator(NonTerminatorType.CompoundStatement)
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// ConstDeclarations -> ε | const ConstDeclaration ;
|
||||
new NonTerminator(NonTerminatorType.ConstDeclarations), [
|
||||
[
|
||||
Terminator.EmptyTerminator,
|
||||
],
|
||||
[
|
||||
new Terminator(KeywordType.Const),
|
||||
new NonTerminator(NonTerminatorType.ConstDeclaration),
|
||||
new Terminator(DelimiterType.Semicolon)
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// ConstDeclaration -> id = ConstValue | ConstDeclaration ; id = ConstValue
|
||||
new NonTerminator(NonTerminatorType.ConstDeclaration), [
|
||||
[
|
||||
Terminator.IdentifierTerminator,
|
||||
new Terminator(OperatorType.Equal),
|
||||
new NonTerminator(NonTerminatorType.ConstValue)
|
||||
],
|
||||
[
|
||||
new NonTerminator(NonTerminatorType.ConstDeclaration),
|
||||
new Terminator(DelimiterType.Semicolon),
|
||||
Terminator.IdentifierTerminator,
|
||||
new Terminator(OperatorType.Equal),
|
||||
new NonTerminator(NonTerminatorType.ConstValue)
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// ConstValue -> +num | -num | num | 'letter'
|
||||
new NonTerminator(NonTerminatorType.ConstValue), [
|
||||
[
|
||||
new Terminator(OperatorType.Plus), Terminator.NumberTerminator
|
||||
],
|
||||
[
|
||||
new Terminator(OperatorType.Minus), Terminator.NumberTerminator,
|
||||
],
|
||||
[
|
||||
Terminator.NumberTerminator,
|
||||
],
|
||||
[
|
||||
new Terminator(DelimiterType.SingleQuotation),
|
||||
Terminator.CharacterTerminator,
|
||||
new Terminator(DelimiterType.SingleQuotation),
|
||||
]
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
[Fact]
|
||||
public void AstTestFirst()
|
||||
{
|
||||
GrammarBuilder builder = new()
|
||||
{
|
||||
Generators = s_pascalGrammar, Begin = new NonTerminator(NonTerminatorType.StartNonTerminator)
|
||||
};
|
||||
|
||||
GrammarParserBase grammar = builder.Build().ToGrammarParser();
|
||||
|
||||
// const a = +5;
|
||||
List<SemanticToken> tokens =
|
||||
[
|
||||
new KeywordSemanticToken
|
||||
{
|
||||
CharacterPos = 0, KeywordType = KeywordType.Const, LinePos = 0, LiteralValue = "const"
|
||||
},
|
||||
new IdentifierSemanticToken { LinePos = 0, CharacterPos = 0, LiteralValue = "a" },
|
||||
new OperatorSemanticToken
|
||||
{
|
||||
LinePos = 0, CharacterPos = 0, LiteralValue = "=", OperatorType = OperatorType.Equal
|
||||
},
|
||||
new OperatorSemanticToken
|
||||
{
|
||||
LinePos = 0, CharacterPos = 0, LiteralValue = "+", OperatorType = OperatorType.Plus
|
||||
},
|
||||
new NumberSemanticToken
|
||||
{
|
||||
CharacterPos = 0, LinePos = 0, LiteralValue = "5", NumberType = NumberType.Integer
|
||||
},
|
||||
new DelimiterSemanticToken
|
||||
{
|
||||
CharacterPos = 0, DelimiterType = DelimiterType.Semicolon, LinePos = 0, LiteralValue = ";"
|
||||
},
|
||||
SemanticToken.End
|
||||
];
|
||||
|
||||
|
||||
// ProgramBody
|
||||
SyntaxNode root = grammar.Analyse(tokens);
|
||||
Assert.Equal(NonTerminatorType.ProgramBody, root.GetNonTerminatorType());
|
||||
Assert.Single(root.Children);
|
||||
Assert.Equal(10, root.Count());
|
||||
|
||||
// ConstDeclarations
|
||||
root = root.Children[0];
|
||||
Assert.Equal(NonTerminatorType.ConstDeclarations, root.GetNonTerminatorType());
|
||||
Assert.Equal(3, root.Children.Count);
|
||||
|
||||
Assert.Contains(root.Children, node =>
|
||||
{
|
||||
if (node.IsTerminated && node.GetSemanticToken().TokenType == SemanticTokenType.Keyword)
|
||||
{
|
||||
KeywordSemanticToken token = (KeywordSemanticToken)node.GetSemanticToken();
|
||||
|
||||
return token.KeywordType == KeywordType.Const;
|
||||
}
|
||||
|
||||
if (node.IsTerminated && node.GetSemanticToken().TokenType == SemanticTokenType.Delimiter)
|
||||
{
|
||||
DelimiterSemanticToken token = (DelimiterSemanticToken)node.GetSemanticToken();
|
||||
|
||||
return token.DelimiterType == DelimiterType.Semicolon;
|
||||
}
|
||||
|
||||
if (!node.IsTerminated && node.GetNonTerminatorType() == NonTerminatorType.ConstDeclaration)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
// ConstDeclaration
|
||||
root = root.Children.Where(child =>
|
||||
!child.IsTerminated && child.GetNonTerminatorType() == NonTerminatorType.ConstDeclaration
|
||||
).ElementAt(0);
|
||||
|
||||
Assert.Equal(NonTerminatorType.ConstDeclaration, root.GetNonTerminatorType());
|
||||
Assert.Equal(3, root.Children.Count);
|
||||
Assert.Contains(root.Children, node =>
|
||||
{
|
||||
if (node.IsTerminated && node.GetSemanticToken().TokenType == SemanticTokenType.Identifier)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!node.IsTerminated && node.GetNonTerminatorType() == NonTerminatorType.ConstValue)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (node.IsTerminated && node.GetSemanticToken().TokenType == SemanticTokenType.Operator)
|
||||
{
|
||||
OperatorSemanticToken token = (OperatorSemanticToken)node.GetSemanticToken();
|
||||
|
||||
return token.OperatorType == OperatorType.Equal;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
// ConstValue
|
||||
root = root.Children.Where(child =>
|
||||
!child.IsTerminated && child.GetNonTerminatorType() == NonTerminatorType.ConstValue
|
||||
).ElementAt(0);
|
||||
Assert.Equal(NonTerminatorType.ConstValue, root.GetNonTerminatorType());
|
||||
Assert.Equal(2, root.Children.Count);
|
||||
Assert.Contains(root.Children, node =>
|
||||
{
|
||||
if (node.IsTerminated && node.GetSemanticToken().TokenType == SemanticTokenType.Operator)
|
||||
{
|
||||
OperatorSemanticToken token = (OperatorSemanticToken)node.GetSemanticToken();
|
||||
|
||||
return token.OperatorType == OperatorType.Plus;
|
||||
}
|
||||
|
||||
if (node.IsTerminated && node.GetSemanticToken().TokenType == SemanticTokenType.Number)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AstTestSecond()
|
||||
{
|
||||
GrammarBuilder builder = new()
|
||||
{
|
||||
Generators = s_pascalGrammar, Begin = new NonTerminator(NonTerminatorType.StartNonTerminator)
|
||||
};
|
||||
|
||||
GrammarParserBase grammar = builder.Build().ToGrammarParser();
|
||||
|
||||
// const a = 5; McCafe = 'Under Pressure (Queen & D. Bowie)' ;
|
||||
List<SemanticToken> tokens =
|
||||
[
|
||||
new KeywordSemanticToken
|
||||
{
|
||||
CharacterPos = 0, KeywordType = KeywordType.Const, LinePos = 0, LiteralValue = "const"
|
||||
},
|
||||
new IdentifierSemanticToken { LinePos = 0, CharacterPos = 0, LiteralValue = "a" },
|
||||
new OperatorSemanticToken
|
||||
{
|
||||
LinePos = 0, CharacterPos = 0, LiteralValue = "=", OperatorType = OperatorType.Equal
|
||||
},
|
||||
new NumberSemanticToken
|
||||
{
|
||||
CharacterPos = 0, LinePos = 0, LiteralValue = "5", NumberType = NumberType.Integer
|
||||
},
|
||||
new DelimiterSemanticToken
|
||||
{
|
||||
CharacterPos = 0, DelimiterType = DelimiterType.Semicolon, LinePos = 0, LiteralValue = ";"
|
||||
},
|
||||
new IdentifierSemanticToken { LinePos = 0, CharacterPos = 0, LiteralValue = "McCafe" },
|
||||
new OperatorSemanticToken
|
||||
{
|
||||
LinePos = 0, CharacterPos = 0, LiteralValue = "=", OperatorType = OperatorType.Equal
|
||||
},
|
||||
new DelimiterSemanticToken
|
||||
{
|
||||
CharacterPos = 0, DelimiterType = DelimiterType.SingleQuotation, LinePos = 0, LiteralValue = "'"
|
||||
},
|
||||
new CharacterSemanticToken
|
||||
{
|
||||
CharacterPos = 0, LinePos = 0, LiteralValue = "Under Pressure (Queen & D. Bowie)"
|
||||
},
|
||||
new DelimiterSemanticToken
|
||||
{
|
||||
CharacterPos = 0, DelimiterType = DelimiterType.SingleQuotation, LinePos = 0, LiteralValue = "'"
|
||||
},
|
||||
new DelimiterSemanticToken
|
||||
{
|
||||
CharacterPos = 0, DelimiterType = DelimiterType.Semicolon, LinePos = 0, LiteralValue = ";"
|
||||
},
|
||||
SemanticToken.End
|
||||
];
|
||||
|
||||
// 分析树见文档
|
||||
|
||||
// ProgramBody
|
||||
SyntaxNode root = grammar.Analyse(tokens);
|
||||
Assert.Equal(NonTerminatorType.ProgramBody, root.GetNonTerminatorType());
|
||||
Assert.Single(root.Children);
|
||||
Assert.Equal(17, root.Count());
|
||||
|
||||
// ConstDeclarations
|
||||
root = root.Children[0];
|
||||
Assert.Equal(NonTerminatorType.ConstDeclarations, root.GetNonTerminatorType());
|
||||
Assert.Equal(3, root.Children.Count);
|
||||
|
||||
Assert.Contains(root.Children, node =>
|
||||
{
|
||||
if (node.IsTerminated && node.GetSemanticToken().TokenType == SemanticTokenType.Keyword)
|
||||
{
|
||||
KeywordSemanticToken token = (KeywordSemanticToken)node.GetSemanticToken();
|
||||
|
||||
return token.KeywordType == KeywordType.Const;
|
||||
}
|
||||
|
||||
if (node.IsTerminated && node.GetSemanticToken().TokenType == SemanticTokenType.Delimiter)
|
||||
{
|
||||
DelimiterSemanticToken token = (DelimiterSemanticToken)node.GetSemanticToken();
|
||||
|
||||
return token.DelimiterType == DelimiterType.Semicolon;
|
||||
}
|
||||
|
||||
if (!node.IsTerminated && node.GetNonTerminatorType() == NonTerminatorType.ConstDeclaration)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
// ConstDeclaration layer3
|
||||
root = root.Children.Where(child =>
|
||||
!child.IsTerminated && child.GetNonTerminatorType() == NonTerminatorType.ConstDeclaration
|
||||
).ElementAt(0);
|
||||
|
||||
Assert.Equal(NonTerminatorType.ConstDeclaration, root.GetNonTerminatorType());
|
||||
Assert.Equal(5, root.Children.Count);
|
||||
Assert.Contains(root.Children, node =>
|
||||
{
|
||||
if (!node.IsTerminated && node.GetNonTerminatorType() == NonTerminatorType.ConstDeclaration)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (node.IsTerminated && node.GetSemanticToken().TokenType == SemanticTokenType.Delimiter)
|
||||
{
|
||||
DelimiterSemanticToken token = (DelimiterSemanticToken)node.GetSemanticToken();
|
||||
|
||||
return token.DelimiterType == DelimiterType.Semicolon;
|
||||
}
|
||||
|
||||
if (node.IsTerminated && node.GetSemanticToken().TokenType == SemanticTokenType.Identifier)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!node.IsTerminated && node.GetNonTerminatorType() == NonTerminatorType.ConstValue)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (node.IsTerminated && node.GetSemanticToken().TokenType == SemanticTokenType.Operator)
|
||||
{
|
||||
OperatorSemanticToken token = (OperatorSemanticToken)node.GetSemanticToken();
|
||||
|
||||
return token.OperatorType == OperatorType.Equal;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
// ConstDeclaration layer4
|
||||
SyntaxNode constDeclarationLayer4 = root.Children.Where(child =>
|
||||
!child.IsTerminated && child.GetNonTerminatorType() == NonTerminatorType.ConstDeclaration
|
||||
).ElementAt(0);
|
||||
Assert.Equal(NonTerminatorType.ConstDeclaration, constDeclarationLayer4.GetNonTerminatorType());
|
||||
Assert.Equal(3, constDeclarationLayer4.Children.Count);
|
||||
Assert.Contains(constDeclarationLayer4.Children, node =>
|
||||
{
|
||||
if (node.IsTerminated && node.GetSemanticToken().TokenType == SemanticTokenType.Identifier)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (node.IsTerminated && node.GetSemanticToken().TokenType == SemanticTokenType.Operator)
|
||||
{
|
||||
OperatorSemanticToken token = (OperatorSemanticToken)node.GetSemanticToken();
|
||||
|
||||
return token.OperatorType == OperatorType.Equal;
|
||||
}
|
||||
|
||||
if (!node.IsTerminated && node.GetNonTerminatorType() == NonTerminatorType.ConstValue)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
|
||||
// ConstValue layer4
|
||||
SyntaxNode constValueLayer4 = root.Children.Where(child =>
|
||||
!child.IsTerminated && child.GetNonTerminatorType() == NonTerminatorType.ConstValue
|
||||
).ElementAt(0);
|
||||
Assert.Equal(NonTerminatorType.ConstValue, constValueLayer4.GetNonTerminatorType());
|
||||
Assert.Equal(3, constValueLayer4.Children.Count);
|
||||
Assert.Contains(constValueLayer4.Children, node =>
|
||||
{
|
||||
if (node.IsTerminated && node.GetSemanticToken().TokenType == SemanticTokenType.Delimiter)
|
||||
{
|
||||
DelimiterSemanticToken token = (DelimiterSemanticToken)node.GetSemanticToken();
|
||||
|
||||
return token.DelimiterType == DelimiterType.SingleQuotation;
|
||||
}
|
||||
|
||||
if (node.IsTerminated && node.GetSemanticToken().TokenType == SemanticTokenType.Character)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (node.IsTerminated && node.GetSemanticToken().TokenType == SemanticTokenType.Delimiter)
|
||||
{
|
||||
DelimiterSemanticToken token = (DelimiterSemanticToken)node.GetSemanticToken();
|
||||
|
||||
return token.DelimiterType == DelimiterType.SingleQuotation;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
// ConstValue layer5
|
||||
SyntaxNode constValueLayer5 = constDeclarationLayer4.Children.Where(child =>
|
||||
!child.IsTerminated && child.GetNonTerminatorType() == NonTerminatorType.ConstValue
|
||||
).ElementAt(0);
|
||||
Assert.Equal(NonTerminatorType.ConstValue, constValueLayer5.GetNonTerminatorType());
|
||||
Assert.Single(constValueLayer5.Children);
|
||||
Assert.Contains(constValueLayer5.Children, node =>
|
||||
{
|
||||
if (node.IsTerminated && node.GetSemanticToken().TokenType == SemanticTokenType.Number)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
595
Canon.Tests/GrammarParserTests/PascalGrammarTests.Grammar.cs
Normal file
595
Canon.Tests/GrammarParserTests/PascalGrammarTests.Grammar.cs
Normal file
|
@ -0,0 +1,595 @@
|
|||
using Canon.Core.Enums;
|
||||
using Canon.Core.GrammarParser;
|
||||
|
||||
namespace Canon.Tests.GrammarParserTests;
|
||||
|
||||
public partial class PascalGrammarTests
|
||||
{
|
||||
private static readonly Dictionary<NonTerminator, List<List<TerminatorBase>>> s_pascalGrammar = new()
|
||||
{
|
||||
{
|
||||
// ProgramStart -> ProgramStruct
|
||||
new NonTerminator(NonTerminatorType.StartNonTerminator), [
|
||||
[new NonTerminator(NonTerminatorType.ProgramStruct)]
|
||||
]
|
||||
},
|
||||
{
|
||||
// ProgramStruct -> ProgramHead ; ProgramBody .
|
||||
new NonTerminator(NonTerminatorType.ProgramStruct), [
|
||||
[
|
||||
new NonTerminator(NonTerminatorType.ProgramHead),
|
||||
new Terminator(DelimiterType.Semicolon),
|
||||
new NonTerminator(NonTerminatorType.ProgramBody),
|
||||
new Terminator(DelimiterType.Period)
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// ProgramHead -> program id (IdList) | program id
|
||||
new NonTerminator(NonTerminatorType.ProgramHead), [
|
||||
[
|
||||
new Terminator(KeywordType.Program),
|
||||
Terminator.IdentifierTerminator,
|
||||
new Terminator(DelimiterType.LeftParenthesis),
|
||||
new NonTerminator(NonTerminatorType.IdentifierList),
|
||||
new Terminator(DelimiterType.RightParenthesis),
|
||||
],
|
||||
[
|
||||
new Terminator(KeywordType.Program),
|
||||
Terminator.IdentifierTerminator,
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// ProgramBody -> ConstDeclarations
|
||||
// VarDeclarations
|
||||
// SubprogramDeclarations
|
||||
// CompoundStatement
|
||||
new NonTerminator(NonTerminatorType.ProgramBody), [
|
||||
[
|
||||
new NonTerminator(NonTerminatorType.ConstDeclarations),
|
||||
new NonTerminator(NonTerminatorType.VarDeclarations),
|
||||
new NonTerminator(NonTerminatorType.SubprogramDeclarations),
|
||||
new NonTerminator(NonTerminatorType.CompoundStatement)
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// IdList -> id | IdList , id
|
||||
new NonTerminator(NonTerminatorType.IdentifierList), [
|
||||
[
|
||||
Terminator.IdentifierTerminator,
|
||||
],
|
||||
[
|
||||
new NonTerminator(NonTerminatorType.IdentifierList),
|
||||
new Terminator(DelimiterType.Comma),
|
||||
Terminator.IdentifierTerminator
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// ConstDeclarations -> ε | const ConstDeclaration ;
|
||||
new NonTerminator(NonTerminatorType.ConstDeclarations), [
|
||||
[
|
||||
Terminator.EmptyTerminator,
|
||||
],
|
||||
[
|
||||
new Terminator(KeywordType.Const),
|
||||
new NonTerminator(NonTerminatorType.ConstDeclaration),
|
||||
new Terminator(DelimiterType.Semicolon)
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// ConstDeclaration -> id = ConstValue | ConstDeclaration ; id = ConstValue
|
||||
new NonTerminator(NonTerminatorType.ConstDeclaration), [
|
||||
[
|
||||
Terminator.IdentifierTerminator,
|
||||
new Terminator(OperatorType.Equal),
|
||||
new NonTerminator(NonTerminatorType.ConstValue)
|
||||
],
|
||||
[
|
||||
new NonTerminator(NonTerminatorType.ConstDeclaration),
|
||||
new Terminator(DelimiterType.Semicolon),
|
||||
Terminator.IdentifierTerminator,
|
||||
new Terminator(OperatorType.Equal),
|
||||
new NonTerminator(NonTerminatorType.ConstValue)
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// ConstValue -> +num | -num | num | 'letter'
|
||||
new NonTerminator(NonTerminatorType.ConstValue), [
|
||||
[
|
||||
new Terminator(OperatorType.Plus), Terminator.NumberTerminator
|
||||
],
|
||||
[
|
||||
new Terminator(OperatorType.Minus), Terminator.NumberTerminator,
|
||||
],
|
||||
[
|
||||
Terminator.NumberTerminator,
|
||||
],
|
||||
[
|
||||
new Terminator(DelimiterType.SingleQuotation),
|
||||
Terminator.CharacterTerminator,
|
||||
new Terminator(DelimiterType.SingleQuotation),
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// VarDeclarations -> ε | var VarDeclaration ;
|
||||
new NonTerminator(NonTerminatorType.VarDeclarations), [
|
||||
[
|
||||
Terminator.EmptyTerminator
|
||||
],
|
||||
[
|
||||
new Terminator(KeywordType.Var),
|
||||
new NonTerminator(NonTerminatorType.VarDeclaration),
|
||||
new Terminator(DelimiterType.Semicolon)
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// VarDeclaration -> IdList : Type | VarDeclaration ; IdList : Type
|
||||
new NonTerminator(NonTerminatorType.VarDeclaration), [
|
||||
[
|
||||
new NonTerminator(NonTerminatorType.IdentifierList),
|
||||
new Terminator(DelimiterType.Colon),
|
||||
new NonTerminator(NonTerminatorType.Type)
|
||||
],
|
||||
[
|
||||
new NonTerminator(NonTerminatorType.VarDeclaration),
|
||||
new Terminator(DelimiterType.Semicolon),
|
||||
new NonTerminator(NonTerminatorType.IdentifierList),
|
||||
new Terminator(DelimiterType.Colon),
|
||||
new NonTerminator(NonTerminatorType.Type)
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// Type -> BasicType | Array [ Period ] of BasicType
|
||||
new NonTerminator(NonTerminatorType.Type), [
|
||||
[
|
||||
new NonTerminator(NonTerminatorType.BasicType)
|
||||
],
|
||||
[
|
||||
new Terminator(KeywordType.Array),
|
||||
new Terminator(DelimiterType.LeftSquareBracket),
|
||||
new NonTerminator(NonTerminatorType.Period),
|
||||
new Terminator(DelimiterType.RightSquareBracket),
|
||||
new Terminator(KeywordType.Of),
|
||||
new NonTerminator(NonTerminatorType.BasicType)
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// BasicType -> Integer | Real | Boolean | char
|
||||
new NonTerminator(NonTerminatorType.BasicType), [
|
||||
[
|
||||
new Terminator(KeywordType.Integer)
|
||||
],
|
||||
[
|
||||
new Terminator(KeywordType.Real)
|
||||
],
|
||||
[
|
||||
new Terminator(KeywordType.Boolean)
|
||||
],
|
||||
[
|
||||
new Terminator(KeywordType.Character)
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// Period -> digits .. digits | Period , digits .. digits
|
||||
new NonTerminator(NonTerminatorType.Period), [
|
||||
[
|
||||
Terminator.NumberTerminator,
|
||||
new Terminator(DelimiterType.DoubleDots),
|
||||
Terminator.NumberTerminator,
|
||||
],
|
||||
[
|
||||
new NonTerminator(NonTerminatorType.Period),
|
||||
new Terminator(DelimiterType.Comma),
|
||||
Terminator.NumberTerminator,
|
||||
new Terminator(DelimiterType.DoubleDots),
|
||||
Terminator.NumberTerminator,
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// SubprogramDeclarations -> ε | SubprogramDeclarations Subprogram ;
|
||||
new NonTerminator(NonTerminatorType.SubprogramDeclarations), [
|
||||
[
|
||||
Terminator.EmptyTerminator
|
||||
],
|
||||
[
|
||||
new NonTerminator(NonTerminatorType.SubprogramDeclarations),
|
||||
new NonTerminator(NonTerminatorType.Subprogram),
|
||||
new Terminator(DelimiterType.Semicolon)
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// Subprogram -> SubprogramHead ; SubprogramBody
|
||||
new NonTerminator(NonTerminatorType.Subprogram), [
|
||||
[
|
||||
new NonTerminator(NonTerminatorType.SubprogramHead),
|
||||
new Terminator(DelimiterType.Semicolon),
|
||||
new NonTerminator(NonTerminatorType.SubprogramBody)
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// SubprogramHead -> procedure id FormalParameter
|
||||
// | function id FormalParameter : BasicType
|
||||
new NonTerminator(NonTerminatorType.SubprogramHead), [
|
||||
[
|
||||
new Terminator(KeywordType.Procedure),
|
||||
Terminator.IdentifierTerminator,
|
||||
new NonTerminator(NonTerminatorType.FormalParameter)
|
||||
],
|
||||
[
|
||||
new Terminator(KeywordType.Function),
|
||||
Terminator.IdentifierTerminator,
|
||||
new NonTerminator(NonTerminatorType.FormalParameter),
|
||||
new Terminator(DelimiterType.Colon),
|
||||
new NonTerminator(NonTerminatorType.BasicType)
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// FormalParameter -> ε | ( ParameterList )
|
||||
new NonTerminator(NonTerminatorType.FormalParameter), [
|
||||
[
|
||||
Terminator.EmptyTerminator,
|
||||
],
|
||||
[
|
||||
new Terminator(DelimiterType.LeftParenthesis),
|
||||
new NonTerminator(NonTerminatorType.ParameterList),
|
||||
new Terminator(DelimiterType.RightParenthesis)
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// ParameterList -> Parameter | ParameterList ; Parameter
|
||||
new NonTerminator(NonTerminatorType.ParameterList), [
|
||||
[
|
||||
new NonTerminator(NonTerminatorType.Parameter)
|
||||
],
|
||||
[
|
||||
new NonTerminator(NonTerminatorType.ParameterList),
|
||||
new Terminator(DelimiterType.Semicolon),
|
||||
new NonTerminator(NonTerminatorType.Parameter)
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// Parameter -> VarParameter | ValueParameter
|
||||
new NonTerminator(NonTerminatorType.Parameter), [
|
||||
[
|
||||
new NonTerminator(NonTerminatorType.VarParameter)
|
||||
],
|
||||
[
|
||||
new NonTerminator(NonTerminatorType.ValueParameter)
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// VarParameter -> var ValueParameter
|
||||
new NonTerminator(NonTerminatorType.VarParameter), [
|
||||
[
|
||||
new Terminator(KeywordType.Var),
|
||||
new NonTerminator(NonTerminatorType.ValueParameter)
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// ValueParameter -> IdList : BasicType
|
||||
new NonTerminator(NonTerminatorType.ValueParameter), [
|
||||
[
|
||||
new NonTerminator(NonTerminatorType.IdentifierList),
|
||||
new Terminator(DelimiterType.Colon),
|
||||
new NonTerminator(NonTerminatorType.BasicType)
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// SubprogramBody -> ConstDeclarations
|
||||
// VarDeclarations
|
||||
// CompoundStatement
|
||||
new NonTerminator(NonTerminatorType.SubprogramBody), [
|
||||
[
|
||||
new NonTerminator(NonTerminatorType.ConstDeclarations),
|
||||
new NonTerminator(NonTerminatorType.VarDeclarations),
|
||||
new NonTerminator(NonTerminatorType.CompoundStatement)
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// CompoundStatement -> begin StatementList end
|
||||
new NonTerminator(NonTerminatorType.CompoundStatement), [
|
||||
[
|
||||
new Terminator(KeywordType.Begin),
|
||||
new NonTerminator(NonTerminatorType.StatementList),
|
||||
new Terminator(KeywordType.End)
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// StatementList -> Statement | StatementList ; Statement
|
||||
new NonTerminator(NonTerminatorType.StatementList), [
|
||||
[
|
||||
new NonTerminator(NonTerminatorType.Statement)
|
||||
],
|
||||
[
|
||||
new NonTerminator(NonTerminatorType.StatementList),
|
||||
new Terminator(DelimiterType.Semicolon),
|
||||
new NonTerminator(NonTerminatorType.Statement)
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// Statement -> ε
|
||||
// | Variable AssignOp Expression
|
||||
// | FuncId AssignOp Expression
|
||||
// | ProcedureCall
|
||||
// | CompoundStatement
|
||||
// | if Expression then Statement ElsePart
|
||||
// | for id AssignOp Expression to Expression do Statement
|
||||
// | read ( VariableList )
|
||||
// | write( ExpressionList )
|
||||
// 注意这里 read 和 write 作为普通的函数调用处理了
|
||||
// 因此下面并没有单独声明
|
||||
new NonTerminator(NonTerminatorType.Statement), [
|
||||
[
|
||||
// ε
|
||||
Terminator.EmptyTerminator,
|
||||
],
|
||||
[
|
||||
// Variable AssignOp Expression
|
||||
new NonTerminator(NonTerminatorType.Variable),
|
||||
new Terminator(OperatorType.Assign),
|
||||
new NonTerminator(NonTerminatorType.Expression)
|
||||
],
|
||||
[
|
||||
// FuncId AssignOp Expression
|
||||
Terminator.IdentifierTerminator,
|
||||
new Terminator(OperatorType.Assign),
|
||||
new NonTerminator(NonTerminatorType.Expression)
|
||||
],
|
||||
[
|
||||
// ProcedureCall
|
||||
new NonTerminator(NonTerminatorType.ProcedureCall)
|
||||
],
|
||||
[
|
||||
// CompoundStatement
|
||||
new NonTerminator(NonTerminatorType.CompoundStatement)
|
||||
],
|
||||
[
|
||||
// if Expression then Statement ElsePart
|
||||
new Terminator(KeywordType.If),
|
||||
new NonTerminator(NonTerminatorType.Expression),
|
||||
new Terminator(KeywordType.Then),
|
||||
new NonTerminator(NonTerminatorType.Statement),
|
||||
new NonTerminator(NonTerminatorType.ElsePart)
|
||||
],
|
||||
[
|
||||
// for id AssignOp Expression to Expression do Statement
|
||||
new Terminator(KeywordType.For),
|
||||
Terminator.IdentifierTerminator,
|
||||
new Terminator(OperatorType.Assign),
|
||||
new NonTerminator(NonTerminatorType.Expression),
|
||||
new Terminator(KeywordType.To),
|
||||
new NonTerminator(NonTerminatorType.Expression),
|
||||
new Terminator(KeywordType.Do),
|
||||
new NonTerminator(NonTerminatorType.Statement)
|
||||
]
|
||||
]
|
||||
},
|
||||
// {
|
||||
// // VariableList -> Variable | VariableList , Variable
|
||||
// // 这里用expressionList代替VariableList
|
||||
// new NonTerminator(NonTerminatorType.ExpressionList), [
|
||||
// [
|
||||
// new NonTerminator(NonTerminatorType.Variable)
|
||||
// ],
|
||||
// [
|
||||
// new NonTerminator(NonTerminatorType.ExpressionList),
|
||||
// new Terminator(DelimiterType.Comma),
|
||||
// new NonTerminator(NonTerminatorType.Variable)
|
||||
// ]
|
||||
// ]
|
||||
// },
|
||||
{
|
||||
// Variable -> id IdVarPart
|
||||
new NonTerminator(NonTerminatorType.Variable), [
|
||||
[
|
||||
Terminator.IdentifierTerminator,
|
||||
new NonTerminator(NonTerminatorType.IdVarPart)
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// IdVarPart -> ε | [ ExpressionList ]
|
||||
new NonTerminator(NonTerminatorType.IdVarPart), [
|
||||
[
|
||||
Terminator.EmptyTerminator,
|
||||
],
|
||||
[
|
||||
new Terminator(DelimiterType.LeftSquareBracket),
|
||||
new NonTerminator(NonTerminatorType.ExpressionList),
|
||||
new Terminator(DelimiterType.RightSquareBracket)
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// ProcedureCall -> id | id ( ExpressionList )
|
||||
new NonTerminator(NonTerminatorType.ProcedureCall), [
|
||||
[
|
||||
Terminator.IdentifierTerminator,
|
||||
],
|
||||
[
|
||||
Terminator.IdentifierTerminator,
|
||||
new Terminator(DelimiterType.LeftParenthesis),
|
||||
new NonTerminator(NonTerminatorType.ExpressionList),
|
||||
new Terminator(DelimiterType.RightParenthesis)
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// ElsePart -> ε | else statement
|
||||
new NonTerminator(NonTerminatorType.ElsePart), [
|
||||
[
|
||||
Terminator.EmptyTerminator,
|
||||
],
|
||||
[
|
||||
new Terminator(KeywordType.Else),
|
||||
new NonTerminator(NonTerminatorType.Statement)
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// ExpressionList -> Expression | ExpressionList , Expression
|
||||
new NonTerminator(NonTerminatorType.ExpressionList), [
|
||||
[
|
||||
new NonTerminator(NonTerminatorType.Expression)
|
||||
],
|
||||
[
|
||||
new NonTerminator(NonTerminatorType.ExpressionList),
|
||||
new Terminator(DelimiterType.Comma),
|
||||
new NonTerminator(NonTerminatorType.Expression)
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// Expression -> SimpleExpression | SimpleExpression RelationOperator SimpleExpression
|
||||
new NonTerminator(NonTerminatorType.Expression), [
|
||||
[
|
||||
new NonTerminator(NonTerminatorType.SimpleExpression)
|
||||
],
|
||||
[
|
||||
new NonTerminator(NonTerminatorType.SimpleExpression),
|
||||
new NonTerminator(NonTerminatorType.RelationOperator),
|
||||
new NonTerminator(NonTerminatorType.SimpleExpression)
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// SimpleExpression -> Term | SimpleExpression AddOperator Term
|
||||
new NonTerminator(NonTerminatorType.SimpleExpression), [
|
||||
[
|
||||
new NonTerminator(NonTerminatorType.Term)
|
||||
],
|
||||
[
|
||||
new NonTerminator(NonTerminatorType.SimpleExpression),
|
||||
new NonTerminator(NonTerminatorType.AddOperator),
|
||||
new NonTerminator(NonTerminatorType.Term)
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// Term -> Factor | Term MultiplyOperator Factor
|
||||
new NonTerminator(NonTerminatorType.Term), [
|
||||
[
|
||||
new NonTerminator(NonTerminatorType.Factor)
|
||||
],
|
||||
[
|
||||
new NonTerminator(NonTerminatorType.Term),
|
||||
new NonTerminator(NonTerminatorType.MultiplyOperator),
|
||||
new NonTerminator(NonTerminatorType.Factor)
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// Factor -> num | Variable
|
||||
// | ( Expression )
|
||||
// | id ( ExpressionList )
|
||||
// | not Factor
|
||||
// | minus Factor
|
||||
new NonTerminator(NonTerminatorType.Factor), [
|
||||
[
|
||||
Terminator.NumberTerminator,
|
||||
],
|
||||
[
|
||||
new NonTerminator(NonTerminatorType.Variable)
|
||||
],
|
||||
[
|
||||
new Terminator(DelimiterType.LeftParenthesis),
|
||||
new NonTerminator(NonTerminatorType.Expression),
|
||||
new Terminator(DelimiterType.RightParenthesis)
|
||||
],
|
||||
[
|
||||
Terminator.IdentifierTerminator,
|
||||
new Terminator(DelimiterType.LeftParenthesis),
|
||||
new NonTerminator(NonTerminatorType.ExpressionList),
|
||||
new Terminator(DelimiterType.RightParenthesis)
|
||||
],
|
||||
[
|
||||
new Terminator(KeywordType.Not),
|
||||
new NonTerminator(NonTerminatorType.Factor)
|
||||
],
|
||||
[
|
||||
new Terminator(OperatorType.Minus),
|
||||
new NonTerminator(NonTerminatorType.Factor)
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// AddOperator -> + | - | or
|
||||
new NonTerminator(NonTerminatorType.AddOperator), [
|
||||
[
|
||||
new Terminator(OperatorType.Plus)
|
||||
],
|
||||
[
|
||||
new Terminator(OperatorType.Minus)
|
||||
],
|
||||
[
|
||||
new Terminator(KeywordType.Or)
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// MultiplyOperator -> * | / | div | mod | and
|
||||
new NonTerminator(NonTerminatorType.MultiplyOperator), [
|
||||
[
|
||||
new Terminator(OperatorType.Multiply),
|
||||
],
|
||||
[
|
||||
new Terminator(OperatorType.Divide),
|
||||
],
|
||||
[
|
||||
new Terminator(KeywordType.Divide)
|
||||
],
|
||||
[
|
||||
new Terminator(KeywordType.Mod)
|
||||
],
|
||||
[
|
||||
new Terminator(KeywordType.And)
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
// RelationOperator -> = | <> | < | <= | > | >=
|
||||
new NonTerminator(NonTerminatorType.RelationOperator), [
|
||||
[
|
||||
new Terminator(OperatorType.Equal)
|
||||
],
|
||||
[
|
||||
new Terminator(OperatorType.NotEqual)
|
||||
],
|
||||
[
|
||||
new Terminator(OperatorType.Less)
|
||||
],
|
||||
[
|
||||
new Terminator(OperatorType.LessEqual)
|
||||
],
|
||||
[
|
||||
new Terminator(OperatorType.Greater)
|
||||
],
|
||||
[
|
||||
new Terminator(OperatorType.GreaterEqual)
|
||||
]
|
||||
]
|
||||
}
|
||||
};
|
||||
}
|
27
Canon.Tests/GrammarParserTests/PascalGrammarTests.cs
Normal file
27
Canon.Tests/GrammarParserTests/PascalGrammarTests.cs
Normal file
|
@ -0,0 +1,27 @@
|
|||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.Enums;
|
||||
using Canon.Core.GrammarParser;
|
||||
|
||||
namespace Canon.Tests.GrammarParserTests;
|
||||
|
||||
public partial class PascalGrammarTests
|
||||
{
|
||||
private readonly GrammarBuilder _builder = new()
|
||||
{
|
||||
Generators = s_pascalGrammar, Begin = new NonTerminator(NonTerminatorType.StartNonTerminator)
|
||||
};
|
||||
|
||||
private readonly GrammarParserBase _parser;
|
||||
|
||||
public PascalGrammarTests()
|
||||
{
|
||||
Grammar grammar = _builder.Build();
|
||||
_parser = grammar.ToGrammarParser();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GrammarTest()
|
||||
{
|
||||
Assert.NotNull(_parser);
|
||||
}
|
||||
}
|
|
@ -18,7 +18,6 @@ public class SimpleGrammarWithEmptyTests(ITestOutputHelper testOutputHelper)
|
|||
/// B ProgramBody
|
||||
/// a Identifier
|
||||
/// </summary>
|
||||
// private readonly ITestOutputHelper _testOutputHelper;
|
||||
|
||||
private readonly ITestOutputHelper _testOutputHelper = testOutputHelper;
|
||||
|
||||
|
|
|
@ -6,45 +6,36 @@ namespace Canon.Tests.LexicalParserTests;
|
|||
public class OperatorTypeTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("+ 123", OperatorType.Plus, 0u, 0u, true)]
|
||||
[InlineData("1 + 123", OperatorType.Plus, 0u, 2u, true)]
|
||||
[InlineData("+123", OperatorType.Plus, 0u, 0u, true)]
|
||||
[InlineData("m +123", OperatorType.Plus, 0u, 2u, true)]
|
||||
[InlineData("-123", OperatorType.Minus, 0u, 0u, true)]
|
||||
[InlineData("*123", OperatorType.Multiply, 0u, 0u, true)]
|
||||
[InlineData("/123", OperatorType.Divide, 0u, 0u, true)]
|
||||
[InlineData("=123", OperatorType.Equal, 0u, 0u, true)]
|
||||
[InlineData("<123", OperatorType.Less, 0u, 0u, true)]
|
||||
[InlineData(">123", OperatorType.Greater, 0u, 0u, true)]
|
||||
[InlineData("<=123", OperatorType.LessEqual, 0u, 0u, true)]
|
||||
[InlineData(">=123", OperatorType.GreaterEqual, 0u, 0u, true)]
|
||||
[InlineData("<>123", OperatorType.NotEqual, 0u, 0u, true)]
|
||||
[InlineData(":=123", OperatorType.Assign, 0u, 0u, true)]
|
||||
[InlineData("and 123", OperatorType.And, 0u, 0u, true)]
|
||||
[InlineData("or123", OperatorType.Or, 0u, 0u, true)]
|
||||
[InlineData("mod123", OperatorType.Mod, 0u, 0u, true)]
|
||||
|
||||
[InlineData("and123", OperatorType.And, 0u, 0u, false)]
|
||||
[InlineData("andasd", OperatorType.And, 0u, 0u, false)]
|
||||
[InlineData("andand", OperatorType.And, 0u, 0u, false)]
|
||||
[InlineData("<><123", OperatorType.NotEqual, 0u, 0u, false)]
|
||||
[InlineData("<><123", OperatorType.Less, 0u, 0u, false)]
|
||||
[InlineData("<=<123", OperatorType.LessEqual, 0u, 0u, false)]
|
||||
public void SmokeTest(string input, OperatorType type, uint expectedLinePos, uint expectedCharacterPos, bool expectedResult)
|
||||
[InlineData("+ 123", OperatorType.Plus)]
|
||||
[InlineData("1 + 123", OperatorType.Plus)]
|
||||
[InlineData("+123", OperatorType.Plus)]
|
||||
[InlineData("m +123", OperatorType.Plus)]
|
||||
[InlineData("-123", OperatorType.Minus)]
|
||||
[InlineData("*123", OperatorType.Multiply)]
|
||||
[InlineData("/123", OperatorType.Divide)]
|
||||
[InlineData("=123", OperatorType.Equal)]
|
||||
[InlineData("<123", OperatorType.Less)]
|
||||
[InlineData(">123", OperatorType.Greater)]
|
||||
[InlineData("<=123", OperatorType.LessEqual)]
|
||||
[InlineData(">=123", OperatorType.GreaterEqual)]
|
||||
[InlineData("<>123", OperatorType.NotEqual)]
|
||||
[InlineData(":=123", OperatorType.Assign)]
|
||||
public void ParseTest(string input, OperatorType result)
|
||||
{
|
||||
LinkedList<char> content = Utils.GetLinkedList(input);
|
||||
Assert.Equal(expectedResult, OperatorSemanticToken.TryParse(expectedLinePos, expectedCharacterPos, content.First!,
|
||||
out OperatorSemanticToken? token));
|
||||
if (expectedResult)
|
||||
{
|
||||
Assert.NotNull(token);
|
||||
Assert.Equal(type, token.OperatorType);
|
||||
Assert.Equal(expectedLinePos, token.LinePos);
|
||||
Assert.Equal(expectedCharacterPos, token.CharacterPos);
|
||||
Assert.True(OperatorSemanticToken.TryParse(0, 0,
|
||||
content.First!, out OperatorSemanticToken? token));
|
||||
Assert.Equal(result, token?.OperatorType);
|
||||
}
|
||||
else
|
||||
|
||||
[Theory]
|
||||
[InlineData("<><123")]
|
||||
[InlineData("<=<123")]
|
||||
public void ParseFailedTest(string input)
|
||||
{
|
||||
LinkedList<char> content = Utils.GetLinkedList(input);
|
||||
Assert.False(OperatorSemanticToken.TryParse(0, 0,
|
||||
content.First!, out OperatorSemanticToken? token));
|
||||
Assert.Null(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user