You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

GrammarParserTest.cs 14 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. using LLama.Native;
  2. using LLama.Grammars;
  3. namespace LLama.Unittest
  4. {
  5. /// <summary>
  6. /// Source:
  7. /// https://github.com/ggerganov/llama.cpp/blob/6381d4e110bd0ec02843a60bbeb8b6fc37a9ace9/tests/test-grammar-parser.cpp
  8. ///
  9. /// The commit hash from URL is the actual commit hash that reflects current C# code.
  10. /// </summary>
  11. public sealed class GrammarParserTest
  12. {
  13. [Fact]
  14. public void ParseComplexGrammar()
  15. {
  16. GBNFGrammarParser parsedGrammar = new GBNFGrammarParser();
  17. string grammarBytes = @"root ::= (expr ""="" term ""\n"")+
  18. expr ::= term ([-+*/] term)*
  19. term ::= [0-9]+";
  20. var state = parsedGrammar.Parse(grammarBytes, "root");
  21. Assert.Equal(0ul, state.StartRuleIndex);
  22. var expected = new List<KeyValuePair<string, uint>>
  23. {
  24. new KeyValuePair<string, uint>("expr", 2),
  25. new KeyValuePair<string, uint>("expr_5", 5),
  26. new KeyValuePair<string, uint>("expr_6", 6),
  27. new KeyValuePair<string, uint>("root", 0),
  28. new KeyValuePair<string, uint>("root_1", 1),
  29. new KeyValuePair<string, uint>("root_4", 4),
  30. new KeyValuePair<string, uint>("term", 3),
  31. new KeyValuePair<string, uint>("term_7", 7),
  32. };
  33. foreach (var symbol in expected)
  34. {
  35. var rule = state.Rules[(int)symbol.Value];
  36. Assert.Equal(symbol.Key, rule.Name);
  37. }
  38. var expectedRules = new List<LLamaGrammarElement>
  39. {
  40. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 4),
  41. new LLamaGrammarElement(LLamaGrammarElementType.END, 0),
  42. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 2),
  43. new LLamaGrammarElement(LLamaGrammarElementType.CHAR, 61),
  44. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 3),
  45. new LLamaGrammarElement(LLamaGrammarElementType.CHAR, 10),
  46. new LLamaGrammarElement(LLamaGrammarElementType.END, 0),
  47. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 3),
  48. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 6),
  49. new LLamaGrammarElement(LLamaGrammarElementType.END, 0),
  50. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 7),
  51. new LLamaGrammarElement(LLamaGrammarElementType.END, 0),
  52. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 1),
  53. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 4),
  54. new LLamaGrammarElement(LLamaGrammarElementType.ALT, 0),
  55. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 1),
  56. new LLamaGrammarElement(LLamaGrammarElementType.END, 0),
  57. new LLamaGrammarElement(LLamaGrammarElementType.CHAR, 45),
  58. new LLamaGrammarElement(LLamaGrammarElementType.CHAR_ALT, 43),
  59. new LLamaGrammarElement(LLamaGrammarElementType.CHAR_ALT, 42),
  60. new LLamaGrammarElement(LLamaGrammarElementType.CHAR_ALT, 47),
  61. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 3),
  62. new LLamaGrammarElement(LLamaGrammarElementType.END, 0),
  63. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 5),
  64. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 6),
  65. new LLamaGrammarElement(LLamaGrammarElementType.ALT, 0),
  66. new LLamaGrammarElement(LLamaGrammarElementType.END, 0),
  67. new LLamaGrammarElement(LLamaGrammarElementType.CHAR, 48),
  68. new LLamaGrammarElement(LLamaGrammarElementType.CHAR_RNG_UPPER, 57),
  69. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 7),
  70. new LLamaGrammarElement(LLamaGrammarElementType.ALT, 0),
  71. new LLamaGrammarElement(LLamaGrammarElementType.CHAR, 48),
  72. new LLamaGrammarElement(LLamaGrammarElementType.CHAR_RNG_UPPER, 57),
  73. new LLamaGrammarElement(LLamaGrammarElementType.END, 0),
  74. };
  75. uint index = 0;
  76. foreach (var rule in state.Rules)
  77. {
  78. // compare rule to expected rule
  79. for (uint i = 0; i < rule.Elements.Count; i++)
  80. {
  81. var element = rule.Elements[(int)i];
  82. var expectedElement = expectedRules[(int)index];
  83. // Pretty print error message before asserting
  84. if (expectedElement.Type != element.Type || expectedElement.Value != element.Value)
  85. {
  86. Console.Error.WriteLine($"index: {index}");
  87. Console.Error.WriteLine($"expected_element: {expectedElement.Type}, {expectedElement.Value}");
  88. Console.Error.WriteLine($"actual_element: {element.Type}, {element.Value}");
  89. Console.Error.WriteLine("expected_element != actual_element");
  90. }
  91. Assert.Equal(expectedElement.Type, element.Type);
  92. Assert.Equal(expectedElement.Value, element.Value);
  93. index++;
  94. }
  95. }
  96. Assert.NotEmpty(state.Rules);
  97. }
  98. [Fact]
  99. public void ParseExtraComplexGrammar()
  100. {
  101. GBNFGrammarParser parsedGrammar = new GBNFGrammarParser();
  102. string grammarBytes = @"
  103. root ::= (expr ""="" ws term ""\n"")+
  104. expr ::= term ([-+*/] term)*
  105. term ::= ident | num | ""("" ws expr "")"" ws
  106. ident ::= [a-z] [a-z0-9_]* ws
  107. num ::= [0-9]+ ws
  108. ws ::= [ \t\n]*
  109. ";
  110. var state = parsedGrammar.Parse(grammarBytes, "root");
  111. Assert.Equal(0ul, state.StartRuleIndex);
  112. var expected = new List<KeyValuePair<string, uint>>
  113. {
  114. new KeyValuePair<string, uint>("expr", 2),
  115. new KeyValuePair<string, uint>("expr_6", 6),
  116. new KeyValuePair<string, uint>("expr_7", 7),
  117. new KeyValuePair<string, uint>("ident", 8),
  118. new KeyValuePair<string, uint>("ident_10", 10),
  119. new KeyValuePair<string, uint>("num", 9),
  120. new KeyValuePair<string, uint>("num_11", 11),
  121. new KeyValuePair<string, uint>("root", 0),
  122. new KeyValuePair<string, uint>("root_1", 1),
  123. new KeyValuePair<string, uint>("root_5", 5),
  124. new KeyValuePair<string, uint>("term", 4),
  125. new KeyValuePair<string, uint>("ws", 3),
  126. new KeyValuePair<string, uint>("ws_12", 12),
  127. };
  128. foreach (var symbol in expected)
  129. {
  130. var rule = state.Rules[(int)symbol.Value];
  131. Assert.Equal(symbol.Key, rule.Name);
  132. }
  133. var expectedRules = new List<LLamaGrammarElement>
  134. {
  135. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 5),
  136. new LLamaGrammarElement(LLamaGrammarElementType.END, 0),
  137. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 2),
  138. new LLamaGrammarElement(LLamaGrammarElementType.CHAR, 61),
  139. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 3),
  140. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 4),
  141. new LLamaGrammarElement(LLamaGrammarElementType.CHAR, 10),
  142. new LLamaGrammarElement(LLamaGrammarElementType.END, 0),
  143. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 4),
  144. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 7),
  145. new LLamaGrammarElement(LLamaGrammarElementType.END, 0),
  146. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 12),
  147. new LLamaGrammarElement(LLamaGrammarElementType.END, 0),
  148. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 8),
  149. new LLamaGrammarElement(LLamaGrammarElementType.ALT, 0),
  150. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 9),
  151. new LLamaGrammarElement(LLamaGrammarElementType.ALT, 0),
  152. new LLamaGrammarElement(LLamaGrammarElementType.CHAR, 40),
  153. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 3),
  154. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 2),
  155. new LLamaGrammarElement(LLamaGrammarElementType.CHAR, 41),
  156. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 3),
  157. new LLamaGrammarElement(LLamaGrammarElementType.END, 0),
  158. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 1),
  159. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 5),
  160. new LLamaGrammarElement(LLamaGrammarElementType.ALT, 0),
  161. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 1),
  162. new LLamaGrammarElement(LLamaGrammarElementType.END, 0),
  163. new LLamaGrammarElement(LLamaGrammarElementType.CHAR, 45),
  164. new LLamaGrammarElement(LLamaGrammarElementType.CHAR_ALT, 43),
  165. new LLamaGrammarElement(LLamaGrammarElementType.CHAR_ALT, 42),
  166. new LLamaGrammarElement(LLamaGrammarElementType.CHAR_ALT, 47),
  167. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 4),
  168. new LLamaGrammarElement(LLamaGrammarElementType.END, 0),
  169. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 6),
  170. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 7),
  171. new LLamaGrammarElement(LLamaGrammarElementType.ALT, 0),
  172. new LLamaGrammarElement(LLamaGrammarElementType.END, 0),
  173. new LLamaGrammarElement(LLamaGrammarElementType.CHAR, 97),
  174. new LLamaGrammarElement(LLamaGrammarElementType.CHAR_RNG_UPPER, 122),
  175. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 10),
  176. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 3),
  177. new LLamaGrammarElement(LLamaGrammarElementType.END, 0),
  178. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 11),
  179. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 3),
  180. new LLamaGrammarElement(LLamaGrammarElementType.END, 0),
  181. new LLamaGrammarElement(LLamaGrammarElementType.CHAR, 97),
  182. new LLamaGrammarElement(LLamaGrammarElementType.CHAR_RNG_UPPER, 122),
  183. new LLamaGrammarElement(LLamaGrammarElementType.CHAR_ALT, 48),
  184. new LLamaGrammarElement(LLamaGrammarElementType.CHAR_RNG_UPPER, 57),
  185. new LLamaGrammarElement(LLamaGrammarElementType.CHAR_ALT, 95),
  186. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 10),
  187. new LLamaGrammarElement(LLamaGrammarElementType.ALT, 0),
  188. new LLamaGrammarElement(LLamaGrammarElementType.END, 0),
  189. new LLamaGrammarElement(LLamaGrammarElementType.CHAR, 48),
  190. new LLamaGrammarElement(LLamaGrammarElementType.CHAR_RNG_UPPER, 57),
  191. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 11),
  192. new LLamaGrammarElement(LLamaGrammarElementType.ALT, 0),
  193. new LLamaGrammarElement(LLamaGrammarElementType.CHAR, 48),
  194. new LLamaGrammarElement(LLamaGrammarElementType.CHAR_RNG_UPPER, 57),
  195. new LLamaGrammarElement(LLamaGrammarElementType.END, 0),
  196. new LLamaGrammarElement(LLamaGrammarElementType.CHAR, 32),
  197. new LLamaGrammarElement(LLamaGrammarElementType.CHAR_ALT, 9),
  198. new LLamaGrammarElement(LLamaGrammarElementType.CHAR_ALT, 10),
  199. new LLamaGrammarElement(LLamaGrammarElementType.RULE_REF, 12),
  200. new LLamaGrammarElement(LLamaGrammarElementType.ALT, 0),
  201. new LLamaGrammarElement(LLamaGrammarElementType.END, 0)
  202. };
  203. uint index = 0;
  204. foreach (var rule in state.Rules)
  205. {
  206. // compare rule to expected rule
  207. for (uint i = 0; i < rule.Elements.Count; i++)
  208. {
  209. var element = rule.Elements[(int)i];
  210. var expectedElement = expectedRules[(int)index];
  211. // Pretty print error message before asserting
  212. if (expectedElement.Type != element.Type || expectedElement.Value != element.Value)
  213. {
  214. Console.Error.WriteLine($"index: {index}");
  215. Console.Error.WriteLine($"expected_element: {expectedElement.Type}, {expectedElement.Value}");
  216. Console.Error.WriteLine($"actual_element: {element.Type}, {element.Value}");
  217. Console.Error.WriteLine("expected_element != actual_element");
  218. }
  219. Assert.Equal(expectedElement.Type, element.Type);
  220. Assert.Equal(expectedElement.Value, element.Value);
  221. index++;
  222. }
  223. }
  224. Assert.NotEmpty(state.Rules);
  225. }
  226. }
  227. }