diff --git a/README.md b/README.md index b918603..be6322a 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ Micro Parser Combinators ======================== -Version 0.8.7 +Version 0.8.8 About diff --git a/mpc.c b/mpc.c index e2b58ba..1801606 100644 --- a/mpc.c +++ b/mpc.c @@ -2730,6 +2730,14 @@ mpc_ast_t *mpc_ast_add_tag(mpc_ast_t *a, const char *t) { return a; } +mpc_ast_t *mpc_ast_add_root_tag(mpc_ast_t *a, const char *t) { + if (a == NULL) { return a; } + a->tag = realloc(a->tag, (strlen(t)-1) + strlen(a->tag) + 1); + memmove(a->tag + (strlen(t)-1), a->tag, strlen(a->tag)+1); + memmove(a->tag, t, (strlen(t)-1)); + return a; +} + mpc_ast_t *mpc_ast_tag(mpc_ast_t *a, const char *t) { a->tag = realloc(a->tag, strlen(t) + 1); strcpy(a->tag, t); @@ -2961,16 +2969,16 @@ mpc_val_t *mpcf_fold_ast(int n, mpc_val_t **xs) { if (as[i] == NULL) { continue; } - if (as[i] && as[i]->children_num > 0) { - + if (as[i] && as[i]->children_num == 0) { + mpc_ast_add_child(r, as[i]); + } else if (as[i] && as[i]->children_num == 1) { + mpc_ast_add_child(r, mpc_ast_add_root_tag(as[i]->children[0], as[i]->tag)); + mpc_ast_delete_no_children(as[i]); + } else if (as[i] && as[i]->children_num >= 2) { for (j = 0; j < as[i]->children_num; j++) { mpc_ast_add_child(r, as[i]->children[j]); } - mpc_ast_delete_no_children(as[i]); - - } else if (as[i] && as[i]->children_num == 0) { - mpc_ast_add_child(r, as[i]); } } diff --git a/mpc.h b/mpc.h index 5dec3af..9fd678f 100644 --- a/mpc.h +++ b/mpc.h @@ -269,6 +269,7 @@ mpc_ast_t *mpc_ast_build(int n, const char *tag, ...); mpc_ast_t *mpc_ast_add_root(mpc_ast_t *a); mpc_ast_t *mpc_ast_add_child(mpc_ast_t *r, mpc_ast_t *a); mpc_ast_t *mpc_ast_add_tag(mpc_ast_t *a, const char *t); +mpc_ast_t *mpc_ast_add_root_tag(mpc_ast_t *a, const char *t); mpc_ast_t *mpc_ast_tag(mpc_ast_t *a, const char *t); mpc_ast_t *mpc_ast_state(mpc_ast_t *a, mpc_state_t s); diff --git a/package.json b/package.json index f398f3b..adcb3bf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mpc", - "version": "0.8.7", + "version": "0.8.8", "repo": "orangeduck/mpc", "description": "A Parser Combinator library for C", "keywords": ["parser", "combinator", "library", "c", "mpc"], diff --git a/tests/grammar.c b/tests/grammar.c index 069e28a..ddf2824 100644 --- a/tests/grammar.c +++ b/tests/grammar.c @@ -25,7 +25,7 @@ void test_grammar(void) { t2 = mpc_ast_build(3, ">", - mpc_ast_build(3, "value|>", + mpc_ast_build(3, "product|value|>", mpc_ast_new("char", "("), mpc_ast_build(3, "expression|>", @@ -167,10 +167,98 @@ void test_partial(void) { } +void test_qscript(void) { + + mpc_ast_t *t0; + mpc_parser_t *Qscript = mpc_new("qscript"); + mpc_parser_t *Comment = mpc_new("comment"); + mpc_parser_t *Resource = mpc_new("resource"); + mpc_parser_t *Rtype = mpc_new("rtype"); + mpc_parser_t *Rname = mpc_new("rname"); + mpc_parser_t *InnerBlock = mpc_new("inner_block"); + mpc_parser_t *Statement = mpc_new("statement"); + mpc_parser_t *Function = mpc_new("function"); + mpc_parser_t *Parameter = mpc_new("parameter"); + mpc_parser_t *Literal = mpc_new("literal"); + mpc_parser_t *Block = mpc_new("block"); + mpc_parser_t *Seperator = mpc_new("seperator"); + mpc_parser_t *Qstring = mpc_new("qstring"); + mpc_parser_t *SimpleStr = mpc_new("simplestr"); + mpc_parser_t *ComplexStr = mpc_new("complexstr"); + mpc_parser_t *Number = mpc_new("number"); + mpc_parser_t *Float = mpc_new("float"); + mpc_parser_t *Int = mpc_new("int"); + + mpc_err_t *err = mpca_lang(0, + " qscript : /^/ ( | )* /$/ ;\n" + " comment : '#' /[^\\n]*/ ;\n" + "resource : '[' ( ) ']' ;\n" + " rtype : /[*]*/ ;\n" + " rname : ;\n" + "\n" + "inner_block : ( | )* ;\n" + " statement : '(' ( | | )* ')' ;\n" + " function : ;\n" + " parameter : ( | ) ;\n" + " literal : ( | ) ;\n" + " block : '{' '}' ;\n" + " seperator : ',' | \"\" ;\n" + "\n" + "qstring : ( | ) * ;\n" + " simplestr : /[a-zA-Z0-9_!@#$%^&\\*_+\\-\\.=\\/<>]+/ ;\n" + " complexstr : (/\"[^\"]*\"/ | /'[^']*'/) ;\n" + "\n" + "number : ( | ) ;\n" + " float : /[-+]?[0-9]+\\.[0-9]+/ ;\n" + " int : /[-+]?[0-9]+/ ;\n", + Qscript, Comment, Resource, Rtype, Rname, InnerBlock, Statement, Function, + Parameter, Literal, Block, Seperator, Qstring, SimpleStr, ComplexStr, Number, + Float, Int, NULL); + + PT_ASSERT(err == NULL); + + t0 = mpc_ast_build(3, ">", + mpc_ast_new("regex", ""), + mpc_ast_build(5, "resource|>", + mpc_ast_new("char", "["), + mpc_ast_new("rtype|regex", ""), + mpc_ast_new("rname|qstring|simplestr|regex", "my_func"), + mpc_ast_new("char", "]"), + mpc_ast_build(5, "inner_block|statement|>", + mpc_ast_new("function|qstring|simplestr|regex", "echo"), + mpc_ast_new("char", "("), + mpc_ast_build(2, "parameter|literal|>", + mpc_ast_build(2, "qstring|>", + mpc_ast_new("simplestr|regex", "a"), + mpc_ast_build(2, "qstring|>", + mpc_ast_new("simplestr|regex", "b"), + mpc_ast_new("qstring|simplestr|regex", "c") + ) + ), + mpc_ast_new("seperator|string", "") + ), + mpc_ast_new("char", ")"), + mpc_ast_new("seperator|string", "") + ) + ), + mpc_ast_new("regex", "")); + + PT_ASSERT(mpc_test_pass(Qscript, "[my_func]\n echo (a b c)\n", t0, + (int(*)(const void*,const void*))mpc_ast_eq, + (mpc_dtor_t)mpc_ast_delete, + (void(*)(const void*))mpc_ast_print)); + + mpc_cleanup(18, Qscript, Comment, Resource, Rtype, Rname, InnerBlock, + Statement, Function, Parameter, Literal, Block, Seperator, Qstring, + SimpleStr, ComplexStr, Number, Float, Int); + +} + void suite_grammar(void) { pt_add_test(test_grammar, "Test Grammar", "Suite Grammar"); pt_add_test(test_language, "Test Language", "Suite Grammar"); pt_add_test(test_language_file, "Test Language File", "Suite Grammar"); pt_add_test(test_doge, "Test Doge", "Suite Grammar"); pt_add_test(test_partial, "Test Partial", "Suite Grammar"); + pt_add_test(test_qscript, "Test QScript", "Suite Grammar"); }