grammar.c (14297B)
1 #include "ptest.h" 2 #include "../mpc.h" 3 4 void test_grammar(void) { 5 6 mpc_parser_t *Expr, *Prod, *Value, *Maths; 7 mpc_ast_t *t0, *t1, *t2; 8 9 Expr = mpc_new("expression"); 10 Prod = mpc_new("product"); 11 Value = mpc_new("value"); 12 Maths = mpc_new("maths"); 13 14 mpc_define(Expr, mpca_grammar(MPCA_LANG_DEFAULT, " <product> (('+' | '-') <product>)* ", Prod)); 15 mpc_define(Prod, mpca_grammar(MPCA_LANG_DEFAULT, " <value> (('*' | '/') <value>)* ", Value)); 16 mpc_define(Value, mpca_grammar(MPCA_LANG_DEFAULT, " /[0-9]+/ | '(' <expression> ')' ", Expr)); 17 mpc_define(Maths, mpca_total(Expr)); 18 19 t0 = mpc_ast_new("product|value|regex", "24"); 20 t1 = mpc_ast_build(1, "product|>", 21 mpc_ast_build(3, "value|>", 22 mpc_ast_new("char", "("), 23 mpc_ast_new("expression|product|value|regex", "5"), 24 mpc_ast_new("char", ")"))); 25 26 t2 = mpc_ast_build(3, ">", 27 28 mpc_ast_build(3, "product|value|>", 29 mpc_ast_new("char", "("), 30 mpc_ast_build(3, "expression|>", 31 32 mpc_ast_build(5, "product|>", 33 mpc_ast_new("value|regex", "4"), 34 mpc_ast_new("char", "*"), 35 mpc_ast_new("value|regex", "2"), 36 mpc_ast_new("char", "*"), 37 mpc_ast_new("value|regex", "11")), 38 39 mpc_ast_new("char", "+"), 40 mpc_ast_new("product|value|regex", "2")), 41 mpc_ast_new("char", ")")), 42 43 mpc_ast_new("char", "+"), 44 mpc_ast_new("product|value|regex", "5")); 45 46 PT_ASSERT(mpc_test_pass(Maths, " 24 ", t0, (int(*)(const void*,const void*))mpc_ast_eq, (mpc_dtor_t)mpc_ast_delete, (void(*)(const void*))mpc_ast_print)); 47 PT_ASSERT(mpc_test_pass(Maths, "(5)", t1, (int(*)(const void*,const void*))mpc_ast_eq, (mpc_dtor_t)mpc_ast_delete, (void(*)(const void*))mpc_ast_print)); 48 PT_ASSERT(mpc_test_pass(Maths, "(4 * 2 * 11 + 2) + 5", t2, (int(*)(const void*,const void*))mpc_ast_eq, (mpc_dtor_t)mpc_ast_delete, (void(*)(const void*))mpc_ast_print)); 49 PT_ASSERT(mpc_test_fail(Maths, "a", t0, (int(*)(const void*,const void*))mpc_ast_eq, (mpc_dtor_t)mpc_ast_delete, (void(*)(const void*))mpc_ast_print)); 50 PT_ASSERT(mpc_test_fail(Maths, "2b+4", t0, (int(*)(const void*,const void*))mpc_ast_eq, (mpc_dtor_t)mpc_ast_delete, (void(*)(const void*))mpc_ast_print)); 51 52 mpc_ast_delete(t0); 53 mpc_ast_delete(t1); 54 mpc_ast_delete(t2); 55 56 mpc_cleanup(4, Expr, Prod, Value, Maths); 57 58 } 59 60 void test_language(void) { 61 62 mpc_parser_t *Expr, *Prod, *Value, *Maths; 63 64 Expr = mpc_new("expression"); 65 Prod = mpc_new("product"); 66 Value = mpc_new("value"); 67 Maths = mpc_new("maths"); 68 69 mpca_lang(MPCA_LANG_DEFAULT, 70 " expression : <product> (('+' | '-') <product>)*; " 71 " product : <value> (('*' | '/') <value>)*; " 72 " value : /[0-9]+/ | '(' <expression> ')'; " 73 " maths : /^/ <expression> /$/; ", 74 Expr, Prod, Value, Maths); 75 76 mpc_cleanup(4, Expr, Prod, Value, Maths); 77 } 78 79 void test_language_file(void) { 80 81 mpc_parser_t *Expr, *Prod, *Value, *Maths; 82 83 Expr = mpc_new("expression"); 84 Prod = mpc_new("product"); 85 Value = mpc_new("value"); 86 Maths = mpc_new("maths"); 87 88 mpca_lang_contents(MPCA_LANG_DEFAULT, "./tests/maths.grammar", Expr, Prod, Value, Maths); 89 90 mpc_cleanup(4, Expr, Prod, Value, Maths); 91 92 } 93 94 void test_doge(void) { 95 96 mpc_ast_t *t0; 97 mpc_parser_t* Adjective = mpc_new("adjective"); 98 mpc_parser_t* Noun = mpc_new("noun"); 99 mpc_parser_t* Phrase = mpc_new("phrase"); 100 mpc_parser_t* Doge = mpc_new("doge"); 101 102 mpca_lang(MPCA_LANG_DEFAULT, 103 " adjective : \"wow\" | \"many\" | \"so\" | \"such\"; " 104 " noun : \"lisp\" | \"language\" | \"c\" | \"book\" | \"build\"; " 105 " phrase : <adjective> <noun>; " 106 " doge : /^/ <phrase>* /$/; ", 107 Adjective, Noun, Phrase, Doge, NULL); 108 109 t0 = 110 mpc_ast_build(4, ">", 111 mpc_ast_new("regex", ""), 112 mpc_ast_build(2, "phrase|>", 113 mpc_ast_new("adjective|string", "so"), 114 mpc_ast_new("noun|string", "c")), 115 mpc_ast_build(2, "phrase|>", 116 mpc_ast_new("adjective|string", "so"), 117 mpc_ast_new("noun|string", "c")), 118 mpc_ast_new("regex", "") 119 ); 120 121 PT_ASSERT(mpc_test_pass(Doge, "so c so c", t0, (int(*)(const void*,const void*))mpc_ast_eq, (mpc_dtor_t)mpc_ast_delete, (void(*)(const void*))mpc_ast_print)); 122 123 PT_ASSERT(mpc_test_fail(Doge, "so a so c", t0, (int(*)(const void*,const void*))mpc_ast_eq, (mpc_dtor_t)mpc_ast_delete, (void(*)(const void*))mpc_ast_print)); 124 125 mpc_ast_delete(t0); 126 127 mpc_cleanup(4, Adjective, Noun, Phrase, Doge); 128 129 } 130 131 void test_partial(void) { 132 133 mpc_ast_t *t0; 134 mpc_err_t *err; 135 136 mpc_parser_t *Line = mpc_new("line"); 137 mpc_parser_t *Number = mpc_new("number"); 138 mpc_parser_t *QuotedString = mpc_new("quoted_string"); 139 mpc_parser_t *LinePragma = mpc_new("linepragma"); 140 mpc_parser_t *Parser = mpc_new("parser"); 141 142 mpc_define(Line, mpca_tag(mpc_apply(mpc_sym("#line"), mpcf_str_ast), "string")); 143 144 err = mpca_lang(MPCA_LANG_PREDICTIVE, 145 "number : /[0-9]+/ ;\n" 146 "quoted_string : /\"(\\.|[^\"])*\"/ ;\n" 147 "linepragma : <line> <number> <quoted_string>;\n" 148 "parser : /^/ (<linepragma>)* /$/ ;\n", 149 Line, Number, QuotedString, LinePragma, Parser, NULL); 150 151 PT_ASSERT(err == NULL); 152 153 t0 = mpc_ast_build(3, ">", 154 mpc_ast_new("regex", ""), 155 mpc_ast_build(3, "linepragma|>", 156 mpc_ast_new("line|string", "#line"), 157 mpc_ast_new("number|regex", "10"), 158 mpc_ast_new("quoted_string|regex", "\"test\"")), 159 mpc_ast_new("regex", "")); 160 161 PT_ASSERT(mpc_test_pass(Parser, "#line 10 \"test\"", t0, 162 (int(*)(const void*,const void*))mpc_ast_eq, 163 (mpc_dtor_t)mpc_ast_delete, 164 (void(*)(const void*))mpc_ast_print)); 165 166 mpc_ast_delete(t0); 167 168 mpc_cleanup(5, Line, Number, QuotedString, LinePragma, Parser); 169 170 } 171 172 void test_qscript(void) { 173 174 mpc_ast_t *t0; 175 mpc_parser_t *Qscript = mpc_new("qscript"); 176 mpc_parser_t *Comment = mpc_new("comment"); 177 mpc_parser_t *Resource = mpc_new("resource"); 178 mpc_parser_t *Rtype = mpc_new("rtype"); 179 mpc_parser_t *Rname = mpc_new("rname"); 180 mpc_parser_t *InnerBlock = mpc_new("inner_block"); 181 mpc_parser_t *Statement = mpc_new("statement"); 182 mpc_parser_t *Function = mpc_new("function"); 183 mpc_parser_t *Parameter = mpc_new("parameter"); 184 mpc_parser_t *Literal = mpc_new("literal"); 185 mpc_parser_t *Block = mpc_new("block"); 186 mpc_parser_t *Seperator = mpc_new("seperator"); 187 mpc_parser_t *Qstring = mpc_new("qstring"); 188 mpc_parser_t *SimpleStr = mpc_new("simplestr"); 189 mpc_parser_t *ComplexStr = mpc_new("complexstr"); 190 mpc_parser_t *Number = mpc_new("number"); 191 mpc_parser_t *Float = mpc_new("float"); 192 mpc_parser_t *Int = mpc_new("int"); 193 194 mpc_err_t *err = mpca_lang(0, 195 " qscript : /^/ (<comment> | <resource>)* /$/ ;\n" 196 " comment : '#' /[^\\n]*/ ;\n" 197 "resource : '[' (<rtype> <rname>) ']' <inner_block> ;\n" 198 " rtype : /[*]*/ ;\n" 199 " rname : <qstring> ;\n" 200 "\n" 201 "inner_block : (<comment> | <statement>)* ;\n" 202 " statement : <function> '(' (<comment> | <parameter> | <block>)* ')' <seperator> ;\n" 203 " function : <qstring> ;\n" 204 " parameter : (<statement> | <literal>) ;\n" 205 " literal : (<number> | <qstring>) <seperator> ;\n" 206 " block : '{' <inner_block> '}' ;\n" 207 " seperator : ',' | \"\" ;\n" 208 "\n" 209 "qstring : (<complexstr> | <simplestr>) <qstring>* ;\n" 210 " simplestr : /[a-zA-Z0-9_!@#$%^&\\*_+\\-\\.=\\/<>]+/ ;\n" 211 " complexstr : (/\"[^\"]*\"/ | /'[^']*'/) ;\n" 212 "\n" 213 "number : (<float> | <int>) ;\n" 214 " float : /[-+]?[0-9]+\\.[0-9]+/ ;\n" 215 " int : /[-+]?[0-9]+/ ;\n", 216 Qscript, Comment, Resource, Rtype, Rname, InnerBlock, Statement, Function, 217 Parameter, Literal, Block, Seperator, Qstring, SimpleStr, ComplexStr, Number, 218 Float, Int, NULL); 219 220 PT_ASSERT(err == NULL); 221 222 t0 = mpc_ast_build(3, ">", 223 mpc_ast_new("regex", ""), 224 mpc_ast_build(5, "resource|>", 225 mpc_ast_new("char", "["), 226 mpc_ast_new("rtype|regex", ""), 227 mpc_ast_new("rname|qstring|simplestr|regex", "my_func"), 228 mpc_ast_new("char", "]"), 229 mpc_ast_build(5, "inner_block|statement|>", 230 mpc_ast_new("function|qstring|simplestr|regex", "echo"), 231 mpc_ast_new("char", "("), 232 mpc_ast_build(2, "parameter|literal|>", 233 mpc_ast_build(2, "qstring|>", 234 mpc_ast_new("simplestr|regex", "a"), 235 mpc_ast_build(2, "qstring|>", 236 mpc_ast_new("simplestr|regex", "b"), 237 mpc_ast_new("qstring|simplestr|regex", "c") 238 ) 239 ), 240 mpc_ast_new("seperator|string", "") 241 ), 242 mpc_ast_new("char", ")"), 243 mpc_ast_new("seperator|string", "") 244 ) 245 ), 246 mpc_ast_new("regex", "")); 247 248 PT_ASSERT(mpc_test_pass(Qscript, "[my_func]\n echo (a b c)\n", t0, 249 (int(*)(const void*,const void*))mpc_ast_eq, 250 (mpc_dtor_t)mpc_ast_delete, 251 (void(*)(const void*))mpc_ast_print)); 252 253 mpc_ast_delete(t0); 254 255 mpc_cleanup(18, Qscript, Comment, Resource, Rtype, Rname, InnerBlock, 256 Statement, Function, Parameter, Literal, Block, Seperator, Qstring, 257 SimpleStr, ComplexStr, Number, Float, Int); 258 259 } 260 261 void test_missingrule(void) { 262 263 int result; 264 mpc_err_t *err; 265 mpc_result_t r; 266 mpc_parser_t *Parser = mpc_new("parser"); 267 268 err = mpca_lang(MPCA_LANG_DEFAULT, 269 "parser : /^/ (<missing>)* /$/ ;\n", 270 Parser, NULL); 271 272 PT_ASSERT(err == NULL); 273 274 result = mpc_parse("<stdin>", "test", Parser, &r); 275 276 PT_ASSERT(result == 0); 277 PT_ASSERT(r.error != NULL); 278 PT_ASSERT(strcmp(r.error->failure, "Unknown Parser 'missing'!") == 0); 279 280 mpc_err_delete(r.error); 281 mpc_cleanup(1, Parser); 282 283 } 284 285 void test_regex_mode(void) { 286 287 mpc_parser_t *Line0, *Line1, *Line2, *Line3; 288 mpc_ast_t *t0, *t1, *t2, *t3, *t4; 289 290 Line0 = mpc_new("line0"); 291 Line1 = mpc_new("line1"); 292 Line2 = mpc_new("line2"); 293 Line3 = mpc_new("line3"); 294 295 mpca_lang(MPCA_LANG_DEFAULT, " line0 : /.*/; ", Line0); 296 mpca_lang(MPCA_LANG_DEFAULT, " line1 : /.*/s; ", Line1); 297 mpca_lang(MPCA_LANG_DEFAULT, " line2 : /(^[a-z]*$)*/; ", Line2); 298 mpca_lang(MPCA_LANG_DEFAULT, " line3 : /(^[a-z]*$)*/m; ", Line3); 299 300 t0 = mpc_ast_new("regex", "blah"); 301 t1 = mpc_ast_new("regex", "blah\nblah"); 302 t2 = mpc_ast_new("regex", ""); 303 t3 = mpc_ast_new("regex", "blah"); 304 t4 = mpc_ast_new("regex", "blah\nblah"); 305 306 PT_ASSERT(mpc_test_pass(Line0, "blah\nblah", t0, 307 (int(*)(const void*,const void*))mpc_ast_eq, 308 (mpc_dtor_t)mpc_ast_delete, 309 (void(*)(const void*))mpc_ast_print)); 310 311 PT_ASSERT(mpc_test_pass(Line1, "blah\nblah", t1, 312 (int(*)(const void*,const void*))mpc_ast_eq, 313 (mpc_dtor_t)mpc_ast_delete, 314 (void(*)(const void*))mpc_ast_print)); 315 316 PT_ASSERT(mpc_test_pass(Line2, "blah\nblah", t2, 317 (int(*)(const void*,const void*))mpc_ast_eq, 318 (mpc_dtor_t)mpc_ast_delete, 319 (void(*)(const void*))mpc_ast_print)); 320 321 PT_ASSERT(mpc_test_pass(Line2, "blah", t3, 322 (int(*)(const void*,const void*))mpc_ast_eq, 323 (mpc_dtor_t)mpc_ast_delete, 324 (void(*)(const void*))mpc_ast_print)); 325 326 PT_ASSERT(mpc_test_pass(Line3, "blah\nblah", t4, 327 (int(*)(const void*,const void*))mpc_ast_eq, 328 (mpc_dtor_t)mpc_ast_delete, 329 (void(*)(const void*))mpc_ast_print)); 330 331 mpc_ast_delete(t0); 332 mpc_ast_delete(t1); 333 mpc_ast_delete(t2); 334 mpc_ast_delete(t3); 335 mpc_ast_delete(t4); 336 337 mpc_cleanup(4, Line0, Line1, Line2, Line3); 338 } 339 340 void test_digits_file(void) { 341 342 FILE *f; 343 mpc_result_t r; 344 mpc_parser_t *Digit = mpc_new("digit"); 345 mpc_parser_t *Program = mpc_new("program"); 346 mpc_ast_t* t0; 347 348 mpc_err_t* err = mpca_lang(MPCA_LANG_DEFAULT, 349 " digit : /[0-9]/ ;" 350 " program : /^/ <digit>+ /$/ ;" 351 , Digit, Program, NULL); 352 353 PT_ASSERT(err == NULL); 354 355 t0 = mpc_ast_build(5, ">", 356 mpc_ast_new("regex", ""), 357 mpc_ast_new("digit|regex", "1"), 358 mpc_ast_new("digit|regex", "2"), 359 mpc_ast_new("digit|regex", "3"), 360 mpc_ast_new("regex", "")); 361 362 if (mpc_parse_contents("tests/digits.txt", Program, &r)) { 363 PT_ASSERT(1); 364 PT_ASSERT(mpc_ast_eq(t0, r.output)); 365 mpc_ast_delete(r.output); 366 } else { 367 PT_ASSERT(0); 368 mpc_err_print(r.error); 369 mpc_err_delete(r.error); 370 } 371 372 f = fopen("tests/digits.txt", "r"); 373 PT_ASSERT(f != NULL); 374 375 if (mpc_parse_file("tests/digits.txt", f, Program, &r)) { 376 PT_ASSERT(1); 377 PT_ASSERT(mpc_ast_eq(t0, r.output)); 378 mpc_ast_delete(r.output); 379 } else { 380 PT_ASSERT(0); 381 mpc_err_print(r.error); 382 mpc_err_delete(r.error); 383 } 384 385 fclose(f); 386 387 if (mpc_parse("tests/digits.txt", "123", Program, &r)) { 388 PT_ASSERT(1); 389 PT_ASSERT(mpc_ast_eq(t0, r.output)); 390 mpc_ast_delete(r.output); 391 } else { 392 PT_ASSERT(0); 393 mpc_err_print(r.error); 394 mpc_err_delete(r.error); 395 } 396 397 mpc_ast_delete(t0); 398 399 mpc_cleanup(2, Digit, Program); 400 401 } 402 403 void suite_grammar(void) { 404 pt_add_test(test_grammar, "Test Grammar", "Suite Grammar"); 405 pt_add_test(test_language, "Test Language", "Suite Grammar"); 406 pt_add_test(test_language_file, "Test Language File", "Suite Grammar"); 407 pt_add_test(test_doge, "Test Doge", "Suite Grammar"); 408 pt_add_test(test_partial, "Test Partial", "Suite Grammar"); 409 pt_add_test(test_qscript, "Test QScript", "Suite Grammar"); 410 pt_add_test(test_missingrule, "Test Missing Rule", "Suite Grammar"); 411 pt_add_test(test_regex_mode, "Test Regex Mode", "Suite Grammar"); 412 pt_add_test(test_digits_file, "Test Digits File", "Suite Grammar"); 413 }