Canon/Canon.Tests/GrammarParserTests/PascalGrammarConstPart.cs
jackfiled 99fdd6438b add: 这就是完全的Pascal (#11)
5!8!4!个状态堂堂登场!

Co-authored-by: Ichirinko <1621543655@qq.com>
Reviewed-on: PostGuard/Canon#11
2024-03-13 23:58:06 +08:00

414 lines
15 KiB
C#

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;
});
}
}