diff --git a/.gitignore b/.gitignore index 2f681f8..ffac557 100644 --- a/.gitignore +++ b/.gitignore @@ -48,3 +48,4 @@ debian/libcleri-dev/ debian/libcleri0.debhelper.log debian/libcleri0.substvars debian/libcleri0/ +debian/tmp/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d5519fd..0c86910 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -45,7 +45,7 @@ git commit -am 'some work that has been done' Create archive from code ``` -git archive -o ../libcleri_0.10.0.orig.tar.gz master +git archive -o ../libcleri_0.10.1.orig.tar.gz master ``` Build deb package diff --git a/README.md b/README.md index b50bb78..e639c3b 100644 --- a/README.md +++ b/README.md @@ -293,13 +293,13 @@ Example: ```c // In case a translation function returns an empty string, no text is used const char * translate(cleri_t * o) { - return ""; // a possible result might be: `error at position x` + return ""; // a possible result might be: `error at line 0, position x` } // Text may be returned based on gid const char * translate(cleri_t * o) { switch (o->gid) { - case 1: return "A"; // error at position x, expecting: A + case 1: return "A"; // error at line 0, position x, expecting: A case 2: return ""; // gid 2 will be ignored } return NULL; // normal parsing for everything else diff --git a/Release/makefile b/Release/makefile index 75c8c3f..9b2dbc1 100644 --- a/Release/makefile +++ b/Release/makefile @@ -1,12 +1,7 @@ -################################################################################ -# Automatically-generated file. Do not edit! -################################################################################ - -include ../makefile.init RM := rm -rf -# All of the sources participating in the build are defined here -include sources.mk -include src/subdir.mk -include subdir.mk @@ -31,8 +26,6 @@ INSTALL_PATH := /usr SO_NAME := soname endif -# Add inputs and outputs from these tool invocations to the build variables - # All Target all: libcleri diff --git a/Release/objects.mk b/Release/objects.mk index 7f4b172..c39de1f 100644 --- a/Release/objects.mk +++ b/Release/objects.mk @@ -1,7 +1,3 @@ -################################################################################ -# Automatically-generated file. Do not edit! -################################################################################ - USER_OBJS := LIBS := -lpcre2-8 diff --git a/Release/sources.mk b/Release/sources.mk index a1c58f7..92b27f4 100644 --- a/Release/sources.mk +++ b/Release/sources.mk @@ -1,17 +1,12 @@ -################################################################################ -# Automatically-generated file. Do not edit! -################################################################################ +OBJ_SRCS := +ASM_SRCS := +C_SRCS := +O_SRCS := +S_UPPER_SRCS := +EXECUTABLES := +OBJS := +C_DEPS := -OBJ_SRCS := -ASM_SRCS := -C_SRCS := -O_SRCS := -S_UPPER_SRCS := -EXECUTABLES := -OBJS := -C_DEPS := - -# Every subdirectory with source files must be described here SUBDIRS := \ src \ diff --git a/Release/src/subdir.mk b/Release/src/subdir.mk index 240aa38..963c239 100644 --- a/Release/src/subdir.mk +++ b/Release/src/subdir.mk @@ -1,8 +1,3 @@ -################################################################################ -# Automatically-generated file. Do not edit! -################################################################################ - -# Add inputs and outputs from these tool invocations to the build variables C_SRCS += \ ../src/children.c \ ../src/choice.c \ @@ -25,7 +20,9 @@ C_SRCS += \ ../src/sequence.c \ ../src/this.c \ ../src/token.c \ -../src/tokens.c +../src/tokens.c \ +../src/version.c + OBJS += \ ./src/children.o \ @@ -49,7 +46,8 @@ OBJS += \ ./src/sequence.o \ ./src/this.o \ ./src/token.o \ -./src/tokens.o +./src/tokens.o \ +./src/version.o C_DEPS += \ ./src/children.d \ @@ -73,14 +71,12 @@ C_DEPS += \ ./src/sequence.d \ ./src/this.d \ ./src/token.d \ -./src/tokens.d +./src/tokens.d \ +./src/version.d -# Each subdirectory must supply rules for building sources it contributes src/%.o: ../src/%.c @echo 'Building file: $<' @echo 'Invoking: Cross GCC Compiler' gcc -DNDEBUG -I../inc -O3 -Wall $(CPPFLAGS) $(CFLAGS) -c -fmessage-length=0 -fPIC -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" @echo 'Finished building: $<' @echo ' ' - - diff --git a/Release/subdir.mk b/Release/subdir.mk deleted file mode 100644 index 1957028..0000000 --- a/Release/subdir.mk +++ /dev/null @@ -1,8 +0,0 @@ -################################################################################ -# Automatically-generated file. Do not edit! -################################################################################ - -# Add inputs and outputs from these tool invocations to the build variables - -# Each subdirectory must supply rules for building sources it contributes - diff --git a/debian/changelog b/debian/changelog index 3a14275..aae8bec 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,27 @@ +libcleri (0.11.0-0~tt1) unstable; urgency=medium + + * Added cleri_parse2() which accepts an additional `flags` argument + * Improved syntax error handling + * Set correct position when nested error in syntax is found + + -- Jeroen van der Heijden Tue, 22 Oct 2019 10:59:14 +0200 + +libcleri (0.10.1-0~alpha1-tt1) unstable; urgency=medium + + * Added option to disable generating expecting info + + -- Jeroen van der Heijden Mon, 12 Nov 2018 14:34:16 +0100 + +libcleri (0.10.1-0~alpha0-tt1) unstable; urgency=medium + + * Added `void *data` to node type for public usage + * Children will only be added to a node when necessary + (Be carefull that accessing the first child therefore + must be checked for NULL whereas in previous versions, + one could immediately check the `children->node` pointer) + + -- Jeroen van der Heijden Wed, 31 Oct 2018 22:22:05 +0100 + libcleri (0.10.0-0~tt1) unstable; urgency=medium * Update deb test diff --git a/debian/libcleri0.symbols b/debian/libcleri0.symbols index a781039..8c6b677 100644 --- a/debian/libcleri0.symbols +++ b/debian/libcleri0.symbols @@ -4,7 +4,6 @@ libcleri.so.0 libcleri0 #MINVER# CLERI_THIS@Base 0.9.3 cleri__children_add@Base 0.9.3 cleri__children_free@Base 0.9.3 - cleri__children_new@Base 0.9.3 cleri__expecting_combine@Base 0.9.3 cleri__expecting_free@Base 0.9.3 cleri__expecting_new@Base 0.9.3 @@ -35,7 +34,7 @@ libcleri.so.0 libcleri0 #MINVER# cleri_list@Base 0.9.3 cleri_new@Base 0.9.3 cleri_optional@Base 0.9.3 - cleri_parse@Base 0.9.3 + cleri_parse2@Base 0.10.1~ cleri_parse_expect_start@Base 0.9.3 cleri_parse_free@Base 0.9.3 cleri_parse_strn@Base 0.10.0~ @@ -47,3 +46,4 @@ libcleri.so.0 libcleri0 #MINVER# cleri_sequence@Base 0.9.3 cleri_token@Base 0.9.3 cleri_tokens@Base 0.9.3 + cleri_version@Base 0.10.1~ diff --git a/inc/cleri/children.h b/inc/cleri/children.h index b230380..f520033 100644 --- a/inc/cleri/children.h +++ b/inc/cleri/children.h @@ -11,9 +11,8 @@ typedef struct cleri_node_s cleri_node_t; typedef struct cleri_children_s cleri_children_t; /* private functions */ -cleri_children_t * cleri__children_new(void); void cleri__children_free(cleri_children_t * children); -int cleri__children_add(cleri_children_t * children, cleri_node_t * node); +int cleri__children_add(cleri_children_t ** children, cleri_node_t * node); /* structs */ struct cleri_children_s diff --git a/inc/cleri/cleri.h b/inc/cleri/cleri.h index e7e31a6..eabe606 100644 --- a/inc/cleri/cleri.h +++ b/inc/cleri/cleri.h @@ -10,6 +10,12 @@ #define cleri__malloc(__t) (malloc(sizeof(__t))) #endif +#ifdef __cplusplus +#define cleri__mallocn(__n, __t) ((__t*)malloc(__n * sizeof(__t))) +#else +#define cleri__mallocn(__n, __t) (malloc(__n * sizeof(__t))) +#endif + #include #include #include @@ -28,6 +34,7 @@ #include #include #include +#include /* typedefs */ typedef struct cleri_s cleri_t; diff --git a/inc/cleri/expecting.h b/inc/cleri/expecting.h index e578604..34420d6 100644 --- a/inc/cleri/expecting.h +++ b/inc/cleri/expecting.h @@ -20,7 +20,7 @@ typedef struct cleri_exp_modes_s cleri_exp_modes_t; typedef struct cleri_expecting_s cleri_expecting_t; /* private functions */ -cleri_expecting_t * cleri__expecting_new(const char * str); +cleri_expecting_t * cleri__expecting_new(const char * str, int flags); int cleri__expecting_update( cleri_expecting_t * expecting, cleri_t * cl_obj, diff --git a/inc/cleri/kwcache.h b/inc/cleri/kwcache.h index fb67b77..d986b76 100644 --- a/inc/cleri/kwcache.h +++ b/inc/cleri/kwcache.h @@ -10,20 +10,20 @@ /* typedefs */ typedef struct cleri_parse_s cleri_parse_t; -typedef struct cleri_kwcache_s cleri_kwcache_t; /* private functions */ -cleri_kwcache_t * cleri__kwcache_new(void); +uint8_t * cleri__kwcache_new(const char * str); ssize_t cleri__kwcache_match(cleri_parse_t * pr, const char * str); -void cleri__kwcache_free(cleri_kwcache_t * kwcache); +static inline void cleri__kwcache_free(uint8_t * kwcache); -/* structs */ -struct cleri_kwcache_s + +/* + * Destroy kwcache. (parsing NULL is allowed) + */ +static inline void cleri__kwcache_free(uint8_t * kwcache) { - size_t len; - const char * str; - cleri_kwcache_t * next; -}; + free(kwcache); +} #endif /* CLERI_KWCACHE_H_ */ diff --git a/inc/cleri/node.h b/inc/cleri/node.h index ac071bc..5685634 100644 --- a/inc/cleri/node.h +++ b/inc/cleri/node.h @@ -34,10 +34,11 @@ struct cleri_node_s size_t len; cleri_t * cl_obj; cleri_children_t * children; + void * data; /* free to use by the user */ /* private */ - uint_fast8_t ref; - int64_t result; + size_t ref; + int64_t result; /* DEPRECATED */ }; #endif /* CLERI_NODE_H_ */ \ No newline at end of file diff --git a/inc/cleri/olist.h b/inc/cleri/olist.h index b35941c..6e4e4d0 100644 --- a/inc/cleri/olist.h +++ b/inc/cleri/olist.h @@ -18,6 +18,7 @@ int cleri__olist_append_nref(cleri_olist_t * olist, cleri_t * cl_object); void cleri__olist_free(cleri_olist_t * olist); void cleri__olist_empty(cleri_olist_t * olist); void cleri__olist_cancel(cleri_olist_t * olist); +void cleri__olist_unique(cleri_olist_t * olist); /* structs */ struct cleri_olist_s diff --git a/inc/cleri/parse.h b/inc/cleri/parse.h index 8f5578a..876da2e 100644 --- a/inc/cleri/parse.h +++ b/inc/cleri/parse.h @@ -14,15 +14,22 @@ #include #ifndef MAX_RECURSION_DEPTH -#define MAX_RECURSION_DEPTH 50 +#define MAX_RECURSION_DEPTH 500 #endif +enum +{ + CLERI_FLAG_EXPECTING_DISABLED =1<<0, + CLERI_FLAG_EXCLUDE_OPTIONAL =1<<1, + CLERI_FLAG_EXCLUDE_FM_CHOICE =1<<2, + CLERI_FLAG_EXCLUDE_RULE_THIS =1<<3, +}; + /* typedefs */ typedef struct cleri_s cleri_t; typedef struct cleri_grammar_s cleri_grammar_t; typedef struct cleri_node_s cleri_node_t; typedef struct cleri_expecting_s cleri_expecting_t; -typedef struct cleri_kwcache_s cleri_kwcache_t; typedef struct cleri_rule_store_s cleri_rule_store_t; typedef struct cleri_parse_s cleri_parse_t; typedef const char * (cleri_translate_t)(cleri_t *); @@ -32,7 +39,13 @@ typedef const char * (cleri_translate_t)(cleri_t *); extern "C" { #endif -cleri_parse_t * cleri_parse(cleri_grammar_t * grammar, const char * str); +static inline cleri_parse_t * cleri_parse( + cleri_grammar_t * grammar, + const char * str); +cleri_parse_t * cleri_parse2( + cleri_grammar_t * grammar, + const char * str, + int flags); void cleri_parse_free(cleri_parse_t * pr); void cleri_parse_expect_start(cleri_parse_t * pr); int cleri_parse_strn( @@ -57,6 +70,7 @@ cleri_node_t * cleri__parse_walk( struct cleri_parse_s { int is_valid; + int flags; size_t pos; const char * str; cleri_node_t * tree; @@ -64,7 +78,14 @@ struct cleri_parse_s cleri_expecting_t * expecting; pcre2_code * re_keywords; pcre2_match_data * match_data; - cleri_kwcache_t * kwcache; + uint8_t * kwcache; }; -#endif /* CLERI_PARSE_H_ */ \ No newline at end of file +static inline cleri_parse_t * cleri_parse( + cleri_grammar_t * grammar, + const char * str) +{ + return cleri_parse2(grammar, str, 0); +} + +#endif /* CLERI_PARSE_H_ */ diff --git a/inc/cleri/version.h b/inc/cleri/version.h index 0b88ec5..cbcf4a3 100644 --- a/inc/cleri/version.h +++ b/inc/cleri/version.h @@ -4,7 +4,7 @@ #ifndef CLERI_VERSION_H_ #define CLERI_VERSION_H_ -#define LIBCLERI_VERSION "0.10.0" +#define LIBCLERI_VERSION "0.11.0" /* public funtion */ #ifdef __cplusplus diff --git a/makefile.init b/makefile.init index 5b3f1b8..30bdc79 100644 --- a/makefile.init +++ b/makefile.init @@ -1,4 +1,4 @@ MAJOR := 0 MINOR := 10 -PATCH := 0 +PATCH := 1 VERSION := $(MAJOR).$(MINOR).$(PATCH) \ No newline at end of file diff --git a/src/children.c b/src/children.c index 29be844..d1786ae 100644 --- a/src/children.c +++ b/src/children.c @@ -4,48 +4,44 @@ #include #include -/* - * Returns NULL and in case an error has occurred. - */ -cleri_children_t * cleri__children_new(void) -{ - cleri_children_t * children = cleri__malloc(cleri_children_t); - if (children != NULL) - { - children->node = NULL; - children->next = NULL; - } - return children; -} - /* * Appends a node to children. * * Returns 0 when successful or -1 in case of an error. */ -int cleri__children_add(cleri_children_t * children, cleri_node_t * node) +int cleri__children_add(cleri_children_t ** children, cleri_node_t * node) { - if (children->node == NULL) + cleri_children_t * child; + if (*children == NULL) { - children->node = node; + *children = cleri__malloc(cleri_children_t); + if (*children == NULL) + { + return -1; + } + + (*children)->node = node; + (*children)->next = NULL; + return 0; } - while (children->next != NULL) + child = *children; + + while (child->next != NULL) { - children = children->next; + child = child->next; } - children->next = cleri__malloc(cleri_children_t); - if (children->next == NULL) + child->next = cleri__malloc(cleri_children_t); + if (child->next == NULL) { return -1; } - else - { - children->next->node = node; - children->next->next = NULL; - } + + child->next->node = node; + child->next->next = NULL; + return 0; } @@ -63,4 +59,3 @@ void cleri__children_free(cleri_children_t * children) children = next; } } - diff --git a/src/choice.c b/src/choice.c index 1b8d103..fe24016 100644 --- a/src/choice.c +++ b/src/choice.c @@ -147,7 +147,7 @@ static cleri_node_t * choice__parse_most_greedy( if (mg_node != NULL) { parent->len += mg_node->len; - if (cleri__children_add(parent->children, mg_node)) + if (cleri__children_add(&parent->children, mg_node)) { /* error occurred, reverse changes set mg_node to NULL */ pr->is_valid = -1; @@ -173,6 +173,26 @@ static cleri_node_t * choice__parse_first_match( cleri_node_t * rnode; olist = cl_obj->via.choice->olist; + + if ((pr->flags & CLERI_FLAG_EXCLUDE_FM_CHOICE) && !cl_obj->gid) + { + while (olist != NULL) + { + node = cleri__parse_walk( + pr, + parent, + olist->cl_obj, + rule, + CLERI__EXP_MODE_REQUIRED); + if (node != NULL) + { + return node; + } + olist = olist->next; + } + return NULL; + } + node = cleri__node_new(cl_obj, parent->str + parent->len, 0); if (node == NULL) { @@ -190,7 +210,7 @@ static cleri_node_t * choice__parse_first_match( if (rnode != NULL) { parent->len += node->len; - if (cleri__children_add(parent->children, node)) + if (cleri__children_add(&parent->children, node)) { /* error occurred, reverse changes set mg_node to NULL */ pr->is_valid = -1; diff --git a/src/expecting.c b/src/expecting.c index a461f74..2bd5cdc 100644 --- a/src/expecting.c +++ b/src/expecting.c @@ -5,6 +5,7 @@ #include #include + static void expecting__empty(cleri_expecting_t * expecting); static int expecting__get_mode(cleri_exp_modes_t * modes, const char * str); static void expecting__shift_modes( @@ -15,13 +16,21 @@ static void expecting__modes_free(cleri_exp_modes_t * modes); /* * Returns NULL in case an error has occurred. */ -cleri_expecting_t * cleri__expecting_new(const char * str) +cleri_expecting_t * cleri__expecting_new(const char * str, int flags) { cleri_expecting_t * expecting = cleri__malloc(cleri_expecting_t); if (expecting != NULL) { expecting->str = str; + expecting->modes = NULL; + + if (flags & CLERI_FLAG_EXPECTING_DISABLED) + { + expecting->required = NULL; + expecting->optional = NULL; + return expecting; + } if ((expecting->required = cleri__olist_new()) == NULL) { @@ -36,7 +45,6 @@ cleri_expecting_t * cleri__expecting_new(const char * str) return NULL; } - expecting->modes = NULL; } return expecting; @@ -51,6 +59,14 @@ int cleri__expecting_update( const char * str) { int rc = 0; + if (expecting->required == NULL) + { + if (str > expecting->str) + { + expecting->str = str; + } + return 0; + } if (str > expecting->str) { diff --git a/src/keyword.c b/src/keyword.c index 59845ae..31537c2 100644 --- a/src/keyword.c +++ b/src/keyword.c @@ -4,6 +4,7 @@ #include #include #include +#include static void keyword__free(cleri_t * cl_object); @@ -14,10 +15,16 @@ static cleri_node_t * keyword__parse( cleri_rule_store_t * rule); /* + * Keywords must match the `keyword` regular expression defined by the grammar, + * and should have more than 0 and less than 255 characters. + * * Returns NULL in case an error has occurred. */ cleri_t * cleri_keyword(uint32_t gid, const char * keyword, int ign_case) { + size_t n = strlen(keyword); + assert (n > 0 && n < UINT8_MAX); + cleri_t * cl_object = cleri_new( gid, CLERI_TP_KEYWORD, @@ -39,7 +46,7 @@ cleri_t * cleri_keyword(uint32_t gid, const char * keyword, int ign_case) cl_object->via.keyword->keyword = keyword; cl_object->via.keyword->ign_case = ign_case; - cl_object->via.keyword->len = strlen(keyword); + cl_object->via.keyword->len = n; return cl_object; } @@ -83,7 +90,7 @@ static cleri_node_t * keyword__parse( if ((node = cleri__node_new(cl_obj, str, match_len)) != NULL) { parent->len += node->len; - cleri__children_add(parent->children, node); + cleri__children_add(&parent->children, node); } } else diff --git a/src/kwcache.c b/src/kwcache.c index 036c172..9557ffa 100644 --- a/src/kwcache.c +++ b/src/kwcache.c @@ -7,23 +7,25 @@ #include #include #include +#include + +#define NOT_FOUND UINT8_MAX static void kwcache__kw_match( - cleri_kwcache_t * kwcache, + uint8_t * kwcache, cleri_parse_t * pr, const char * str); /* * Returns NULL in case an error has occurred. */ -cleri_kwcache_t * cleri__kwcache_new(void) +uint8_t * cleri__kwcache_new(const char * str) { - cleri_kwcache_t * kwcache = cleri__malloc(cleri_kwcache_t); + size_t n = strlen(str); + uint8_t * kwcache = cleri__mallocn(n, uint8_t); if (kwcache != NULL) { - kwcache->len = 0; - kwcache->str = NULL; - kwcache->next = NULL; + memset(kwcache, NOT_FOUND, n * sizeof(uint8_t)); } return kwcache; } @@ -36,79 +38,43 @@ ssize_t cleri__kwcache_match( cleri_parse_t * pr, const char * str) { - cleri_kwcache_t * kwcache = pr->kwcache; - if (kwcache->str != NULL) - { - while (1) - { - if (str == kwcache->str) - { - return kwcache->len; - } + uint8_t * len; - if (kwcache->next == NULL) - { - break; - } - kwcache = kwcache->next; - } - kwcache->next = cleri__malloc(cleri_kwcache_t); - if (kwcache->next == NULL) - { - return -1; - } - kwcache = kwcache->next; - kwcache->len = 0; - kwcache->next = NULL; + if (*str == '\0') + { + return 0; } - kwcache->str = str; - kwcache__kw_match(kwcache, pr, str); - return kwcache->len; -} + len = &pr->kwcache[str - pr->str]; -/* - * Destroy kwcache. (parsing NULL is allowed) - */ -void cleri__kwcache_free(cleri_kwcache_t * kwcache) -{ - cleri_kwcache_t * next; - while (kwcache != NULL) + if (*len == NOT_FOUND) { - next = kwcache->next; - free(kwcache); - kwcache = next; + kwcache__kw_match(len, pr, str); } + + return *len; } /* * This function will set kwcache->len if a match is found. */ static void kwcache__kw_match( - cleri_kwcache_t * kwcache, + uint8_t * kwcache, cleri_parse_t * pr, const char * str) { int pcre_exec_ret; - PCRE2_SIZE * ovector; - pcre_exec_ret = pcre2_match( pr->re_keywords, (PCRE2_SPTR8) str, - strlen(str), + PCRE2_ZERO_TERMINATED, 0, // start looking at this point 0, // OPTIONS pr->match_data, NULL); - if (pcre_exec_ret < 0) - { - return; - } - - ovector = pcre2_get_ovector_pointer(pr->match_data); - kwcache->len = ovector[1]; - - + *kwcache = pcre_exec_ret < 0 + ? 0 + : pcre2_get_ovector_pointer(pr->match_data)[1]; } diff --git a/src/list.c b/src/list.c index 5d8c8cb..48a6d7e 100644 --- a/src/list.c +++ b/src/list.c @@ -126,7 +126,7 @@ static cleri_node_t * list__parse( return NULL; } parent->len += node->len; - if (cleri__children_add(parent->children, node)) + if (cleri__children_add(&parent->children, node)) { /* error occurred, reverse changes set mg_node to NULL */ pr->is_valid = -1; diff --git a/src/node.c b/src/node.c index 8cd36ca..605983d 100644 --- a/src/node.c +++ b/src/node.c @@ -28,22 +28,7 @@ cleri_node_t * cleri__node_new(cleri_t * cl_obj, const char * str, size_t len) node->str = str; node->len = len; - - if (cl_obj == NULL || cl_obj->tp <= CLERI_TP_THIS) - { - /* NULL when initializing the root node but we do need children */ - node->children = cleri__children_new(); - if (node->children == NULL) - { - free(node); - return NULL; - } - } - else - { - /* we do not need children for some objects */ - node->children = NULL; - } + node->children = NULL; } return node; } diff --git a/src/olist.c b/src/olist.c index 3ae23ca..c6c100d 100644 --- a/src/olist.c +++ b/src/olist.c @@ -155,3 +155,23 @@ void cleri__olist_cancel(cleri_olist_t * olist) } cleri__olist_empty(olist); } + +void cleri__olist_unique(cleri_olist_t * olist) +{ + while (olist != NULL && olist->next != NULL) + { + cleri_olist_t * test = olist; + while (test->next != NULL) + { + if (olist->cl_obj == test->next->cl_obj) + { + cleri_olist_t * tmp = test->next->next; + free(test->next); + test->next = tmp; + continue; + } + test = test->next; + } + olist = olist->next; + } +} \ No newline at end of file diff --git a/src/optional.c b/src/optional.c index e45045b..cf32c1e 100644 --- a/src/optional.c +++ b/src/optional.c @@ -70,21 +70,34 @@ static cleri_node_t * optional__parse( cleri_node_t * node; cleri_node_t * rnode; + if ((pr->flags & CLERI_FLAG_EXCLUDE_OPTIONAL) && !cl_obj->gid) + { + node = cleri__parse_walk( + pr, + parent, + cl_obj->via.optional->cl_obj, + rule, + CLERI__EXP_MODE_OPTIONAL); + return node ? node : CLERI_EMPTY_NODE; + } + if ((node = cleri__node_new(cl_obj, parent->str + parent->len, 0)) == NULL) { pr->is_valid = -1; return NULL; } + rnode = cleri__parse_walk( pr, node, cl_obj->via.optional->cl_obj, rule, CLERI__EXP_MODE_OPTIONAL); + if (rnode != NULL) { parent->len += node->len; - if (cleri__children_add(parent->children, node)) + if (cleri__children_add(&parent->children, node)) { /* error occurred, reverse changes set mg_node to NULL */ pr->is_valid = -1; diff --git a/src/parse.c b/src/parse.c index a3930e7..bfc21d8 100644 --- a/src/parse.c +++ b/src/parse.c @@ -12,13 +12,15 @@ * Return a parse result. In case of a memory allocation error the return value * will be NULL. */ -cleri_parse_t * cleri_parse(cleri_grammar_t * grammar, const char * str) +cleri_parse_t * cleri_parse2( + cleri_grammar_t * grammar, + const char * str, + int flags) { cleri_node_t * nd; cleri_parse_t * pr; const char * end; const char * test; - bool at_end = true; /* prepare parsing */ pr = cleri__malloc(cleri_parse_t); @@ -27,6 +29,7 @@ cleri_parse_t * cleri_parse(cleri_grammar_t * grammar, const char * str) return NULL; } + pr->flags = flags; pr->str = str; pr->tree = NULL; pr->kwcache = NULL; @@ -34,8 +37,8 @@ cleri_parse_t * cleri_parse(cleri_grammar_t * grammar, const char * str) pr->is_valid = 0; if ( (pr->tree = cleri__node_new(NULL, str, 0)) == NULL || - (pr->kwcache = cleri__kwcache_new()) == NULL || - (pr->expecting = cleri__expecting_new(str)) == NULL) + (pr->kwcache = cleri__kwcache_new(str)) == NULL || + (pr->expecting = cleri__expecting_new(str, flags)) == NULL) { cleri_parse_free(pr); return NULL; @@ -65,38 +68,44 @@ cleri_parse_t * cleri_parse(cleri_grammar_t * grammar, const char * str) end = pr->tree->str + pr->tree->len; /* check if we are at the end of the string */ - for (test = end; *test; test++) + if (pr->is_valid) for (test = end; *test; test++) { if (!isspace(*test)) { - at_end = false; pr->is_valid = false; + if (pr->expecting->required) + { + if (cleri__expecting_set_mode( + pr->expecting, + end, + CLERI__EXP_MODE_REQUIRED) == -1 || + cleri__expecting_update( + pr->expecting, + CLERI_END_OF_STATEMENT, + end) == -1) + { + cleri_parse_free(pr); + return NULL; + } + cleri__expecting_combine(pr->expecting); + } + else if (cleri__expecting_update( + pr->expecting, + CLERI_END_OF_STATEMENT, + end)) + { + cleri_parse_free(pr); + return NULL; + } break; } } - pr->pos = (pr->is_valid) ? - pr->tree->len : (size_t) (pr->expecting->str - pr->str); - - if (!at_end && pr->expecting->required->cl_obj == NULL) - { - pr->pos = pr->tree->len; - if (cleri__expecting_set_mode( - pr->expecting, - end, - CLERI__EXP_MODE_REQUIRED) == -1 || - cleri__expecting_update( - pr->expecting, - CLERI_END_OF_STATEMENT, - end) == -1) - { - cleri_parse_free(pr); - return NULL; - } - } - - cleri__expecting_combine(pr->expecting); + pr->pos = pr->is_valid + ? pr->tree->len + : (size_t) (pr->expecting->str - pr->str); + cleri__olist_unique(pr->expecting->required); pr->expect = pr->expecting->required; return pr; @@ -124,6 +133,56 @@ void cleri_parse_expect_start(cleri_parse_t * pr) pr->expect = pr->expecting->required; } +static void parse__line_pos(cleri_parse_t * pr, size_t * line, size_t * pos) +{ + size_t n = pr->pos; + const char * pt = pr->str; + *pos = 0; + *line = 0; + while (n--) + { + if (*pt == '\n') + { + if (!n) + break; + + ++pt; + if (*pt == '\r') + { + if (!--n) + break; + ++pt; + } + + ++(*line); + *pos = 0; + continue; + } + if (*pt == '\r') + { + if (!n) + break; + + ++pt; + if (*(++pt) == '\n' ) + { + if (!--n) + break; + + ++pt; + ++(*line); + *pos = 0; + } + + ++(*line); + *pos = 0; + continue; + } + ++(*pos); + ++pt; + } +} + /* * Print parse result to a string. The return value is equal to the snprintf * function. Argument `translate_cb` maybe NULL or a function which may return @@ -138,7 +197,7 @@ int cleri_parse_strn( cleri_translate_t * translate) { int rc, count = 0; - size_t i, m; + size_t i, m, line, pos; cleri_t * o; const char * expect; const char * template; @@ -155,13 +214,51 @@ int cleri_parse_strn( /* make sure expecting is at start */ cleri_parse_expect_start(pr); - rc = snprintf(s, n, "error at position %zd", pr->pos); + parse__line_pos(pr, &line, &pos); + + rc = snprintf(s, n, "error at line %zu, position %zu", line, pos); if (rc < 0) { return rc; } i = rc; + expect = pr->str + pr->pos; + if (isgraph(*expect)) + { + ssize_t nc = cleri__kwcache_match(pr, expect); + const char * pt = expect; + const int max_chars = 20; + + if (nc < 1) + { + while (isdigit(*pt)) + ++pt; + nc = pt - expect; + } + + m = (i < n) ? n-i : 0; + + if (nc > 1) + { + rc = nc > max_chars + ? snprintf(s+i, m, ", unexpected `%.*s...`", max_chars, expect) + : snprintf(s+i, m, ", unexpected `%.*s`", (int) nc, expect); + } + else + { + rc = snprintf(s+i, m, ", unexpected character `%c`", *expect); + } + + if (rc < 0) + { + return rc; + } + + i += rc; + } + + while (pr->expect) { o = pr->expect->cl_obj; @@ -191,17 +288,19 @@ int cleri_parse_strn( } /* make sure len is not greater than the maximum size */ - m = (i < n) ? n - i : 0; + m = (i < n) ? n-i : 0; /* we use count = 0 to print the first one, then for the others * a comma prefix and the last with -or- + * + * TODO: could be improved since the last `or` might never be added */ template = !count++ ? ", expecting: %s" : pr->expect->next ? ", %s" : " or %s"; - rc = snprintf(s + i, m, template, expect); + rc = snprintf(s+i, m, template, expect); if (rc < 0) { return rc; @@ -225,11 +324,10 @@ cleri_node_t * cleri__parse_walk( cleri_rule_store_t * rule, int mode) { + const char * str = parent->str + parent->len; + /* set parent len to next none white space char */ - while (isspace(*(parent->str + parent->len))) - { - parent->len++; - } + for (; isspace(*str); ++str, ++parent->len); /* set expecting mode */ if (cleri__expecting_set_mode(pr->expecting, parent->str, mode) == -1) diff --git a/src/prio.c b/src/prio.c index 0497e35..c4027cc 100644 --- a/src/prio.c +++ b/src/prio.c @@ -131,7 +131,7 @@ static cleri_node_t * prio__parse( if (tested->node != NULL) { parent->len += tested->node->len; - if (cleri__children_add(parent->children, tested->node)) + if (cleri__children_add(&parent->children, tested->node)) { /* error occurred, reverse changes set mg_node to NULL */ pr->is_valid = -1; diff --git a/src/regex.c b/src/regex.c index a56b501..e8775cd 100644 --- a/src/regex.c +++ b/src/regex.c @@ -117,7 +117,7 @@ static cleri_node_t * regex__parse( pcre_exec_ret = pcre2_match( cl_obj->via.regex->regex, (PCRE2_SPTR8) str, - strlen(str), + PCRE2_ZERO_TERMINATED, 0, // start looking at this point 0, // OPTIONS cl_obj->via.regex->match_data, @@ -139,7 +139,7 @@ static cleri_node_t * regex__parse( if ((node = cleri__node_new(cl_obj, str, (size_t) ovector[1])) != NULL) { parent->len += node->len; - if (cleri__children_add(parent->children, node)) + if (cleri__children_add(&parent->children, node)) { /* error occurred, reverse changes set node to NULL */ pr->is_valid = -1; diff --git a/src/repeat.c b/src/repeat.c index adee88b..77f5f6b 100644 --- a/src/repeat.c +++ b/src/repeat.c @@ -107,7 +107,7 @@ static cleri_node_t * repeat__parse( return NULL; } parent->len += node->len; - if (cleri__children_add(parent->children, node)) + if (cleri__children_add(&parent->children, node)) { /* error occurred, reverse changes set mg_node to NULL */ pr->is_valid = -1; diff --git a/src/rule.c b/src/rule.c index 73a26a6..7e8b8d6 100644 --- a/src/rule.c +++ b/src/rule.c @@ -115,6 +115,41 @@ static cleri_node_t * rule__parse( cleri_node_t * rnode; cleri_rule_store_t nrule; + if (pr->flags & CLERI_FLAG_EXCLUDE_RULE_THIS) + { + nrule.depth = 0; + nrule.tested = cleri__malloc(cleri_rule_tested_t); + + if (nrule.tested == NULL) + { + pr->is_valid = -1; + return NULL; + } + + nrule.tested->str = NULL; + nrule.tested->node = NULL; + nrule.tested->next = NULL; + nrule.root_obj = cl_obj->via.rule->cl_obj; + + node = cleri__parse_walk( + pr, + parent, + nrule.root_obj, + &nrule, + CLERI__EXP_MODE_REQUIRED); + + + if (node != NULL) + { + node = parent; + } + + /* cleanup rule */ + rule__tested_free(nrule.tested); + + return node; + } + if ((node = cleri__node_new(cl_obj, parent->str + parent->len, 0)) == NULL) { pr->is_valid = -1; @@ -152,7 +187,7 @@ static cleri_node_t * rule__parse( else { parent->len += node->len; - if (cleri__children_add(parent->children, node)) + if (cleri__children_add(&parent->children, node)) { /* error occurred, reverse changes set mg_node to NULL */ pr->is_valid = -1; diff --git a/src/sequence.c b/src/sequence.c index 887150c..2dd005e 100644 --- a/src/sequence.c +++ b/src/sequence.c @@ -110,7 +110,7 @@ static cleri_node_t * sequence__parse( } parent->len += node->len; - if (cleri__children_add(parent->children, node)) + if (cleri__children_add(&parent->children, node)) { /* error occurred, reverse changes set mg_node to NULL */ pr->is_valid = -1; diff --git a/src/this.c b/src/this.c index 0852003..6c36d38 100644 --- a/src/this.c +++ b/src/this.c @@ -43,6 +43,17 @@ static cleri_node_t * cleri_parse_this( switch (cleri__rule_init(&tested, rule->tested, str)) { case CLERI_RULE_TRUE: + if (pr->flags & CLERI_FLAG_EXCLUDE_RULE_THIS) + { + tested->node = cleri__parse_walk( + pr, + parent, + rule->root_obj, + rule, + CLERI__EXP_MODE_REQUIRED); + + return tested->node == NULL ? NULL : parent; + } if ((node = cleri__node_new(cl_obj, str, 0)) == NULL) { pr->is_valid = -1; @@ -79,7 +90,7 @@ static cleri_node_t * cleri_parse_this( } parent->len += tested->node->len; - if (cleri__children_add(parent->children, node)) + if (cleri__children_add(&parent->children, node)) { /* error occurred, reverse changes set mg_node to NULL */ pr->is_valid = -1; diff --git a/src/token.c b/src/token.c index 8953e53..099fb1c 100644 --- a/src/token.c +++ b/src/token.c @@ -76,7 +76,7 @@ static cleri_node_t * token__parse( cl_obj->via.token->len)) != NULL) { parent->len += node->len; - if (cleri__children_add(parent->children, node)) + if (cleri__children_add(&parent->children, node)) { /* error occurred, reverse changes set mg_node to NULL */ pr->is_valid = -1; diff --git a/src/tokens.c b/src/tokens.c index 829843d..322e9f3 100644 --- a/src/tokens.c +++ b/src/tokens.c @@ -144,7 +144,7 @@ static cleri_node_t * tokens__parse( if ((node = cleri__node_new(cl_obj, str, tlist->len)) != NULL) { parent->len += node->len; - if (cleri__children_add(parent->children, node)) + if (cleri__children_add(&parent->children, node)) { /* error occurred, reverse changes set mg_node to NULL */ pr->is_valid = -1; diff --git a/test/helpers.h b/test/helpers.h index 20ed937..f59a4b8 100644 --- a/test/helpers.h +++ b/test/helpers.h @@ -29,7 +29,7 @@ static char * parse_str(cleri_parse_t * pr, cleri_translate_t * translate) #define _assert_is_valid(__grammar, __str) \ { \ - cleri_parse_t * __pr = cleri_parse(__grammar, __str); \ + cleri_parse_t * __pr = cleri_parse2(__grammar, __str, 0); \ _assert (__pr); \ _assert (__pr->is_valid); \ cleri_parse_free(__pr); \ @@ -45,7 +45,18 @@ static char * parse_str(cleri_parse_t * pr, cleri_translate_t * translate) #define _assert_parse_str(__grammar, __str, __expect, __translate) \ { \ - cleri_parse_t * __pr = cleri_parse(__grammar, __str); \ + cleri_parse_t * __pr = cleri_parse2(__grammar, __str, 0); \ + char * __s = parse_str(__pr, __translate); \ + _assert (__s); \ + if (strcmp(__s, __expect) != 0) printf("\n\ngot: `%s`\n", __s); \ + _assert (strcmp(__s, __expect) == 0); \ + free(__s); \ + if (__pr) cleri_parse_free(__pr); \ +} + +#define _assert_parse_str2(__grammar, __str, __expect, __translate) \ +{ \ + cleri_parse_t * __pr = cleri_parse2(__grammar, __str, 1); \ char * __s = parse_str(__pr, __translate); \ _assert (__s); \ if (strcmp(__s, __expect) != 0) printf("\n\ngot: `%s`\n", __s); \ diff --git a/test/test_choice/test_choice.c b/test/test_choice/test_choice.c index 6ff18fd..d2ef7eb 100644 --- a/test/test_choice/test_choice.c +++ b/test/test_choice/test_choice.c @@ -43,6 +43,38 @@ static int test_choice_first_match(void) _assert_is_not_valid (grammar, "hi iris"); _assert_is_not_valid (grammar, "hi sasha"); + + cleri_grammar_free(grammar); + + return test_end(); +} + +static int test_choice_expecting(void) +{ + test_start("choice (expecting)"); + + cleri_grammar_t * grammar; + cleri_t * k_hi, * k_iris, * k_sasha, * seq, * choice; + + k_hi = cleri_keyword(0, "hi", false); + k_iris = cleri_keyword(0, "iris", false); + k_sasha = cleri_keyword(0, "sasha", false); + choice = cleri_choice(0, false, 2, k_iris, k_sasha); + seq = cleri_sequence(0, 2, k_hi, choice); + grammar = cleri_grammar(seq, NULL); + + _assert (choice->via.choice->most_greedy == false); + _assert_is_valid (grammar, "hi iris"); + _assert_is_valid (grammar, "hi sasha"); + _assert_is_not_valid (grammar, "hi cleri"); + + _assert_parse_str ( + grammar, + "hi cleri", + "error at line 0, position 3, " + "unexpected `cleri`, expecting: iris or sasha", + NULL); + cleri_grammar_free(grammar); return test_end(); @@ -53,6 +85,7 @@ int main() return ( test_choice_most_greedy() || test_choice_first_match() || + test_choice_expecting() || 0 ); } diff --git a/test/test_dup/test_dup.c b/test/test_dup/test_dup.c index 3c2f60f..7e4acde 100644 --- a/test/test_dup/test_dup.c +++ b/test/test_dup/test_dup.c @@ -32,14 +32,23 @@ static int test_dup(void) _assert_parse_str ( grammar, "", - "error at position 0, expecting: hi", + "error at line 0, position 0, expecting: hi", &translate); _assert_parse_str ( grammar, "hi", - "error at position 2, expecting: hi(dup)", + "error at line 0, position 2, expecting: hi(dup)", + &translate); + _assert_parse_str2 ( + grammar, + "", + "error at line 0, position 0", + &translate); + _assert_parse_str2 ( + grammar, + "hi", + "error at line 0, position 2", &translate); - cleri_grammar_free(grammar); return test_end(); diff --git a/test/test_keyword/sources b/test/test_keyword/sources index 6c4e51f..830387f 100644 --- a/test/test_keyword/sources +++ b/test/test_keyword/sources @@ -7,3 +7,5 @@ ../src/olist.c ../src/parse.c ../src/keyword.c +../src/token.c +../src/choice.c diff --git a/test/test_keyword/test_keyword.c b/test/test_keyword/test_keyword.c index bda9da4..fb8a309 100644 --- a/test/test_keyword/test_keyword.c +++ b/test/test_keyword/test_keyword.c @@ -23,13 +23,23 @@ static int test_keyword(void) _assert_parse_str ( grammar, "hello", - "error at position 0, expecting: hi", + "error at line 0, position 0, unexpected `hello`, expecting: hi", NULL); _assert_parse_str ( grammar, "hi", "parsed successfully", NULL); + _assert_parse_str2 ( + grammar, + "hello", + "error at line 0, position 0, unexpected `hello`", + NULL); + _assert_parse_str2 ( + grammar, + "hi", + "parsed successfully", + NULL); cleri_grammar_free(grammar); return test_end(); @@ -52,11 +62,47 @@ static int test_keyword_ign_case(void) _assert_is_valid (grammar, "hi"); _assert_is_valid (grammar, "Hi"); _assert_is_not_valid (grammar, "hello"); + _assert_is_not_valid (grammar, + "hihihihihihihihihihihihihihihihi" + "hihihihihihihihihihihihihihihihi" + "hihihihihihihihihihihihihihihihi" + "hihihihihihihihihihihihihihihihi" + "hihihihihihihihihihihihihihihihi" + "hihihihihihihihihihihihihihihihi" + "hihihihihihihihihihihihihihihihi" + "hihihihihihihihihihihihihihihihi"); _assert_parse_str ( grammar, "Hi Iris", - "error at position 2, expecting: end_of_statement", + "error at line 0, position 2, expecting: end_of_statement", NULL); + _assert_parse_str2 ( + grammar, + "Hi Iris", + "error at line 0, position 2", + NULL); + cleri_grammar_free(grammar); + + return test_end(); +} + +static int test_keyword_alt_regkw(void) +{ + test_start("keyword (alt_regkw)"); + + cleri_grammar_t * grammar; + cleri_t * k_hi, * t_hi; + + k_hi = cleri_keyword(0, "hi", false); + t_hi = cleri_token(0, "HI"); + + grammar = cleri_grammar(cleri_choice(0, 1, 2, k_hi, t_hi), "^[a-z]+"); + _assert (grammar); + + _assert_is_valid (grammar, "hi"); + _assert_is_valid (grammar, "HI"); + _assert_is_not_valid (grammar, "Hi"); + cleri_grammar_free(grammar); return test_end(); @@ -67,6 +113,7 @@ int main() return ( test_keyword() || test_keyword_ign_case() || + test_keyword_alt_regkw() || 0 ); } diff --git a/test/test_list/sources b/test/test_list/sources index e40d131..13cd32f 100644 --- a/test/test_list/sources +++ b/test/test_list/sources @@ -9,3 +9,4 @@ ../src/keyword.c ../src/token.c ../src/list.c +../src/choice.c \ No newline at end of file diff --git a/test/test_list/test_list.c b/test/test_list/test_list.c index fa9cca1..2f0f100 100644 --- a/test/test_list/test_list.c +++ b/test/test_list/test_list.c @@ -25,9 +25,25 @@ static int test_list(void) _assert_parse_str ( grammar, "hi.", - "error at position 2, expecting: , or end_of_statement", + "error at line 0, position 2, " + "unexpected character `.`, expecting: , or end_of_statement", + NULL); + _assert_parse_str2 ( + grammar, + "hi.", + "error at line 0, position 2, unexpected character `.`", NULL); + /* check if list children is really NULL */ + { + cleri_parse_t * pr = cleri_parse(grammar, ""); + _assert (pr); + _assert (pr->is_valid); + _assert (pr->tree->children->node->cl_obj->tp == CLERI_TP_LIST); + _assert (pr->tree->children->node->children == NULL); + cleri_parse_free(pr); + } + cleri_grammar_free(grammar); return test_end(); @@ -59,29 +75,90 @@ static int test_list_all_options(void) _assert_parse_str ( grammar, "hi-hi-hi-hi-hi", - "error at position 9, expecting: end_of_statement", + "error at line 0, position 9, " + "unexpected `hi`, expecting: end_of_statement", NULL); _assert_parse_str ( grammar, "hi.", - "error at position 2, expecting: - or end_of_statement", + "error at line 0, position 2" + ", unexpected character `.`, expecting: - or end_of_statement", NULL); _assert_parse_str ( grammar, "", - "error at position 0, expecting: hi", + "error at line 0, position 0, expecting: hi", + NULL); + _assert_parse_str2 ( + grammar, + "hi-hi-hi-hi-hi", + "error at line 0, position 9, unexpected `hi`", + NULL); + _assert_parse_str2 ( + grammar, + "hi.", + "error at line 0, position 2, unexpected character `.`", + NULL); + _assert_parse_str2 ( + grammar, + "", + "error at line 0, position 0", NULL); + cleri_grammar_free(grammar); + + return test_end(); +} + +static int test_list_vs_single(void) +{ + test_start("list (vs_single)"); + + cleri_grammar_t * grammar; + cleri_t * k_hi, * delimiter, * list, * choice; + + k_hi = cleri_keyword(0, "hi", false); + delimiter = cleri_token(0, ","); + list = cleri_list(0, k_hi, delimiter, 1, 0, false); + choice = cleri_choice(0, true, 2, k_hi, list); + + grammar = cleri_grammar(choice, NULL); + // assert statements + _assert_is_valid (grammar, "hi, hi, hi"); + _assert_parse_str ( + grammar, + "hi, hello", + "error at line 0, position 4, unexpected `hello`, expecting: hi", + NULL); + _assert_parse_str ( + grammar, + "hello", + "error at line 0, position 0, unexpected `hello`, expecting: hi", + NULL); + _assert_parse_str2 ( + grammar, + "hi, hello", + "error at line 0, position 4, unexpected `hello`", + NULL); + _assert_parse_str2 ( + grammar, + "hello", + "error at line 0, position 0, unexpected `hello`", + NULL); cleri_grammar_free(grammar); return test_end(); } + + + int main() { return ( test_list() || test_list_all_options() || + test_list_vs_single() || 0 ); } diff --git a/test/test_optional/test_optional.c b/test/test_optional/test_optional.c index 6605d88..7356c96 100644 --- a/test/test_optional/test_optional.c +++ b/test/test_optional/test_optional.c @@ -21,15 +21,26 @@ static int test_optional(void) _assert_parse_str ( grammar, "hello", - "error at position 0, expecting: hi or end_of_statement", + "error at line 0, position 0, " + "unexpected `hello`, expecting: hi or end_of_statement", NULL); _assert_parse_str ( grammar, "hi hi", - "error at position 2, expecting: end_of_statement", + "error at line 0, position 2, expecting: end_of_statement", + NULL); + _assert_parse_str2 ( + grammar, + "hello", + "error at line 0, position 0, unexpected `hello`", NULL); + _assert_parse_str2 ( + grammar, + "hi hi", + "error at line 0, position 2", + NULL); cleri_grammar_free(grammar); return test_end(); diff --git a/test/test_prio/test_prio.c b/test/test_prio/test_prio.c index 2445b91..6b01eb4 100644 --- a/test/test_prio/test_prio.c +++ b/test/test_prio/test_prio.c @@ -40,8 +40,26 @@ static int test_prio(void) { cleri_parse_t * pr = cleri_parse( grammar, + "(((((((((((((((((((((((((((((((((((((((((((((((((((" + "(((((((((((((((((((((((((((((((((((((((((((((((((((" + "(((((((((((((((((((((((((((((((((((((((((((((((((((" + "(((((((((((((((((((((((((((((((((((((((((((((((((((" + "(((((((((((((((((((((((((((((((((((((((((((((((((((" + "(((((((((((((((((((((((((((((((((((((((((((((((((((" + "(((((((((((((((((((((((((((((((((((((((((((((((((((" + "(((((((((((((((((((((((((((((((((((((((((((((((((((" + "(((((((((((((((((((((((((((((((((((((((((((((((((((" "(((((((((((((((((((((((((((((((((((((((((((((((((((hi" ")))))))))))))))))))))))))))))))))))))))))))))))))))" + ")))))))))))))))))))))))))))))))))))))))))))))))))))" + ")))))))))))))))))))))))))))))))))))))))))))))))))))" + ")))))))))))))))))))))))))))))))))))))))))))))))))))" + ")))))))))))))))))))))))))))))))))))))))))))))))))))" + ")))))))))))))))))))))))))))))))))))))))))))))))))))" + ")))))))))))))))))))))))))))))))))))))))))))))))))))" + ")))))))))))))))))))))))))))))))))))))))))))))))))))" + ")))))))))))))))))))))))))))))))))))))))))))))))))))" + ")))))))))))))))))))))))))))))))))))))))))))))))))))" ); _assert (pr == NULL); /* max recursion depth */ @@ -49,12 +67,54 @@ static int test_prio(void) _assert_parse_str ( grammar, + "(((((((((((((((((((((((((((((((((((((((((((((((((((" + "(((((((((((((((((((((((((((((((((((((((((((((((((((" + "(((((((((((((((((((((((((((((((((((((((((((((((((((" + "(((((((((((((((((((((((((((((((((((((((((((((((((((" + "(((((((((((((((((((((((((((((((((((((((((((((((((((" + "(((((((((((((((((((((((((((((((((((((((((((((((((((" + "(((((((((((((((((((((((((((((((((((((((((((((((((((" + "(((((((((((((((((((((((((((((((((((((((((((((((((((" + "(((((((((((((((((((((((((((((((((((((((((((((((((((" "(((((((((((((((((((((((((((((((((((((((((((((((((((hi" + ")))))))))))))))))))))))))))))))))))))))))))))))))))" + ")))))))))))))))))))))))))))))))))))))))))))))))))))" + ")))))))))))))))))))))))))))))))))))))))))))))))))))" + ")))))))))))))))))))))))))))))))))))))))))))))))))))" + ")))))))))))))))))))))))))))))))))))))))))))))))))))" + ")))))))))))))))))))))))))))))))))))))))))))))))))))" + ")))))))))))))))))))))))))))))))))))))))))))))))))))" + ")))))))))))))))))))))))))))))))))))))))))))))))))))" + ")))))))))))))))))))))))))))))))))))))))))))))))))))" ")))))))))))))))))))))))))))))))))))))))))))))))))))", "no parse result, a possible reason might be that the maximum " - "recursion depth of 50 has been reached", + "recursion depth of 500 has been reached", + NULL); + _assert_parse_str2 ( + grammar, + "(((((((((((((((((((((((((((((((((((((((((((((((((((" + "(((((((((((((((((((((((((((((((((((((((((((((((((((" + "(((((((((((((((((((((((((((((((((((((((((((((((((((" + "(((((((((((((((((((((((((((((((((((((((((((((((((((" + "(((((((((((((((((((((((((((((((((((((((((((((((((((" + "(((((((((((((((((((((((((((((((((((((((((((((((((((" + "(((((((((((((((((((((((((((((((((((((((((((((((((((" + "(((((((((((((((((((((((((((((((((((((((((((((((((((" + "(((((((((((((((((((((((((((((((((((((((((((((((((((" + "(((((((((((((((((((((((((((((((((((((((((((((((((((hi" + ")))))))))))))))))))))))))))))))))))))))))))))))))))" + ")))))))))))))))))))))))))))))))))))))))))))))))))))" + ")))))))))))))))))))))))))))))))))))))))))))))))))))" + ")))))))))))))))))))))))))))))))))))))))))))))))))))" + ")))))))))))))))))))))))))))))))))))))))))))))))))))" + ")))))))))))))))))))))))))))))))))))))))))))))))))))" + ")))))))))))))))))))))))))))))))))))))))))))))))))))" + ")))))))))))))))))))))))))))))))))))))))))))))))))))" + ")))))))))))))))))))))))))))))))))))))))))))))))))))" + ")))))))))))))))))))))))))))))))))))))))))))))))))))", + "no parse result, a possible reason might be that the maximum " + "recursion depth of 500 has been reached", NULL); - cleri_grammar_free(grammar); return test_end(); diff --git a/test/test_ref/test_ref.c b/test/test_ref/test_ref.c index 41a0b3e..2ebe49c 100644 --- a/test/test_ref/test_ref.c +++ b/test/test_ref/test_ref.c @@ -21,9 +21,13 @@ static int test_ref(void) _assert_parse_str ( grammar, "ha", - "error at position 0, expecting: hi", + "error at line 0, position 0, unexpected `ha`, expecting: hi", + NULL); + _assert_parse_str2 ( + grammar, + "ha", + "error at line 0, position 0, unexpected `ha`", NULL); - cleri_grammar_free(grammar); return test_end(); diff --git a/test/test_regex/test_regex.c b/test/test_regex/test_regex.c index 9e5867f..d264e3a 100644 --- a/test/test_regex/test_regex.c +++ b/test/test_regex/test_regex.c @@ -35,9 +35,15 @@ static int test_regex(void) _assert_parse_str ( grammar, "\"double quoted\"", - "error at position 0, expecting: single_quoted_string", + "error at line 0, position 0, " + "unexpected character `\"`, expecting: single_quoted_string", + translate); + _assert_parse_str2 ( + grammar, + "\"double quoted\"", + "error at line 0, position 0, " + "unexpected character `\"`", translate); - cleri_grammar_free(grammar); return test_end(); diff --git a/test/test_repeat/test_repeat.c b/test/test_repeat/test_repeat.c index ba78d4e..323110c 100644 --- a/test/test_repeat/test_repeat.c +++ b/test/test_repeat/test_repeat.c @@ -30,12 +30,26 @@ static int test_repeat(void) _assert_parse_str ( grammar, "hi.", - "error at position 2, expecting: hi or end_of_statement", + "error at line 0, position 2, " + "unexpected character `.`, expecting: hi or end_of_statement", NULL); _assert_parse_str ( grammar, "hi.", - "error at position 2", + "error at line 0, position 2, " + "unexpected character `.`", + &translate); + _assert_parse_str2 ( + grammar, + "hi.", + "error at line 0, position 2, " + "unexpected character `.`", + NULL); + _assert_parse_str2 ( + grammar, + "hi.", + "error at line 0, position 2, " + "unexpected character `.`", &translate); cleri_grammar_free(grammar); @@ -63,19 +77,35 @@ static int test_repeat_all_options(void) _assert_parse_str ( grammar, "hi hi hi hi hi", - "error at position 8, expecting: end_of_statement", + "error at line 0, position 8, expecting: end_of_statement", NULL); _assert_parse_str ( grammar, "hi.", - "error at position 2, expecting: hi or end_of_statement", + "error at line 0, position 2, " + "unexpected character `.`, expecting: hi or end_of_statement", NULL); _assert_parse_str ( grammar, "", - "error at position 0, expecting: hi", + "error at line 0, position 0, expecting: hi", + NULL); + _assert_parse_str2 ( + grammar, + "hi hi hi hi hi", + "error at line 0, position 8", + NULL); + _assert_parse_str2 ( + grammar, + "hi.", + "error at line 0, position 2, " + "unexpected character `.`", + NULL); + _assert_parse_str2 ( + grammar, + "", + "error at line 0, position 0", NULL); - cleri_grammar_free(grammar); return test_end(); diff --git a/test/test_sequence/test_sequence.c b/test/test_sequence/test_sequence.c index 60efe67..075e89a 100644 --- a/test/test_sequence/test_sequence.c +++ b/test/test_sequence/test_sequence.c @@ -19,9 +19,15 @@ static int test_sequence(void) _assert_parse_str ( grammar, "hi sasha", - "error at position 3, expecting: iris", + "error at line 0, position 3, " + "unexpected `sasha`, expecting: iris", + NULL); + _assert_parse_str2 ( + grammar, + "hi sasha", + "error at line 0, position 3, " + "unexpected `sasha`", NULL); - cleri_grammar_free(grammar); return test_end(); diff --git a/test/test_token/test_token.c b/test/test_token/test_token.c index f3e979a..4df06cc 100644 --- a/test/test_token/test_token.c +++ b/test/test_token/test_token.c @@ -19,7 +19,12 @@ static int test_token(void) _assert_parse_str ( grammar, "", - "error at position 0, expecting: .", + "error at line 0, position 0, expecting: .", + NULL); + _assert_parse_str2 ( + grammar, + "", + "error at line 0, position 0", NULL); cleri_grammar_free(grammar); @@ -44,7 +49,12 @@ static int test_token_multi_char(void) _assert_parse_str ( grammar, "", - "error at position 0, expecting: !=", + "error at line 0, position 0, expecting: !=", + NULL); + _assert_parse_str2 ( + grammar, + "", + "error at line 0, position 0", NULL); cleri_grammar_free(grammar); diff --git a/test/test_tokens/test_tokens.c b/test/test_tokens/test_tokens.c index c4c3ade..cae7ced 100644 --- a/test/test_tokens/test_tokens.c +++ b/test/test_tokens/test_tokens.c @@ -24,9 +24,13 @@ static int test_tokens(void) _assert_parse_str ( grammar, "", - "error at position 0, expecting: == != >= <= > <", + "error at line 0, position 0, expecting: == != >= <= > <", + NULL); + _assert_parse_str2 ( + grammar, + "", + "error at line 0, position 0", NULL); - cleri_grammar_free(grammar); return test_end(); diff --git a/test/test_version/sources b/test/test_version/sources new file mode 100644 index 0000000..17b9d36 --- /dev/null +++ b/test/test_version/sources @@ -0,0 +1 @@ +../src/version.c \ No newline at end of file diff --git a/test/test_version/test_version.c b/test/test_version/test_version.c new file mode 100644 index 0000000..f40254c --- /dev/null +++ b/test/test_version/test_version.c @@ -0,0 +1,19 @@ +#include "../test.h" +#include + +static int test_version(void) +{ + test_start("version"); + + _assert ( strlen(cleri_version()) > 5 ); + + return test_end(); +} + +int main() +{ + return ( + test_version() || + 0 + ); +}