mumble

A Lisp written in C, following the *Build Your Own Lisp* book
Log | Files | Refs | README

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 }